Secrets Manager / SSM / IRSA:秘密管理做對了嗎?

你的 DB 密碼放在哪裡?環境變數?.env 檔?git repo 裡?如果答案是後兩個,你的系統已經有資安破口了。

先講結論

Secrets Manager 適合存高價值秘密(DB 密碼、API key),支援自動 rotation。SSM Parameter Store 適合存一般設定(feature flag、endpoint URL),免費額度大。IRSA(IAM Roles for Service Accounts)讓 EKS 的 Pod 用 IAM Role 而不是 Access Key 存取 AWS 服務。三個搭起來,你的秘密管理就安全了。


Secrets Manager:高價值秘密的家

什麼該放 Secrets Manager

  • DB 密碼
  • 第三方 API key(Stripe、SendGrid)
  • OAuth client secret
  • TLS 私鑰
# 建立 Secret
aws secretsmanager create-secret \
  --name prod/database/postgres \
  --description "Production PostgreSQL credentials" \
  --secret-string '{"username":"dbadmin","password":"SuperSecretPass123!","host":"prod-postgres.xxx.ap-northeast-1.rds.amazonaws.com","port":5432,"dbname":"appdb"}'
 
# 讀取 Secret
aws secretsmanager get-secret-value --secret-id prod/database/postgres \
  --query SecretString --output text | jq .
 
# 更新 Secret
aws secretsmanager update-secret --secret-id prod/database/postgres \
  --secret-string '{"username":"dbadmin","password":"NewPassword456!"}'

自動 Rotation

Secrets Manager 的殺手功能是自動 rotation——定期幫你換密碼,不用人工介入:

# 設定 RDS 密碼自動 rotation(每 30 天)
aws secretsmanager rotate-secret \
  --secret-id prod/database/postgres \
  --rotation-lambda-arn arn:aws:lambda:ap-northeast-1:123456789012:function:SecretsManagerRDSPostgreSQLRotation \
  --rotation-rules AutomaticallyAfterDays=30

AWS 提供了 RDS rotation 的 Lambda template,幾乎不用自己寫 code。

在 ECS 裡使用 Secrets Manager

{
  "containerDefinitions": [{
    "name": "app",
    "image": "123456789012.dkr.ecr.ap-northeast-1.amazonaws.com/web-app:1.0.0",
    "secrets": [
      {
        "name": "DB_PASSWORD",
        "valueFrom": "arn:aws:secretsmanager:ap-northeast-1:123456789012:secret:prod/database/postgres:password::"
      },
      {
        "name": "STRIPE_KEY",
        "valueFrom": "arn:aws:secretsmanager:ap-northeast-1:123456789012:secret:prod/stripe-api-key"
      }
    ]
  }]
}

ECS 在啟動 Task 的時候會自動從 Secrets Manager 拉 secret 注入環境變數。你的 code 只要讀 process.env.DB_PASSWORD 就好。


SSM Parameter Store:一般設定的家

Secrets Manager vs SSM Parameter Store

Secrets ManagerSSM Parameter Store
費用$0.40/secret/月 + API call 費免費(Standard tier)
自動 Rotation內建要自己寫
版本管理
加密KMS 加密可選 KMS
跨帳號存取支援支援
適合密碼、API keyFeature flag、config、endpoint URL
# 存一般設定(String)
aws ssm put-parameter \
  --name /prod/app/feature-flags/dark-mode \
  --type String \
  --value "enabled"
 
# 存機敏設定(SecureString,用 KMS 加密)
aws ssm put-parameter \
  --name /prod/app/smtp-password \
  --type SecureString \
  --value "SmtpPass123!"
 
# 讀取
aws ssm get-parameter --name /prod/app/feature-flags/dark-mode --query Parameter.Value --output text
 
# 讀取加密的(要加 --with-decryption)
aws ssm get-parameter --name /prod/app/smtp-password --with-decryption --query Parameter.Value --output text
 
# 批次讀取某個路徑下的所有參數
aws ssm get-parameters-by-path --path /prod/app/ --recursive --with-decryption

在 ECS 裡使用 SSM

