TL;DL
あまりニーズは無いのかもしれないが、気になったので以下のドキュメントや参考記事等を見ながら手を動かしてみた。
ちなみに Consul とは関係無いけどサーバー証明書周りについてはちゃんと勉強する必要があるし(CSR 作って証明書を取得する位しか知らない)、Gossip や RPC についてもフワッとしか知らないのでちゃんと勉強する必要がある。
尚、以下にデモ環境を用意した。
README に従って Playbook を流せば Consul の暗号化をザクっと試せるはず…。
Consul が利用する通信路(ポート番号)
Consul が利用している通信路(開放されているポート)については以下の通り。
用途 | ポート番号(デフォルト) | 詳細 |
---|---|---|
Server RPC | TCP 8300 | 全ての agent からの RPC リクエストを処理する |
Serf LAN | TCP / UDP 8301 | LAN 内の Gossip を処理する |
Serf WAN | TCP / UDP 8302 | WAN 内の Server からの Gossip を処理する |
CLI RPC | TCP 8400 | 全ての agent からの CLI からの RPC リクエストを処理する |
HTTP API | TCP 8500 | 全てのクライアントからの HTTP API リクエストを処理する |
DNS Interface | TCP 8600 | 全てのクライアントからの DNS クエリを処理する |
以下、参考にさせて頂いた記事。
有難うございます。
暗号化する通信路
構成
今回は以下のような構成で検証を行う。
全ての Consul agent を Server モードで動かしている。
今回、暗号化する通信路
用途 | ポート番号(デフォルト) | 暗号化の方法 |
---|---|---|
Server RPC | TCP 8300 | TLS を有効にする |
Serf LAN | TCP / UDP 8301 | 暗号化キーを生成して agent 間で共有する |
HTTP API | TCP 8500 / TCP 10443 | HTTP API を HTTPS でも処理出来るように HTTPS を有効にする |
以下、参考にさせて頂いた記事。
有難うございます。
Gossip の通信路を暗号化する
概要
consul keygen
でキーをを生成してクラスタ内のエージェントで共有する
暗号化キーを生成する
$ docker exec consul-01 consul keygen xxxxxxxxxxxxxxxxxxxxxxxxx
生成したキーを consul の設定ファイルに定義する
{ "encrypt": "xxxxxxxxxxxxxxxxxxxxxxx" }
確認
- 以下暗号化していない状態
平文で確認出来る。
- 以下は暗号化している状態
暗号化されているように見える。
RPC リクエストの暗号化
概要
- CA 証明書、秘密鍵、証明書を作成し配置する
- 検証目的なのでプライベート CA を作成、自己証明書にサインする
verify_incoming
とverify_outgoing
でリクエストトラフィックと着信トラフィックの検証を定義する
プライベート CA を構築して自己証明書を発行する
以下の手順は参考にさせて頂いた記事の丸パクリ。
# プライベート CA 用ディレクトリ作成 $ mkdir etc/consul.d/ssl/CA # プライベート CA 用ディレクトリに移動 $ cd etc/consul.d/ssl/CA # 証明書のシリアル番号が記録されるファイルを作成(初期値を 000a にする) $ echo "000a" > serial # 証明書のインデックスが記録されるファイルを作成 $touch certindex # 自己署名ルート証明書のリクエスト $ openssl req -x509 -newkey rsa:2048 -days 3650 -nodes -out ca.cert # 自己証明書のリクエスト(CSR と秘密鍵の生成) $ openssl req -newkey rsa:1024 -nodes -out consul.csr -keyout consul.key # 認証局の設定 $ cat > myca.conf [ ca ] default_ca = myca [ myca ] unique_subject = no new_certs_dir = . certificate = ca.cert database = certindex private_key = privkey.pem serial = serial default_days = 3650 default_md = sha1 policy = myca_policy x509_extensions = myca_extensions [ myca_policy ] commonName = supplied stateOrProvinceName = supplied countryName = supplied emailAddress = optional organizationName = supplied organizationalUnitName = optional [ myca_extensions ] basicConstraints = CA:false subjectKeyIdentifier = hash authorityKeyIdentifier = keyid:always keyUsage = digitalSignature,keyEncipherment extendedKeyUsage = serverAuth,clientAuth EOT # 自己証明書の作成(証明書要求に署名して証明書を作成する) $ openssl ca -batch -config myca.conf -notext -in consul.csr -out consul.cert # CA 証明書、証明書、秘密鍵を etc/consul.d/ssl/ 以下にコピーする $ cp ca.cert consul.key consul.cert ../
発行した証明書を consul の設定ファイルに定義する
{ "ca_file": "/etc/consul.d/ssl/ca.cert", "cert_file": "/etc/consul.d/ssl/consul.cert", "key_file": "/etc/consul.d/ssl/consul.key", "verify_incoming": true, "verify_outgoing": true }
以下、設定項目の詳細
設定項目 | 値 | 詳細 | 備考 |
---|---|---|---|
ca_file | /etc/consul.d/ssl/ca.cert | CA 証明書ファイルへのパスを定義 | Server / Client に必須 |
cert_file | /etc/consul.d/ssl/consul.cert | 証明書へのパスを定義 | Server / Client に必須 |
key_file | /etc/consul.d/ssl/consul.key | 秘密鍵へのパスを定義 | Server / Client に必須 |
verify_incoming | true | server に着信する接続を検証する | Server に必須 |
verify_outgoing | true | agent の外部接続を検証する | Server / Client に必須 |
設定したら Consul を再起動を行って設定を反映。
確認
- TLS 設定無し
- TLS 設定有り
暗号化されているように見える。
以下、参考にさせて頂いた記事。
- https://www.digitalocean.com/community/tutorials/how-to-secure-consul-with-tls-encryption-on-ubuntu-14-04
- https://www.mauras.ch/securing-consul.html
有難うございました。
HTTP API の通信路を暗号化する
概要
- デフォルトで HTTP API の HTTPS は無効となっているので
ports
オプション有効にした上でhttps
で利用するポート番号を指定する(今回は10443
)
{ "client_addr": "0.0.0.0", "ports": { "https": 10443 }, "ca_file": "/etc/consul.d/ssl/ca.cert", "cert_file": "/etc/consul.d/ssl/consul.cert", "key_file": "/etc/consul.d/ssl/consul.key", "verify_incoming": true, "verify_outgoing": true }
確認
- 以下のように秘密鍵と証明書ファイルを指定してリクエストを投げる
docker exec consul-01 curl -s -k --cert /etc/consul.d/ssl/consul.cert --key /etc/consul.d/ssl/consul.key 'https://localhost:10443/v1/status/leader' "172.17.0.17:8300"
- HTTP 接続
-
HTTPS 接続
ちゃんと暗号化されている。
メモ
暗号化と関係無いけど remote 越しの consul exec を無効にしたい
consul exec
を使うとクラスタ内のノードで同じコマンドを実行することが出来て便利だが、このコマンドの実行自体を以下のように設定して無効にすることが出来る。(実際の挙動としてはコマンドが無視されるようだ)
{ "disable_remote_exec": true }
無効にした状態で consul exec
を実行すると以下のようにコマンドの実行は行われない。
$ docker exec consul-01 consul exec pwd 0 / 0 node(s) completed / acknowledged
Consul とは関係無いけど Docker コンテナの通信を tcpdump したい
下図のようなイメージので docker0 インターフェース指定して tcpdump すると良い。
以下、実行例。
$ sudo tcpdump -X -i docker0 port 8300 -w /tmp/consul-8300.capture $ sudo tcpdump -X -i docker0 port 8301 -w /tmp/consul-8301.capture $ sudo tcpdump -X -i docker0 port 8500 -w /tmp/consul-8500.capture $ sudo tcpdump -X -i docker0 port 10443 -w /tmp/consul-10443.capture
以下、参考にさせて頂いた記事。
最後に
気になる点
- 通信路を暗号化したことによるパフォーマンスへの影響の有無、そして、それを計測する方法
- DC 間の暗号化(環境作れて無いので未確認)
- TL;DL の使い方が正しいのか
以上。