1
1

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

EKSでExternal Secret Operatorを利用して、シークレットをAWS Secrets Managerから取得する

Last updated at Posted at 2025-09-20

はじめに

Kubernetesでアプリケーションを運用する際、データベースのパスワードやAPIキーなどの機密情報をどのように管理するかは重要な課題です。従来の方法では、これらの情報をマニフェストファイルに直接記述したり、手動でKubernetes Secretを作成する必要がありました。しかし、この方法では機密情報がコードに埋め込まれるリスクがあり、パスワード変更時の運用負荷も大きくなります。

このデモでは、Amazon EKSでExternal Secrets Operatorを使用して、AWS Secrets ManagerからRDSの認証情報を自動的に取得し、Kubernetesアプリケーションで安全に利用するデモ環境を構築しました。External Secrets Operatorを使用することで、機密情報を外部のシークレット管理サービスで一元管理し、Kubernetesクラスター内では自動的にSecretリソースを作成・更新できるようになります。

パターン別実装

External Secrets Operatorで取得したシークレットをアプリケーションで利用する方法として、2つの異なるアプローチを実装しています。それぞれに特徴があり、用途に応じて選択できます。

環境変数パターンは、KubernetesのSecretから環境変数として値を注入するシンプルな方法です。実装が簡単でデモや開発環境に適していますが、kubectl操作で環境変数の内容が見えてしまうセキュリティ上の懸念があります。

ファイルマウントパターンは、Secretをファイルとしてコンテナ内にマウントする方式で、kubectl操作では環境変数として表示されないため、よりセキュアです。ただし、アプリケーション側でファイルを読み込む実装が必要になるため、少し複雑になります。本番環境での利用に推奨されます。

External Secrets Operatorとは

External Secrets Operatorは、外部のシークレット管理サービス(AWS Secrets Manager、HashiCorp Vault等)からKubernetesのSecretを自動で作成・同期するオープンソースツールです。このツールを使用することで、機密情報の管理を外部サービスに委ね、Kubernetesクラスター内では自動的にSecretリソースを生成・更新できるようになります。

従来の課題と解決方法

従来のKubernetesでは、シークレットを扱う際に多くの課題がありました。パスワードをマニフェストファイルに直接書き込む必要があり、パスワード変更時には手動でファイルを更新する必要がありました。また、base64エンコードが必要で、実質的にはパスワードがコードに埋め込まれる形となり、セキュリティリスクが高い状態でした。

また、base64は暗号化ではなく、ただのエンコーディングなので、簡単に解読されてしまいます。

# 従来の方法:手動でSecretを作成する必要があった
apiVersion: v1
kind: Secret
metadata:
  name: db-secret
data:
  username: YWRtaW4=  # base64エンコードが必要
  password: cGFzc3dvcmQ=  # パスワードがコードに埋め込まれる

External Secrets Operatorは、これらの課題を解決します。シークレットをAWS Secrets Managerなどの外部サービスで一元管理し、Kubernetesクラスター内では自動的にSecretリソースを作成・更新する仕組みを提供します。パスワードをコードに書く必要がなくなり、パスワード変更時も自動で同期されるため、セキュリティが大幅に向上し、運用負荷も軽減されます。

動作の流れ:

  1. AWS Secrets Managerにシークレットを保存
  2. External Secrets OperatorがAWS Secrets Managerを定期的に監視、シークレットを取得
  3. External Secrets OperatorがKubernetes Secretを自動作成・更新
  4. アプリケーションがそのSecretを利用
    • 環境変数パターン: valueFrom secretKeyRefで環境変数として注入
    • ファイルマウントパターン: volumeMountでファイルとしてマウント

メリット:

  • セキュリティ向上: パスワードをコードに書かない
  • 自動同期: パスワード変更時に自動でKubernetesに反映
  • 中央管理: AWS Secrets Managerで一元管理
  • 監査: アクセスログが残る
  • ローテーション: 自動パスワードローテーション対応

