ようへいの日々精進XP

よかろうもん

Vagrant + CoreOS + etcd + fleet + docker + datadog + crypt メモ

前の記事と同様の構成で fleet で Datadog Agent コンテナも管理する。

参考

www.datadoghq.com


まずは...

unit ファイル

[Unit]
Description=kappa-dd-agent
After=docker.service
Requires=docker.service

[Service]
ExecStartPre=-/usr/bin/docker kill dd-agent
ExecStartPre=-/usr/bin/docker rm dd-agent
ExecStart=/usr/bin/bash -c \
  "/usr/bin/docker run --privileged --name dd-agent -h `hostname` \
  -v /var/run/docker.sock:/var/run/docker.sock \
  -v /proc/mounts:/host/proc/mounts:ro \
  -v /sys/fs/cgroup/:/host/sys/fs/cgroup:ro \
  -e API_KEY=`etcdctl get /dd-api-key` \
datadog/docker-dd-agent"
ExecStop=/usr/bin/docker stop dd-agent

[Install]
WantedBy=multi-user.target

[X-Fleet]
Global=true

今回の [X-Fleet]Global=true となっているが、これは

Schedule this unit on all agents in the cluster. A unit is considered invalid if options other than MachineMetadata are provided alongside Global=true.

とあるのでクラスタ内の全てのエージェント(ノード)でユニット(サービス)を起動することになる。

API キー

以下のように etcd に登録してサービス起動時(コンテナ起動時)に etcd から取得する。

core@core-01 ~ $ curl -X PUT -L http://127.0.0.1:4001/v2/keys/dd-api-key -d value="xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"

念のために API キーを etcd から取得する。

core@core-01 ~ $ etcdctl get /dd-api-key
xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx

起動

core@core-01 ~ $ fleetctl submit kappa-dd-agent.service
core@core-01 ~ $ fleetctl load kappa-dd-agent.service
core@core-01 ~ $ fleetctl start kappa-dd-agent.service

監視開始でめでたしめでたし

f:id:inokara:20150811072538p:plain


ところが...

API キーは etcd に平文で

暗号化等されずに平文で入っているので改めて...

core@core-01 ~ $ etcdctl get /dd-api-key
xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx

これではいかんざき。

xordataexchange/crypt で暗号化

上記の記事を参考にさせて頂いて etcd に登録する API キーを暗号化してみるのでまずは gpg2 を利用して公開鍵と秘密鍵を生成する必要があるので以下のようなバッチファイルを作成して生成する。

core@core-01 ~ $ cat app.batch 
%echo Generating a configuration OpenPGP key
Key-Type: default
Subkey-Type: default
Name-Real: dd-api-key
Name-Comment: Datadog API key
Name-Email: app@example.com
Expire-Date: 0
%pubring .pubring.gpg
%secring .secring.gpg
%commit
%echo done

次に gpg2 で公開鍵と秘密鍵を生成。

# gpg2 --batch --armor --gen-key app.batch を実行して生成
core@core-01 ~ $ gpg2 --batch --armor --gen-key app.batch
gpg: Generating a configuration OpenPGP key
(暫く時間が掛かる...)
gpg: done

# 公開鍵 .pubring.gpg と 秘密鍵 .secring.gpg が生成されている
core@core-01 ~ $ ls -l .*.gpg
-rw-r--r-- 1 core core 1722 Aug 10 22:36 .pubring.gpg
-rw------- 1 core core 3488 Aug 10 22:36 .secring.gpg

続けて xordataexchange/crypt は Go で書かれておりバイナリも配布されているのでバイナリをダウンロードする。

core@core-01 ~ $ wget https://github.com/xordataexchange/crypt/releases/download/v0.0.1/crypt-0.0.1-linux-amd64
core@core-01 ~ $ mv crypt-0.0.1-linux-amd64 crypt                   
core@core-01 ~ $ chmod +x crypt
core@core-01 ~ $ ./crypt -h
usage: ./crypt COMMAND [arg...]

