スマートキャンプの入山です。
Kubernetes(k8s)を運用されている方々は、Podに受け渡す機密情報をどうやって管理していますか?
k8sでの機密情報の管理といえばSecretリソースが一般的ですが、Secretリソースを管理する上では以下のような課題に悩む方が多いのではないでしょうか?
- SecretはBase64エンコードのみなので、内容が確認できれば簡単にデコードできてしまう
- SecretリソースのマニフェストにBase64エンコードのみの機密情報を含むため、GitHubなどにそのままコミットするのは危険
これらの対策として、kubesecやSealed Secretsなどを利用して暗号化を行う方法が主流だと思いますが、今回は外部のKMSなどに保存した機密情報をk8sに直接受け渡すことが可能なKubernetes External Secretsについて、EKSとAWS Secrets Managerを例に紹介したいと思います!
Kubernetes External Secretsとは
概要
Kubernetes External Secretsは、ドメインレジストラ・レンタルサーバサービスを提供しているGoDaddy社が公開しているOSSです。
外部のKMSなどに保存した機密情報をSecretリソースとしてk8sクラスタに直接受け渡すことができるもので、現時点で以下との連携をサポートしています。
- AWS Secrets Manager
- AWS System Manager
- Hashicorp Vault
- Azure Key Vault
- GCP Secret Manager
動作としては、対象とする機密情報を指定したExternalSecretsリソースを作成しておくことで、コントローラがKMSに保存されている値をSecretリソースに反映してくれる
というシンプルなものです。
メリット
冒頭に紹介したSecretを暗号化して管理する方法と比較して、以下のようなメリットがあると思います。
- k8sで利用するSecretリソースのマニフェストに機密情報を保持しなくてよくなる
- 機密情報に関する管理(機密情報、アクセス権限など)を一元化できる
- 機密情報変更に伴う反映コストが減る
導入
公式のGitHubリポジトリに記載されている手順に従って、実際に導入していきます。 今回は、EKSとAWS Secrets Managerの環境で試してみます。
インストール
インストールは、helmで全て行う方法とhelmとkubectlを使用して行う方法があります。 今回は、helmとkubectlを使用して行う方法で実施します。
1. helmをインストール
マニフェストの生成にhelmが必要となるため、helmコマンドをインストールします。
2. リポジトリをclone
Kubernetes External Secretsのリポジトリをローカルにcloneします。
$ git clone https://github.com/godaddy/kubernetes-external-secrets
3. マニフェストを生成
cloneしたディレクトリで以下コマンドを実行して、マニフェストを生成します。
※公式の手順のコマンドにオプションを追加して、nameとregionを変更しています。 オプションの詳細は、リポジトリに記載されています。
$ helm template -f charts/kubernetes-external-secrets/values.yaml --output-dir ./output_dir ./charts/kubernetes-external-secrets/ --name test --set env.AWS_REGION='ap-northeast-1'
コマンドを実行すると指定したoutput_dir
以下にマニフェストが生成されます。
4. 生成されたマニフェストをapply
output_dir
に生成されたマニフェストをapplyすればインストールは完了です。
kubectl apply -f ./output_dir/kubernetes-external-secrets/templates/
アクセス権限設定
Kubernetes External Secretsを使ってAWS Secrets Managerにアクセスするために権限設定が必要となります。
公式のサンプルを参考に以下のようなIAMポリシーを作成後、ロールにアタッチします。
{ "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:aes256-7g8H9i" # AWS Secrets Managerからk8sに受け渡したいSecretのARN ] } ] }
実際に運用で利用する場合はkube2iamなどを利用して権限の付与先を最小限にすることが推奨されています。
実際に試してみる
1. AWS Secrets ManagerにSecretを保存
以下のコマンドやAWSコンソールを使って、AWS Secrets ManagerにSecretを保存します。
$ aws secretsmanager create-secret --region ap-northeast-1 --name test/credentials --secret-string '{"username":"admin","password":"1234"}'
2. ExternalSecretリソースを作成
k8sでSecretリソースを作成する代わりに、AWS Secret Managerから取得したいSecretの情報を指定したExternalSecretリソースを作成します。
以下ようなマニフェストを作成して、applyすれば完了です。
apiVersion: kubernetes-client.io/v1 kind: ExternalSecret metadata: name: test-credentials spec: backendType: secretsManager # optional: specify role to assume when retrieving the data roleArn: arn:aws:iam::123456789012:role/test-role # 作成したIAMポリシーを付与したロールのARNを指定 data: - key: test/credentials # AWS Secret Managerに保存したSecretのname name: username # 変数名を設定 property: username # AWS Secret Managerに保存したSecretのどのキーを取得するか指定 - key: test/credentials name: password property: password
3. k8sのSecretリソースを確認
ExternalSecretリソースで指定したSecretが、k8sのSecretリソースとして受け渡されているか確認します。
$ kubectl get secret test-credentials -o=yaml apiVersion: v1 data: username: YWRtaW4= password: MTIzNA== kind: Secret ︙
Secretリソースを取得した情報を参照し、指定したSecretがBase64でエンコードされた状態で表示されていれば成功です。
これで通常のSecretリソースと同様にPod内で利用することが可能となっており、AWS Secrets Manager側でSecretの値が変更された場合も自動でk8sのSecretリソースに反映されます。
最後に
今回は、KubernetesのSecretをKMSと連携して管理する方法を紹介しました!
機密情報を含んだSecretリソースのマニフェストをリポジトリにコミットせずに管理できることは、かなりのメリットだと思います。 また、当初はAWSのサポートだけでしたが、現時点でAzureやGCPもサポートしており、状況に合わせてKMSを選択できることも嬉しい点ですね!
権限などに注意して作り込めば、k8sのSecretを良い感じに管理できるようになるのではないでしょうか?参考になれば幸いです!