システム構成

構築したシステムは、AWS上でマネージドサービスを活用したセキュアなアーキテクチャを採用しています。RDSの認証情報をAWS Secrets Managerで管理し、External Secrets OperatorがEKSクラスター内のKubernetes Secretとして自動同期する仕組みになっています。StreamlitアプリケーションはALB経由でインターネットからアクセス可能で、同期されたシークレットを使用してRDS PostgreSQLに接続します。

archi-image.png

システムの主要コンポーネント:

  • EKS: Kubernetesクラスターを提供するマネージドサービス
  • AWS Secrets Manager: RDS PostgreSQLの認証情報を安全に保存
  • External Secrets Operator: Secrets ManagerからKubernetes Secretを自動生成
  • Streamlit App: PostgreSQLに接続してメッセージを保存・表示
  • RDS PostgreSQL: データの永続化
  • ALB: インターネットからのアクセス

プロジェクト構成

共通インフラストラクチャと各パターン固有の実装に分かれた構成になっています。infrastructure/フォルダには両パターンで共通利用するAWSリソース(VPC、RDS、Secrets Manager等)とEKSクラスターの定義が含まれており、各パターンフォルダには、それぞれ異なるシークレット利用方式に対応したStreamlitアプリケーションとKubernetesマニフェストが配置されています。

eks-external-secret-operator/
├── infrastructure/       # 共通インフラ(CloudFormation、EKS)
│   ├── cloudformation/
│   └── eksctl/
│
├── env-vars-pattern/           # 環境変数パターン
│   ├── app/
│   └── infrastructure/manifests/   # Kubernetesマニフェストのみ
│    
└── file-mount-pattern/         # ファイルマウントパターン
    ├── app/
    └── infrastructure/manifests/   # Kubernetesマニフェストのみ

共通インフラ:

  • AWSインフラ: infrastructure/cloudformation/infrastructure.yamlで定義
  • EKSクラスター: infrastructure/eksctl/create-cluster-nodegroup.yamlで構成
  • External Secrets Operator: 同じ設定を使用
  • AWS Secrets Manager: 同じSecretを使用

違いはKubernetesマニフェストとアプリケーションコードのみとなっています。

実装手順

システムのデプロイは段階的に進めていきます。まず共通のインフラストラクチャを構築し、その後各パターンに応じたアプリケーションをデプロイします。

共通手順(両パターン共通)

1. インフラストラクチャのデプロイ

AWSコンソールからCloudFormationを使用してインフラストラクチャをデプロイします。AWSコンソールでCloudFormationサービスにアクセスし、「スタックの作成」を選択して、infrastructure/cloudformation/infrastructure.yamlファイルをアップロードします。このテンプレートには、VPC、サブネット、RDS、Secrets Manager、ECRなどの必要なAWSリソースが定義されています。

RDS Secrets Manager設定(CloudFormation)
# RDS PostgreSQLインスタンスとSecrets Managerの設定
RDSInstance:
  Type: AWS::RDS::DBInstance
  Properties:
    DBInstanceIdentifier: test-postgres
    DBInstanceClass: db.t3.micro
    Engine: postgres
    MasterUsername: !Ref DBMasterUsername
    MasterUserPassword: !Ref DBMasterUserPassword
    ManageMasterUserPassword: true  # Secrets Managerで自動管理
    MasterUserSecret:
      SecretArn: !Ref RDSSecret

RDSSecret:
  Type: AWS::SecretsManager::Secret
  Properties:
    Name: test-rds-secret
    GenerateSecretString:
      SecretStringTemplate: '{"username": "dbuser"}'
      GenerateStringKey: 'password'
      PasswordLength: 32
      ExcludeCharacters: '"@/\'

2. EKSクラスターの作成

eksctlコマンドを使用してEKSクラスターを作成します。Auto Modeで作成しています。

