Tutorial

Ubuntu 20.04にRedisをインストールしてセキュリティを保護する方法

UbuntuNoSQLRedisDatabasesUbuntu 20.04

このチュートリアルの以前のバージョンは、Justin Ellingwoodによって作成されました。 

はじめに

Radis は、柔軟性、パフォーマンス、幅広い言語サポートで知られるインメモリ型の Key-Value ストアです。このチュートリアルでは、Ubuntu 20.04サーバーにRedisをインストールし、設定、保護する方法を説明します。

前提条件

このガイドを完了するには、sudo権限が付与されたroot以外のユーザー、ufwで設定したファイアウォールを備えたUbuntu 20.04サーバーへのアクセスが必要です。Ubuntu 20.04初期サーバーセットアップガイドに従ってこれをセットアップします。

ステップ1 — Redisのインストールと設定

APTパッケージマネージャーを使用して、公式UbuntuリポジトリからRedisをインストールします。執筆時点では、デフォルトリポジトリで利用可能なバージョンは5.0.7です。

まず、ローカルaptパッケージキャッシュを更新します。

  • sudo apt update

次に、以下のように入力しRedisをインストールします。

  • sudo apt install redis-server

これにより、Redisとその依存関係がダウンロード、インストールされます。続いて、インストール中に自動生成されたRedis設定ファイルに、1点重要な変更を加えます。

任意のテキストエディターでこのファイルを開きます。

  • sudo nano /etc/redis/redis.conf

ファイル内で、supervisedディレクティブを検索します。このディレクティブを使用すると、Redisをサービスとして管理するinitシステムを宣言でき、その操作をより詳細に制御できます。supervisedディレクティブは、デフォルトでnoに設定されています。systemdinitシステムを使用するUbuntuを実行しているので、systemdに変更します。

/etc/redis/redis.conf
. . .

# If you run Redis from upstart or systemd, Redis can interact with your
# supervision tree. Options:
#   supervised no      - no supervision interaction
#   supervised upstart - signal upstart by putting Redis into SIGSTOP mode
#   supervised systemd - signal systemd by writing READY=1 to $NOTIFY_SOCKET
#   supervised auto    - detect upstart or systemd method based on
#                        UPSTART_JOB or NOTIFY_SOCKET environment variables
# Note: these supervision methods only signal "process is ready."
#       They do not enable continuous liveness pings back to your supervisor.
supervised systemd

. . .

現時点でRedis設定ファイルに必要な変更はこれだけなので、終了したら保存して閉じます。nanoを使用した場合は、CTRL + XYENTERキーを押します。

次に、Redisサービスを再起動して、設定ファイルに加えた変更を反映します。

  • sudo systemctl restart redis.service

これで、Radisのインストールと設定が完了しマシン上で稼働します。ただし、使用を開始する前に、Redisが正しく機能しているか確認しましょう。

ステップ2 — Redisのテスト

新たにインストールしたあらゆるソフトウェアと同様に、Redisを設定変更する前に、期待どおりに機能しているか確認することをお勧めします。このステップではRedisが正常に動作しているか確認する方法をいくつか見ていきます。

まず、Redisサービスが稼働しているか確認します。

  • sudo systemctl status redis

エラーなく稼働していれば、このコマンドは次のような出力を生成します。

Output
● redis-server.service - Advanced key-value store Loaded: loaded (/lib/systemd/system/redis-server.service; enabled; vendor preset: enabled) Active: active (running) since Thu 2020-04-30 23:26:54 UTC; 4s ago Docs: http://redis.io/documentation, man:redis-server(1) Process: 36552 ExecStart=/usr/bin/redis-server /etc/redis/redis.conf (code=exited, status=0/SUCCESS) Main PID: 36561 (redis-server) Tasks: 4 (limit: 2345) Memory: 1.8M CGroup: /system.slice/redis-server.service └─36561 /usr/bin/redis-server 127.0.0.1:6379 . . .

ここで、Redisが稼働し既に有効になっていることがわかります。つまり、サーバーが起動するたびにRedisも起動するように設定されています。

