のべラボ.blog

謙虚に、臆せず、さぼらずにブログを書く

Amazon EKS で Pod から AWS Secrets Manager のシークレットを取得する

今回は、AWS Secrets Manager で管理しているシークレットの情報を Amazon EKS の Pod から取得させてみます。

これを実現するために、AWS Secrets and Config Provider (ASCP) を使用します。

下図がそのイメージです。

https://cdn-ak.f.st-hatena.com/images/fotolife/n/neob/20220913/20220913083939.png

ASCP については、次の AWS ブログの記事や、AWS のドキュメントにも情報があるので、併せてご参照ください。

aws.amazon.com

docs.aws.amazon.com

ここに記述している内容は、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) が役立ちそうですね。