commands:
   get  retrieve the value of a key
   set  set the value of a key

暗号化して登録したい情報をファイルで用意する。

core@core-01 ~ $ cat dd-api-key
xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx

用意した JSON ファイルを利用して etcd に情報を登録する。

# help を確認
core@core-01 ~ $ ./crypt set -h
usage: ./crypt set [args...] key file
  -backend="etcd": backend provider
  -endpoint="": backend url
  -keyring=".pubring.gpg": path to armored public keyring

# 登録する
core@core-01 ~ $ ./crypt set -backend=etcd -keyring=/home/core/.pubring.gpg /dd-api-key dd-api-key

念のために etcdctl コマンドで確認する。

# 暗号化されている
core@core-01 ~ $ etcdctl get /dd-api-key
wcBMA7haxrMkuVotAQgAjhI52MGY+xM/WY7cliXLse0i5g5in8j2eo51rWGq7c6zsWmxiVD+nwBGubLiqWWz3xeR3wVgXy4nE4qX2gpW3VoK8sDZZ9kDEJ5OtgU/LdLXbEgG8GYHx8M3ODeuJQRr9+y4fiJcDOBXAVh2m5Uj2NfdyHkGv+7HchFfyNDLt6pXLFF6aRIgED10cC65Qkujtd/C1ouGrHZq9tjWYSw7MqPg94+vsXZNx9BCs9ZW4uzMDIwrKhxXvNXq0m/6bW9ky7ZrfbZGAlBbXYplMY9qQV5Rhn0G0w9xkEugvWkjX1y/mO+NoZKbxSyP9JgsnvtA5hXY9WzNzO5913uiHsbbx9LgAeR18eKNNiJ16JGhLf+pge474aeb4JbgPOHm0uDy4tG4R1vgn+NKerfJJZFBjuCt4QTE4FTiTYtrv+Cn4Ssk4J7icd3BuOAC4z8Whhmt7ECf4KfkvtnNb76/VjGO22dKAxBr9eKCT0Ps4UzIAA==

crypt を利用して復号化して確認する。

# help を確認
core@core-01 ~ $ ./crypt get -h
usage: ./crypt get [args...] key
  -backend="etcd": backend provider
  -endpoint="": backend url
  -secret-keyring=".secring.gpg": path to armored secret keyring

# 確認
core@core-01 ~ $ ./crypt get -backend=etcd -secret-keyring=/home/core/.secring.gpg /dd-api-key
xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx

暗号化された API キーを利用して Datadog Agent のコンテナを起動してみる。

core@core-01 ~ $ docker run -d \
  --name dd-agent \
  -h `hostname` \
  -v /var/run/docker.sock:/var/run/docker.sock \
  -v /proc/mounts:/host/proc/mounts:ro \
  -v /cgroup/:/host/sys/fs/cgroup:ro \
  -e API_KEY=`/home/core/crypt get -backend=etcd -secret-keyring=/home/core/.secring.gpg /dd-api-key` \
datadog/docker-dd-agent

-e オプションを利用してコンテナに環境変数 API_KEY を渡す際に crypt get で復号化してコンテナを起動している。

f:id:inokara:20150811082429p:plain

めでたし...と言いたいところだけど、気になった点を幾つか。

  • etcd に登録された暗号化データを利用するノード全てに crypt を導入して利用できるようにしておく必要がある(これはやるしかない)
  • せっかく etcd で暗号化していても起動したコンテナに対して docker inspect すると Environment の値が見れてしまうのに気付いた...(これは Environment で API キー等を渡すアプリケーションコンテナでは共通の悩みだとオモフ)

おわり

etcd や Consul の KVS に

環境変数や今回のような API キー等を登録して利用するのは色々と捗りそうだが、登録する内容によっては暗号化はしておきたいので crypt は良さそう。

CoreOS + etcd + fleet + Docker

従来のサーバー管理と比較すると異次元だが全てのアプリケーションを Docker で運用するというのは、上記のような認証情報管理等の課題も多いと思われるが、面白いなあと今更ながらに思った。