注:通常、これがRedisの多くの共通ユースケースで推奨される設定です。サーバーが起動するたびにRedisを手動で起動させたい場合は、次のコマンドで設定します。

  • sudo systemctl disable redis

Redisが正しく機能しているかテストするには、Redisのコマンドラインクライアントredis-cliを使用してサーバーに接続します。

  • redis-cli

次のプロンプトで、pingコマンドにより接続テストをします。

  • ping
Output
PONG

この出力から、サーバーと接続できているのが分かります。次に、以下を実行して鍵を設定できるか確認します。

  • set test "It's working!"
Output
OK

次のように入力して値を取得します。

  • get test

すべてが機能していれば、保存した値が取得できるはずです。

Output
"It's working!"

値を取得できることを確認したら、Redisプロンプトを終了してシェルに戻ります。

  • exit

最終テストとして、Redisが停止または再起動した後でもデータを保持できるか確認します。これを行うには、まずRedisインスタンスを再起動します。

  • sudo systemctl restart redis

次に、コマンドラインクライアントに再接続します。

  • redis-cli

そこでテスト値がまだ利用可能であることを確認します。

  • get test

鍵の値にまだアクセスできます。

Output
"It's working!"

終了したら、シェルを再度終了します。

  • exit

これで、Redisのインストールは完全に機能し、使用できる状態にあります。 ただし、デフォルトの構成設定の一部は安全でないため、悪意のある攻撃者に、サーバーとそのデータに攻撃してアクセスする機会を与えてしまいます。 このチュートリアルの後半の手順では、Redisの公式Webサイトで明記された、これらの脆弱性を軽減する方法について説明します。  これらの手順はオプションであり、従わない選択した場合でもRedisは引き続き機能しますが、システムのセキュリティを強化するためにも、これらを完了することを強くお勧めします。    

ステップ3 — localhostヘのバインド

デフォルトでは、Redisはlocalhostからのみアクセス可能です。ただし、これとは異なるチュートリアルに従ってRedisをインストール・設定した場合は、どこからでも接続できるように設定ファイルを更新した可能性があります。これは、localhostへのバインドほど安全ではありません。

これを修正するには、Redis設定ファイルを開いて編集します。

  • sudo nano /etc/redis/redis.conf