{
  "containerDefinitions": [{
    "name": "app",
    "secrets": [
      {
        "name": "FEATURE_DARK_MODE",
        "valueFrom": "arn:aws:ssm:ap-northeast-1:123456789012:parameter/prod/app/feature-flags/dark-mode"
      }
    ]
  }]
}

IRSA:讓 EKS Pod 用 IAM Role

傳統做法:把 AWS Access Key 放在環境變數裡。問題是 key 會洩漏、不好 rotate、所有 Pod 共用同一個 key。

IRSA(IAM Roles for Service Accounts)讓每個 K8s ServiceAccount 綁定一個 IAM Role,Pod 透過 ServiceAccount 自動拿到臨時 credentials——不需要 Access Key。

設定 IRSA

# 1. 啟用 OIDC Provider(EKS cluster 建立時自動有)
eksctl utils associate-iam-oidc-provider \
  --cluster prod-cluster --approve
 
# 2. 建立 IAM Role + K8s ServiceAccount
eksctl create iamserviceaccount \
  --cluster prod-cluster \
  --namespace default \
  --name s3-reader \
  --attach-policy-arn arn:aws:iam::aws:policy/AmazonS3ReadOnlyAccess \
  --approve
 
# 3. 在 Pod spec 裡使用這個 ServiceAccount
# deployment.yaml
apiVersion: apps/v1
kind: Deployment
metadata:
  name: my-app
spec:
  template:
    spec:
      serviceAccountName: s3-reader  # 綁定 IRSA
      containers:
        - name: app
          image: my-app:1.0.0
          # 不需要 AWS_ACCESS_KEY_ID / AWS_SECRET_ACCESS_KEY
          # SDK 會自動透過 IRSA 拿到臨時 credentials

IRSA 的好處

  1. Pod 層級權限:不同 Pod 有不同 IAM Role,不是整台 Node 共用
  2. 臨時 credentials:每 12 小時自動 rotate,不需要管理 Access Key
  3. 最小權限:S3 讀取的 Pod 就只能讀 S3,不能碰 RDS
  4. 審計:CloudTrail 能看到哪個 Pod 做了什麼 AWS API call

最佳實踐

秘密分層

/prod/
  /database/
    postgres → Secrets Manager(自動 rotation)
    redis → Secrets Manager
  /api-keys/
    stripe → Secrets Manager
    sendgrid → Secrets Manager
  /app/
    feature-flags/ → SSM Parameter Store(免費)
    endpoints/ → SSM Parameter Store
    smtp-password → SSM SecureString

不要做的事

  • 不要把 secret 放在 git repo 裡(即使是 private repo)
  • 不要把 secret 硬寫在 code 裡
  • 不要用同一個 Access Key 給所有服務
  • 不要忘記設 secret 的 rotation

自架 vs AWS

面向自架AWS
秘密管理HashiCorp VaultSecrets Manager
設定管理.env + ConsulSSM Parameter Store
自動 RotationVault + cronjob內建 Lambda rotation
Pod 權限K8s ServiceAccount + RBACIRSA(IAM + ServiceAccount)
審計Vault audit logCloudTrail
加密Vault Transit / Sealed SecretsKMS

如果你讀過 Secrets & ConfigSecrets & Certificate Management,Secrets Manager 就是 Vault 的 AWS 版——功能沒有 Vault 全面,但零維護。


K8s 映射

AWS 秘密管理K8s 對應
Secrets ManagerK8s Secret(建議用 External Secrets Operator 同步)
SSM Parameter StoreConfigMap / K8s Secret
IRSAServiceAccount + RBAC
KMSSealed Secrets(加密 Secret)
Secret rotationExternal Secrets Operator 自動同步

在 EKS 上最佳實踐:用 External Secrets Operator 把 Secrets Manager 的 secret 自動同步到 K8s Secret,Pod 直接讀 K8s Secret——這樣既有 AWS 的安全性,又保持 K8s 原生的使用方式。詳見 K8s 配置管理


系列導覽


你的系統有多安全,取決於你最弱的那個秘密怎麼管理。