EKSでの機密情報の隠蔽にkubernetes-external-secretsを導入してみた

アソビュー!SREチームの霧生です。
この記事はアソビュー! Advent Calendar 2019 13日目の記事となります。

アソビューでは最近一部のアプリケーションのインフラにEKSを導入しています。
その運用をしていく中でDBのuser/passやAPIキーといった機密情報を隠蔽したい要件が出てきました。 ECSでは下記のClassmethodさんの記事にある通り、タスク定義とパラメータストアによる隠蔽ができますが、EKSではまだ公式で対応していないためどうしようかと悩んでいたところ、kubernetes-external-secretsを見つけました。

dev.classmethod.jp

kubernetes-external-secretsとは

kubernetes-external-secretsはドメインレジストラサービスを提供しているGoDaddy社がOSSとして公開しているもので、AWS Secrets ManagerAWS Systems Manager パラメータストアを利用して、機密情報の引き渡しが行えます。

github.com

より詳細に知りたい場合はGitHubにもありますが、下記の公式ブログが参考になると思います。 jp.godaddy.com

導入の決め手でもありますが、kubernetes-external-secretsは引き渡したい機密情報をyaml管理できる点が優れていると感じています。

EKS環境にkubernetes-external-secretsをインストールする

install方法は公式のGitHubでも公開されていますが、今回は単にkubectlコマンドを利用したインストールを試していきたいと思います。
(バージョン2.1までは生のyamlもあったのですが、現在はHelmを利用したインストールが推奨されているようです。)

まずはkubectlが利用できる環境でHelmをインストールします。 helm.sh

インストールが完了したら、kubernetes-external-secretsをローカルに落としてきます。

$ git clone https://github.com/godaddy/kubernetes-external-secrets

kubernetes-external-secretsのルートディレクトリに移動し、下記のコマンドを実行すると./output_dir以下にyamlファイルが生成されます。

$ helm template -f charts/kubernetes-external-secrets/values.yaml --output-dir ./output_dir ./charts/kubernetes-external-secrets/

あとは生成されたyamlファイルをそれぞれapplyしていけばインストールは完了です。

インストール時の注意点

環境変数等の設定について

基本的にはデフォルトのままで問題ないと思いますが、AWS_REGIONの値が利用する環境と違っていると値の取得ができないため注意が必要です。 設定の一覧はここから確認できます。

権限について

AWS Secrets Managerを使う場合とパラメータストアを使う場合でそれぞれ必要な権限が変わります。 こちらもサンプルがGitHubのページにありますが下記にそれぞれ載せておきます。

  • AWS Secrets Manager
{
  "Version": "2012-10-17",
  "Statement": [
    {
      "Effect": "Allow",
      "Action": [
        "secretsmanager:GetResourcePolicy",
        "secretsmanager:GetSecretValue",
        "secretsmanager:DescribeSecret",
        "secretsmanager:ListSecretVersionIds"
      ],
      "Resource": [
        "arn:aws:secretsmanager:ap-northeast-1:111122223333:secret:aes128-1a2b3c",
        "arn:aws:secretsmanager:ap-northeast-1:111122223333:secret:aes192-4D5e6F",
        "arn:aws:secretsmanager:ap-northeast-1:111122223333:secret:aes256-7g8H9i"
      ]
    }
  ]
}
  • パラメータストア
{
  "Version": "2012-10-17",
  "Statement": [
    {
      "Effect": "Allow",
      "Action": "ssm:GetParameter",
      "Resource": "arn:aws:ssm:ap-northeast-1:123456789012:parameter/prod-*"
    }
  ]
}

実際に使ってみる

今回はパラメータストアを利用した方法を紹介します。

パラメータストアへの機密情報の登録は上記でも紹介したClassmethodさんの記事が参考になると思います。 dev.classmethod.jp

パラメータストアで機密情報を登録した後、次はkubernetes-external-secretsを利用してSecretsを作成します。
/staging/test-app/TEST_VALUEという変数をパラメータストアで登録した場合、yamlは下記のようになります。

apiVersion: 'kubernetes-client.io/v1'
kind: ExternalSecret
metadata:
  name: test-app
secretDescriptor:
  backendType: systemManager
  data:
    - key: /staging/test-app/TEST_VALUE  # パラメータストアで設定した変数の名前
      name: test-value                   # この変数の一意の名前を設定する

作成されたExternalSecretを例えばDeploymentで利用する場合は下記のように設定します。

apiVersion: extensions/v1beta1
kind: Deployment
metadata:
  name: test-app
spec:
~中略~
          env:
            - name: TEST_VALUE
              valueFrom:
                secretKeyRef:
                  name: test-app      #ExternalSecretのmetadata.nameで指定した値
                  key: test-value     #ExternalSecretのsecretDescriptor.data.nameで指定した値

注意点

これは導入した後に見えた問題なのですが、DBのuser/passといったアプリケーションの起動時に参照される情報をパラメータストアに登録し、同じyamlファイルでExternalSecretとDeploymentを定義すると、ExternalSecretがAWSからパラメータを取ってくる際のほんの少しのラグによってDeploymentの作成時にSecretsの取得に失敗し、初回のアプリケーションの起動に失敗します。
yamlを分けてデプロイの順番を整理することで対応しましたが、利用する状況によっては注意が必要です。

導入してみて

正直ここまで公式のREADMEの内容をなぞってるだけでは?という感じなのですが、それほど導入も利用も簡単です。
kubernetes-external-secretsを導入することで、ソースと機密情報を完璧に分離しつつ、利用するyamlは管理できる理想の状態が作れました。 また、利用するパラメータストアの変数はTerraformで作成することで人的ミスを減らしています。

いくつか注意点はあるものの、EKS環境では現状最適解ではないかと思っています。

最後に

ベンチャーやスタートアップでは優先したいことも多く軽視されがちな部分ではありますが、導入も利用も簡単なので十分に検討する価値があるかと思います。 バージョンアップも盛んに行われているようなので、今後にも期待です。

アソビュー!ではSREの募集も行っています。 少しでも興味をお持ちになりましたら下記のページをご覧いただければと思います! hrmos.co

それでは良いKubernetesライフを!