この行を見つけて、コメントが解除されていることを確認します(#があれば削除します)。

/etc/redis/redis.conf
bind 127.0.0.1 ::1

終了したらファイルを保存して閉じます(CTRL + XYENTERキーを押します)。

次に、サービスを再起動して、systemdが変更を読み取ることを確認します。

  • sudo systemctl restart redis

この変更が有効になったことを確認するには、次のようにnetstatコマンドを実行します。

  • sudo netstat -lnp | grep redis
Output
tcp 0 0 127.0.0.1:6379 0.0.0.0:* LISTEN 14222/redis-server tcp6 0 0 ::1:6379 :::* LISTEN 14222/redis-server

:netstatコマンドがデフォルトで使用できないことがあります。その場合は、次のコマンドで(ほかの便利なネットワークツールと併せて)インストールできます。

  • sudo apt install net-tools

この出力から、redis-serverプログラムがlocalhost127.0.0.1にバインドされ、たった今設定ファイルに加えた変更が反映されていることが分かります。その列に別のIPアドレス(例えば0.0.0.0)が表示された場合、コメントを解除した行が間違っていないか再度確認し、Redisサービスを再起動します。

Redisインストールがlocalhostのみlistenするようになったため、悪意のある攻撃者がサーバーにリクエストを送信したり、サーバーにアクセスしたりすることはさらに困難になります。ただし、Redisはまだ、ユーザーが自身の設定や保持するデータを変更する前に、自分自身の認証を要求する設定にはなっていません。これを改善するために、Redisでは、Redisクライアント(redis-cli)を介して変更を行う前に、ユーザーにパスワード認証を要求することができます。

ステップ4 — Redisパスワードの設定

Redisパスワードを設定すると、2つのビルトインセキュリティ機能の1つであるauthコマンドが有効になります。これは、クライアントがデータベースにアクセスするために認証要求するものです。   パスワードは、Redisの設定ファイル/etc/redis/redis/redis.confで直接設定されるため、任意のエディターでそのファイルをもう一度開きます。

  • sudo nano /etc/redis/redis.conf

SECURITYセクションまでスクロールして、次のコメント付きディレクティブを探します。

/etc/redis/redis.conf
. . .
# requirepass foobared
. . .

#を削除してコメント解除し、foobaredを安全なパスワードに変更します。

注:redis.confファイル内のrequirepassディレクティブの上に、コメントアウトされた次の警告があります。

/etc/redis/redis.conf
. . .
# Warning: since Redis is pretty fast an outside user can try up to
# 150k passwords per second against a good box. This means that you should
# use a very strong password otherwise it will be very easy to break.
#
. . .

したがって、パスワードとして非常に強力で非常に長い値を指定することが重要です。パスワードを自身で作成するよりも、次の例のとおり、opensslコマンドを使用すれば、ランダムなパソワードを生成できます。ここに示されるように、1つ目のコマンドの出力を2つ目のopensslコマンドにパイプすることで、1つ目のコマンドで生じた改行が削除されます。

  • openssl rand 60 | openssl base64 -A

出力は次のように見えるはずです。

Output
RBOJ9cCNoGCKhlEBwQLHri1g+atWgn4Xn4HwNUbtzoVxAYxkiYBi7aufl4MILv1nxBqR4L6NNzI0X6cE

そのコマンド出力をrequirepassの新しい値としてコピー&ペーストすると、次のように表示されます。

/etc/redis/redis.conf
requirepass RBOJ9cCNoGCKhlEBwQLHri1g+atWgn4Xn4HwNUbtzoVxAYxkiYBi7aufl4MILv1nxBqR4L6NNzI0X6cE

パスワードを設定したら、ファイルを保存して閉じ、Redisを再起動します。

  • sudo systemctl restart redis.service

パスワードが機能するかテストするには、Redisクライアントを開きます。

  • redis-cli

以下、Redisパスワードが機能するかどうかテストするために使用される一連のコマンドを示します。 最初のコマンドは、認証する前に鍵を値に設定しようとします。

  • set key1 10

認証しなかったため機能しません。そのため、Redisはエラーを返します。

Output
(error) NOAUTH Authentication required.

次のコマンドは、Redis設定ファイルで指定されたパスワードで認証します。

  • auth your_redis_password

Redisが承認します。

Output
OK

その後、前のコマンドを再度実行すると成功します。

  • set key1 10
Output
OK

get key1はRedisに新しいキーの値を問い合わせます。

  • get key1
Output
"10"

認証後にRedisクライアントでコマンドを実行できることを確認したら、redis-cliを終了します。 

  • quit

次に、Redisコマンドの名前変更について説明します。Redisコマンドは、誤って入力したり、悪意のある攻撃者によって入力されると、マシンに重大な損傷を与えるおそれがあります。

ステップ5 — 危険なコマンドの名前変更

Redisに組み込まれたセキュリティ機能には他に、危険とみなされる特定のコマンドの名前を変更したり完全に無効化する機能があります。

そのようなコマンドは、権限のないユーザーに実行されると、データの再設定、破棄、または消去に利用されかねません。コマンドの名前の変更・無効化は、認証パスワードと同じく/etc/redis/redis.confファイルのSECURITYセクションで設定します。

危険とみなされるコマンドには次のものがあります:FLUSHDBFLUSHALLKEYSPEXPIREDELCONFIGSHUTDOWNBGRRITEAOFBGSAVESAVESPOPSREMRENAMEDEBUGこの一覧がすべてを網羅しているわけではありませんが、一覧の各コマンドを名前変更・無効化することは、Redisサーバーのセキュリティを強化するための良い出発点となります。

コマンドを無効にするか名前を変更するかは、特定のニーズまたはサイトのニーズによって異なります。悪用されるおそれのあるコマンドで使用しないことがわかっているものは、無効化できます。 それ以外の場合は、名前を変更するのが得策でしょう。

Redisコマンドを名前変更・無効化するには、設定ファイルをもう一度開きます。

  • sudo nano /etc/redis/redis.conf

警告:次のステップで示されるコマンドを無効化・名前変更する方法は一例です。自分にとって意味のあるコマンドのみ無効化・名前変更してください。redis.io/commandsで全コマンド一覧を自身で見直し、どのように誤用されうるかを見極めます。

コマンドを無効にするには、以下に示すように、空の文字列(間に文字を含まない引用符のペアで指定)に名前を変更するだけです。

/etc/redis/redis.conf
. . .
# It is also possible to completely kill a command by renaming it into
# an empty string:
#
rename-command FLUSHDB ""
rename-command FLUSHALL ""
rename-command DEBUG ""
. . .

コマンドの名前を変更するには、次の例に示すように別の名前を付けます。変更されたコマンドの名前は、覚えやすくて推測されにくいものである必要があります。

/etc/redis/redis.conf
. . .
# rename-command CONFIG ""
rename-command SHUTDOWN SHUTDOWN_MENOT
rename-command CONFIG ASC12_CONFIG
. . .

変更を保存してファイルを閉じます。

コマンドの名前を変更した後、Redisを再起動して変更を適用します。

  • sudo systemctl restart redis.service

新しいコマンドをテストするには、Redisコマンドラインを入力します。

  • redis-cli

次に、認証をおこないます。

  • auth your_redis_password
Output
OK

前の例のように、CONFIGコマンドをASC12_CONFIGに名前変更したと仮定しましょう。最初に、元のCONFIGコマンドを使用してみてください。名前を変更したため、失敗するはずです。

  • config get requirepass
Output
(error) ERR unknown command `config`, with args beginning with:

また一方、名前を変更したコマンドの呼び出しは成功するはずです。大文字と小文字の区別はありません。

  • asc12_config get requirepass
Output
1) "requirepass" 2) "your_redis_password"

