AWS System Manager Parameter StoreからパラメータをYAMLにいい感じに展開する

AWS上でアプリケーションを動作させる際、みなさん秘匿情報はどう扱っていますか?

  • KMSをつかう
  • Parameter Storeをつかう
  • Privateな設定管理ツールで管理する

あたりが一般的かなと思います。

開発リポジトリには秘匿情報をいれないポリシーで開発している場合、設定用のリポジトリを分けたり、別のコードとして管理する必要があるなど、ややまどろっこしいなあと思っていました。

そこで今回はYAMLにマクロ展開の機能を追加して、このあたりの管理を楽にできないかと思い、PoCしてみました。

Parameter Storeとは

Parameter Storeはキーと値を保存するシンプルな仕組みです。ざっくり紹介すると、以下が特徴です。

  • キーと値のペアを保存できる
  • 平文あるいは暗号化するか否かを選択可能
  • 暗号化のためのCMK(customer master key)を選択可能

aws-cliを利用した操作例は次のとおりです。

# 平文の場合
$ aws ssm put-parameter --name a_name --value "a value"
$ aws ssm get-parameter --name a_name --with-no-decryption

# 暗号化する場合
$ aws ssm put-parameter --name a_name --value "a value" --type SecureString
$ aws ssm get-parameter --name a_name --with-decryption

参考: http://docs.aws.amazon.com/systems-manager/latest/userguide/systems-manager-paramstore.html

yaml.Unmarshal を拡張する

これらをアプリケーション実行時に環境変数になりに展開することもできます。ECSなどのコンテナ環境で環境変数に秘匿情報を平文でいれるのはセキュアではありません。

そこでYAMLファイルを読み取る際に値を展開すればよいのでは、と考えて実装してみました。

https://github.com/suzuken/yamlssm

機能はシンプルです。

  • yaml.Unmarshal と同様のインタフェースです。(import文を変えるだけで適用可能)
  • ssm:// から始まる場合のみParameter Storeから値を展開します。

コード例は次のとおりです。

type T struct {
    Foo string
    Bar string
}
var t T

if err := yamlssm.Unmarshal([]byte[`
foo: ssm://prod.database.name
bar: test
`], &t); err != nil {
    // ...
}

fmt.Print(t.Foo) // -> value of prod.database.name on your ssm

ひとまずデフォルトのCMSのみサポートしています。実行権限についてはaws-sdk-goの認証に準じます。

Parameter Storeにパラメータが存在しない場合にはUnmarshalがエラーになります。実際のアプリケーションでは初期化処理時にYAMLで設定を読み込むと思うので、エラーの場合にはpanicなりで起動させないようにするとよいです。

まとめ

Parameter Store便利なのでどんどんつかっていきましょう。