# EKSクラスター作成
eksctl create cluster -f infrastructure/eksctl/create-cluster-nodegroup.yaml
EKS Auto Mode設定(eksctl)
# EKS Auto Mode クラスター設定
apiVersion: eksctl.io/v1alpha5
kind: ClusterConfig

metadata:
  name: test-usw2-eks-cluster
  region: us-west-2
  version: "1.31"

# Auto Mode設定
accessConfig:
  bootstrapClusterCreatorAdminPermissions: true
  authenticationMode: API_AND_CONFIG_MAP

computeConfig:
  enabled: true  # Auto Modeを有効化
  nodeRoleArn: "arn:aws:iam::aws:role/eks-node-group-role"

storageConfig:
  blockStorage:
    enabled: true
  fileSystemStorage:
    enabled: true

3. External Secrets Operatorのインストール

Helmを使用してExternal Secrets Operatorをインストールし、AWS Secrets ManagerにアクセスするためのIAMロールを作成します。

Auto Modeでは、OIDCプロバイダーがデフォルトで作成されています。

# External Secrets Operatorをインストール
helm repo add external-secrets https://charts.external-secrets.io
helm install external-secrets external-secrets/external-secrets -n external-secrets --create-namespace

# IAMロール作成(External Secrets Operator用)
eksctl create iamserviceaccount \
  --cluster=test-usw2-eks-cluster \
  --namespace=external-secrets \
  --name=external-secrets-sa \
  --attach-policy-arn=arn:aws:iam::aws:policy/SecretsManagerReadWrite \
  --override-existing-serviceaccounts \
  --region us-west-2 \
  --approve

環境変数パターンの実装

ここからはパターン別に進めます。

環境変数パターンでは、シークレットを環境変数として注入する方式を採用しています。まずSecretStoreとExternalSecretを作成し、その後アプリケーションをデプロイします。

4. SecretStoreとExternalSecretの作成

External Secrets Operator が AWS Secrets Manager からシークレットを取得するための設定を適用します。

kubectl apply -f env-vars-pattern/infrastructure/manifests/external-secrets.yml
External Secrets マニフェスト(環境変数パターン)
# SecretStore設定
apiVersion: external-secrets.io/v1
kind: SecretStore
metadata:
  name: aws-secrets-manager
  namespace: external-secrets
spec:
  provider:
    aws:
      service: SecretsManager
      region: us-west-2
      auth:
        jwt:
          serviceAccountRef:
            name: external-secrets-sa
---
# ExternalSecret設定
apiVersion: external-secrets.io/v1
kind: ExternalSecret
metadata:
  name: rds-external-secret
  namespace: external-secrets
spec:
  refreshInterval: 5m
  secretStoreRef:
    name: aws-secrets-manager
    kind: SecretStore
  target:
    name: rds-secret
    creationPolicy: Owner
  data:
  - secretKey: username
    remoteRef:
      key: test-rds-secret
      property: username
  - secretKey: password
    remoteRef:
      key: test-rds-secret
      property: password

5. アプリケーションのデプロイ

DockerイメージをビルドしてECRにプッシュし、Kubernetesマニフェストをデプロイします。

# ECRにDockerイメージをプッシュ
aws ecr get-login-password --region us-west-2 | docker login --username AWS --password-stdin <ACCOUNT-ID>.dkr.ecr.us-west-2.amazonaws.com

# Dockerイメージのビルドとプッシュ
docker build -t test-ecr env-vars-pattern/app/
docker tag test-ecr:latest <ACCOUNT-ID>.dkr.ecr.us-west-2.amazonaws.com/test-ecr:latest
docker push <ACCOUNT-ID>.dkr.ecr.us-west-2.amazonaws.com/test-ecr:latest