最後に、redis-cliを終了します。

  • exit

既にRedisコマンドラインを使用していて、Redisを再起動する場合は、再認証する必要があることに注意してください。再認証せずにコマンドを入力すると、このエラーが表示されます。

Output
NOAUTH Authentication required.

コマンドの名前変更の実践に関して、/etc/redis/redis.confSECURITYセクションの最後に次の注意書きが記されています。

/etc/redis/redis.conf
. . .
# Please note that changing the name of commands that are logged into the
# AOF file or transmitted to replicas may cause problems.
. . .

注:Redisプロジェクトは、「マスター」と「スレーブ」という用語を採択してしますが、DigitalOceanは一般的に別の呼称「プライマリ」と「セカンダリ」を使用します。  混乱を避けるために、ここではRedisドキュメントで使用される用語を採択しました。

つまり、名前を変更したコマンドがAOFファイルにない、あるいはあったとしてもAOFファイルがスレーブに送信されていない場合、問題ではありません。

したがって、コマンドの名前を変更する際には上記に留意してください。コマンドの名前を変更する最良のタイミングは、AOF永続性を使用していないときか、インストール直後、つまりRedisを使用するアプリケーションをインストールする前です。

AOFを使用してマスター・スレーブ構成のインストールを処理している場合は、プロジェクトのGitHub Issueページのこの回答を検討します。筆者の質問への回答は次のとおりです。

コマンドはAOFに書き込まれ、送られたのと同じ方法でスレーブに複製されます。このため、コマンドの名前が同様に変更されていないインスタンスでAOFをリプレイしようとすると、コマンドが実行できないため、不整合が発生する可能性があります(スレーブも同様)。 

したがって、名前の変更を処理する最良の方法は、マスター・スレーブインストールのインスタンスすべてに、名前を変更したコマンドが適用されるようにすることです。

まとめ

このチュートリアルでは、Redisをインストールして設定し、Redisインストールが正しく機能しているか検証し、ビルトインセキュリティ機能を使用して悪意のある攻撃者からの攻撃に対する脆弱性を低減しました。

いったん誰かがサーバーにログインしてしまうと、装備したRedis固有のセキュリティ機能を簡単に回避できることに留意してください。したがって、Redisサーバーの最も重要なセキュリティ機能はファイアウォール(前提条件の初期サーバーセットアップチュートリアル通りに設定したファイアウォール)です。悪意のある攻撃者がそのフェンスを飛び越えることは極めて困難です。

Creative Commons License