Amazon EKS で Pod から AWS Secrets Manager のシークレットを取得する
今回は、AWS Secrets Manager で管理しているシークレットの情報を Amazon EKS の Pod から取得させてみます。
これを実現するために、AWS Secrets and Config Provider (ASCP) を使用します。
下図がそのイメージです。
ASCP については、次の AWS ブログの記事や、AWS のドキュメントにも情報があるので、併せてご参照ください。
ここに記述している内容は、2022 年 9 月13 日時点で動作を確認しています。
また、対象にしている Kubernetes のバージョンは 1.23 です。
前提と環境
今回は、大阪リージョンの「 ASCP-cluster 」という名前の EKS クラスター (バージョンは 1.23 ) を使う前提とします。
kubectl や eksctl 、AWS CLI 、Helm、git が使用でき、対象のクラスターに接続できる Amazon Linux2 の環境で実施していきます。
AWS Secrets and Config Provider (ASCP) のインストール
これは、AWS のドキュメントに基づいて行います。
まず Helm を使って Secrets Store CSI ドライバーをインストールします。
helm repo add secrets-store-csi-driver https://kubernetes-sigs.github.io/secrets-store-csi-driver/charts
helm install -n kube-system csi-secrets-store secrets-store-csi-driver/secrets-store-csi-driver
次に ASCP をインストールします。
kubectl apply -f https://raw.githubusercontent.com/aws/secrets-store-csi-driver-provider-aws/main/deployment/aws-provider-installer.yaml
環境変数の作成
このあとの手順でよく利用する情報を環境変数に格納しておきます。
REGION=ap-northeast-3 CLUSTERNAME=ASCP-cluster
AWS Secrets Manager のシークレットの作成
今回は、ユーザー名: admin とパスワード: admin1234 という値をシークレットとして作成します。
aws --region "$REGION" secretsmanager create-secret --name ascp-demo-secret --secret-string '{"username":"admin", "password":"admin1234"}'
作成後に表示されるシークレットの ARN をメモしておきましょう。
Service Account の作成
Amazon EKS の Pod には、 AWS Secrets Manager のシークレットを取得するための権限を付与する必要があるので、Service Account を作成します。
まず 作成したシークレットの取得を許可する IAM ポリシーを作成します。次の例では、ポリシー名を ascp-demo-secret-policy にしています。
下記で、 <作成したシークレットのARN> の部分に、メモしておいた ARN を記載します。
POLICY_ARN=$(aws --region "$REGION" --query Policy.Arn --output text iam create-policy --policy-name ascp-demo-secret-policy --policy-document '{ "Version": "2012-10-17", "Statement": [ { "Effect": "Allow", "Action": ["secretsmanager:GetSecretValue", "secretsmanager:DescribeSecret"], "Resource": ["<作成したシークレットのARN>"] } ] }')
次に EKS クラスターの OIDC プロバイダを AWS IAM に関連付けます。これはクラスター単位で 1回行うだけで OK です。
eksctl utils associate-iam-oidc-provider --region="$REGION" --cluster="$CLUSTERNAME" --approve
そして、Service Account を作成します。次の例では、Service Account 名を ascp-demo-secret-sa にしています。
eksctl create iamserviceaccount --name ascp-demo-secret-sa --region="$REGION" --cluster "$CLUSTERNAME" --attach-policy-arn "$POLICY_ARN" --approve --override-existing-serviceaccounts
SecretProviderClass の作成
SecretProviderClass を作成するためのマニフェストを用意します。
次の例では、secret-provider-class.yaml
というファイルで作成しています。
このマニフェストの objectName
に作成したシークレットの名前を指定します。
apiVersion: secrets-store.csi.x-k8s.io/v1 kind: SecretProviderClass metadata: name: ascp-demo-secrets-provider-class spec: provider: aws parameters: objects: | - objectName: "ascp-demo-secret" objectType: "secretsmanager"
マニフェスト作成後、適用します。
kubectl apply -f secret-provider-class.yaml
Deployment の作成
それでは、Pod から シークレットの情報を取得してみます。
まず Deployment のマニフェストを作成します。Pod の spec には、Service Account や SecretProviderClass を正しく指定しましょう。
次の例では、/mnt/secrets-store をマウントに指定し、シークレットを取得できるようにして example-deployment.yaml
というファイルに保存しています。
apiVersion: apps/v1 kind: Deployment metadata: name: nginx-deployment labels: app: nginx spec: replicas: 2 selector: matchLabels: app: nginx template: metadata: labels: app: nginx spec: serviceAccountName: ascp-demo-secret-sa volumes: - name: secrets-store-inline csi: driver: secrets-store.csi.k8s.io readOnly: true volumeAttributes: secretProviderClass: "ascp-demo-secrets-provider-class" containers: - name: nginx-deployment image: nginx ports: - containerPort: 80 volumeMounts: - name: secrets-store-inline mountPath: "/mnt/secrets-store" readOnly: true
マニフェスト作成後、適用します。
kubectl apply -f example-deployment.yaml
無事に Deployment の Pod が作成されたことを確認します。
kubectl get deploy nginx-deployment
次の出力例ように、2つの Pod が READY になっていれば OK です。
出力例
NAME READY UP-TO-DATE AVAILABLE AGE nginx-deployment 2/2 2 2 15s
もし Pod が作成されない場合は、kubectl describe で イベントに エラー情報が出力されているか確認しましょう。
kubectl get pods kubectl describe pod <Pod名>
Pod が作成されたら、シークレットの値を参照してみます。
まず、Pod 名を確認します。
kubectl get pods
次に Pod 名を指定して コンテナのシェルに接続します。
kubectl exec -it <Pod名> -- /bin/bash
シェルに接続したらシークレットの情報を参照してみます。
cat /mnt/secrets-store/ascp-demo-secret
次の例のように表示されれば OK です。
出力例
{"username":"admin", "password":"admin1234"}
最後に
Kubernetes には Secrets というリソースがありますが、Amazon EKS にて Pod から AWS Secrets Manager を使い、認証情報などのシークレットを取得したい場合は、この AWS Secrets and Config Provider (ASCP) が役立ちそうですね。