# Kubernetesマニフェストをデプロイ
kubectl apply -f env-vars-pattern/infrastructure/manifests/manifest.yml
アプリケーションでの環境変数利用
# Deployment設定(環境変数パターン)
spec:
  template:
    spec:
      containers:
      - name: streamlit-app
        env:
        - name: DB_HOST
          value: "test-postgres.cx644isqscfp.us-west-2.rds.amazonaws.com"
        - name: DB_NAME
          value: "postgres"
        - name: DB_USER
          valueFrom:
            secretKeyRef:
              name: rds-secret
              key: username
        - name: DB_PASSWORD
          valueFrom:
            secretKeyRef:
              name: rds-secret
              key: password

ファイルマウントパターンの実装

続いて、ファイルマウントパターンでは、シークレットをファイルとしてコンテナ内にマウントする方式を採用しています。セキュリティ面でより優れた方法ですが、アプリケーション側でファイルを読み込む実装が必要になります。

4. SecretStoreとExternalSecretの作成

ファイルマウント用の設定を適用します。

kubectl apply -f file-mount-pattern/infrastructure/manifests/external-secrets.yml
External Secrets マニフェスト(ファイルマウントパターン)
# SecretStore設定(ファイルマウントパターンも同じ設定)
apiVersion: external-secrets.io/v1
kind: SecretStore
metadata:
  name: aws-secrets-manager
  namespace: external-secrets
spec:
  provider:
    aws:
      service: SecretsManager
      region: us-west-2
      auth:
        jwt:
          serviceAccountRef:
            name: external-secrets-sa
---
# ExternalSecret設定(ファイルマウントパターンも同じ設定)
apiVersion: external-secrets.io/v1
kind: ExternalSecret
metadata:
  name: rds-external-secret
  namespace: external-secrets
spec:
  refreshInterval: 5m
  secretStoreRef:
    name: aws-secrets-manager
    kind: SecretStore
  target:
    name: rds-secret
    creationPolicy: Owner
  data:
  - secretKey: username
    remoteRef:
      key: test-rds-secret
      property: username
  - secretKey: password
    remoteRef:
      key: test-rds-secret
      property: password

5. アプリケーションのデプロイ

ファイルマウントパターン用のアプリケーションをデプロイします。

# ECRにDockerイメージをプッシュ
aws ecr get-login-password --region us-west-2 | docker login --username AWS --password-stdin <ACCOUNT-ID>.dkr.ecr.us-west-2.amazonaws.com

# Dockerイメージのビルドとプッシュ
docker build -t test-ecr file-mount-pattern/app/
docker tag test-ecr:latest <ACCOUNT-ID>.dkr.ecr.us-west-2.amazonaws.com/test-ecr:latest
docker push <ACCOUNT-ID>.dkr.ecr.us-west-2.amazonaws.com/test-ecr:latest

# Kubernetesマニフェストをデプロイ
kubectl apply -f file-mount-pattern/infrastructure/manifests/manifest.yml
ファイルマウントパターンの設定
# Deployment設定(ファイルマウントパターン)
spec:
  template:
    spec:
      containers:
      - name: streamlit-app
        env:
        - name: DB_HOST
          value: "test-postgres.cx644isqscfp.us-west-2.rds.amazonaws.com"
        - name: DB_NAME
          value: "postgres"
        volumeMounts:
        - name: db-secrets
          mountPath: "/etc/secrets"
          readOnly: true
      volumes:
      - name: db-secrets
        secret:
          secretName: rds-secret

動作確認

システムが正常に動作しているかを確認するため、チェックを行います。

External Secrets Operatorの動作確認

まず、External Secrets Operatorが正常にAWS Secrets Managerからシークレットを取得し、Kubernetes Secretを作成できているかを確認します。

ここで、トラブルが起きましたが、トラブルが起きましたが、下で解説しています。

# External Secrets Operatorが作成したSecretを確認
kubectl get secret rds-secret -n external-secrets -o yaml

