ようへいの日々精進XP

よかろうもん

Consul の暗号化について調べた雑なメモ

tl;dr

あまりニーズは無いのかもしれないが、気になったので以下のドキュメントや参考記事等を見ながら手を動かしてみた。

www.consul.io

ちなみに 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 クエリを処理する

以下、参考にさせて頂いた記事。

有難うございます。


暗号化する通信路

構成

今回は以下のような構成で検証を行う。

f:id:inokara:20150813074150p:plain

全ての Consul agent を Server モードで動かしている。

今回、暗号化する通信路

用途 ポート番号(デフォルト) 暗号化の方法
Server RPC TCP 8300 TLS を有効にする
Serf LAN TCP / UDP 8301 暗号化キーを生成して agent 間で共有する
HTTP API TCP 8500 / TCP 10443 HTTP APIHTTPS でも処理出来るように HTTPS を有効にする

以下、参考にさせて頂いた記事。

有難うございます。


Gossip の通信路を暗号化する

概要

  • consul keygen でキーをを生成してクラスタ内のエージェントで共有する

暗号化キーを生成する

$ docker exec consul-01 consul keygen
xxxxxxxxxxxxxxxxxxxxxxxxx

生成したキーを consul の設定ファイルに定義する

{
  "encrypt": "xxxxxxxxxxxxxxxxxxxxxxx"
}

確認

  • 以下暗号化していない状態

f:id:inokara:20150813074214p:plain

平文で確認出来る。

  • 以下は暗号化している状態

f:id:inokara:20150813074235p:plain

暗号化されているように見える。


RPC リクエストの暗号化

概要

  • CA 証明書、秘密鍵、証明書を作成し配置する
  • 検証目的なのでプライベート CA を作成、自己証明書にサインする
  • verify_incomingverify_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 << EOT >> 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 設定無し

f:id:inokara:20150813074256p:plain

  • TLS 設定有り

f:id:inokara:20150813074310p:plain

暗号化されているように見える。

以下、参考にさせて頂いた記事。

有難うございました。


HTTP API の通信路を暗号化する

概要

  • デフォルトで HTTP APIHTTPS は無効となっているので 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 接続

f:id:inokara:20150813074331p:plain

f:id:inokara:20150813074350p:plain

ちゃんと暗号化されている。


メモ

暗号化と関係無いけど 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 すると良い。

f:id:inokara:20150813074417p:plain

以下、実行例。

$ 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 の使い方が正しいのか

以上。