# ExternalSecretの状態確認
kubectl get externalsecret -n external-secrets
kubectl describe externalsecret rds-external-secret -n external-secrets

# アプリケーションの状態確認
kubectl get pods -n external-secrets
kubectl logs -f deployment/streamlit-app -n external-secrets

システムの接続の確認

システム全体が正常に動作していることを確認するため、各コンポーネントの状態をチェックします。

  • ALBのターゲットグループでPodが正常に登録されている
  • ターゲットのヘルスチェックが成功している

アプリケーション画面の確認

デプロイが完了すると、StreamlitアプリケーションがALB経由でアクセス可能になります。

image.png

ALBのDNS名からアクセスして、以下の機能を確認できます:

  • データベースへの接続状況
  • External Secrets Operatorによって取得されたシークレットの表示
  • メッセージの投稿・表示機能

このデモアプリケーションは、デモンストレーション目的でRDSの接続情報やシークレットの内容を画面上に表示します。本番環境では機密情報を表示しないよう実装してください。

開発で遭遇した課題と解決方法

開発中に遭遇した主要な課題とその解決方法について説明します。

External Secrets OperatorのSecretSyncedErrorエラー

開発中に発生した問題の一つが、External Secrets OperatorでSecretSyncedErrorステータスが表示されるエラーでした。

# 以下のようなエラーが発生する場合
kubectl get externalsecret -n external-secrets
NAME                  STORETYPE     STORE                 REFRESH INTERVAL   STATUS              READY
rds-external-secret   SecretStore   aws-secrets-manager   5m                 SecretSyncedError   False

SecretSyncedErrorは、External Secrets OperatorがAWS Secrets Managerからシークレットを取得できない、またはKubernetes Secretを作成できないことを示しています。詳細なエラー内容を確認するためには、以下のコマンドで詳細情報を取得できます。

# 詳細なエラー情報を確認
kubectl describe externalsecret rds-external-secret -n external-secrets

# External Secrets Operatorのログを確認
kubectl logs -l app.kubernetes.io/name=external-secrets -n external-secrets

この問題の原因は、HelmでインストールしたExternal Secrets Operatorのバージョンと、適用したexternal-secrets.ymlマニフェストのAPIバージョンが異なっていたことでした。インストールしたExternal Secrets Operatorは最新版でv1 APIをサポートしていましたが、マニフェストでは古いv1beta1を使用していたため、互換性の問題が発生しました。解決方法として、external-secrets.ymlのAPIバージョンをインストールしたバージョンに合わせて更新する必要がありました。

# 修正前(v1beta1)
apiVersion: external-secrets.io/v1beta1
spec:

# 修正後(v1)
apiVersion: external-secrets.io/v1
spec:

パターン比較

2つのパターンにはそれぞれ特徴があり、用途に応じて適切に選択する必要があります。

項目 環境変数パターン ファイルマウントパターン
実装の簡単さ ✅ シンプル ❌ 少し複雑
kubectl操作での露出 ❌ 見える ✅ 見えない
推奨環境 デモ・開発 本番
シークレット利用方法 valueFrom secretKeyRef volumeMount + ファイル読み込み

環境変数パターンは実装がシンプルで、開発やデモ環境での利用に適しています。一方、ファイルマウントパターンは実装が少し複雑になりますが、セキュリティ面で優れており、本番環境での利用に推奨されます。要件とセキュリティレベルに応じて、適切なパターンを選択してください。

まとめ

External Secrets Operatorを使用してAWS Secrets ManagerとKubernetesを連携させる2つのアプローチを実装しました。従来の手動でのシークレット管理から脱却し、自動化されたセキュアなシークレット管理システムを構築することで、運用負荷の軽減とセキュリティの向上を実現できました。

External Secrets Operatorは、Kubernetesでのシークレット管理を大幅に改善するツールです。このデモの実装例が、同様のシステムを構築する際の参考になれば幸いです。

1
1
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
1
1

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?