𝕏 f B! L
案件・求人数 12,345
案件を探す(準備中) エージェントを探す(準備中) お役立ち情報 ログイン
案件・求人数 12,345
AWS Secrets Managerの使い方完全ガイド|シークレット管理・自動ローテーション・SES案件での実践活用法

AWS Secrets Managerの使い方完全ガイド|シークレット管理・自動ローテーション・SES案件での実践活用法

AWSSecrets Managerセキュリティシークレット管理SES
目次

「.envファイルにAPIキーをハードコードしてGitにコミットしてしまった」——SES現場で一度は聞いたことがあるインシデントではないでしょうか。AWS Secrets Managerを正しく活用すれば、このようなシークレット漏洩リスクをゼロにできます。

AWS Secrets Managerは、APIキー・データベースパスワード・OAuth トークンなどのシークレットを暗号化して一元管理し、自動ローテーション機能でセキュリティを継続的に維持するフルマネージドサービスです。この記事では、AWSシリーズ第40弾として、Secrets Managerの実践的な活用法をSES現場の視点で解説します。

この記事を3秒でまとめると

  • AWS Secrets Managerでシークレットを暗号化一元管理し、ハードコード・.env漏洩を完全防止
  • 自動ローテーションでDBパスワード・APIキーを定期更新し、漏洩時の影響範囲を最小化
  • Lambda・ECS・EKSとのシームレスな連携パターンで、SES現場のあらゆるアーキテクチャに対応

AWS Secrets Managerとは

概要と位置づけ

AWS Secrets Managerは、アプリケーションで使用する機密情報(シークレット)を安全に管理するためのサービスです。

管理できるシークレットの種類:

  • データベース認証情報(RDS, Aurora, Redshift)
  • APIキー・アクセストークン
  • OAuth 2.0 クライアントシークレット
  • SSH鍵・TLS証明書
  • 任意のキー・バリューペア

Systems Manager Parameter Store との違い

比較項目Secrets ManagerParameter Store (SecureString)
自動ローテーション✅ ネイティブ対応❌ カスタム実装が必要
料金$0.40/シークレット/月無料(Standard)/ $0.05(Advanced)
クロスアカウント共有✅ リソースポリシーで可能❌ 直接共有不可
RDS連携✅ 自動ローテーション❌ 手動
バージョン管理✅ ステージング対応✅ バージョンあり
最大サイズ64KB8KB (Standard) / 8KB (Advanced)

使い分けの判断基準:

  • 自動ローテーションが必要 → Secrets Manager
  • DB認証情報 → Secrets Manager(RDSとの統合が優秀)
  • コスト重視・設定値中心 → Parameter Store
  • クロスアカウント共有 → Secrets Manager

基本操作

シークレットの作成

AWS CLIでの作成:

# RDSデータベースの認証情報を登録
aws secretsmanager create-secret \
  --name "prod/myapp/database" \
  --description "本番環境のRDS認証情報" \
  --secret-string '{"username":"admin","password":"P@ssw0rd!2026","host":"mydb.cluster-xxxxx.ap-northeast-1.rds.amazonaws.com","port":"5432","dbname":"myapp"}' \
  --tags Key=Environment,Value=production Key=Team,Value=backend

# APIキーの登録
aws secretsmanager create-secret \
  --name "prod/myapp/stripe-api-key" \
  --description "Stripe APIキー" \
  --secret-string '{"api_key":"sk_live_xxxxx","webhook_secret":"whsec_xxxxx"}'

CloudFormationでの作成:

Resources:
  DatabaseSecret:
    Type: AWS::SecretsManager::Secret
    Properties:
      Name: prod/myapp/database
      Description: 本番環境のRDS認証情報
      GenerateSecretString:
        SecretStringTemplate: '{"username": "admin"}'
        GenerateStringKey: password
        PasswordLength: 32
        ExcludeCharacters: '"@/\'
      Tags:
        - Key: Environment
          Value: production

シークレットの取得

AWS SDK(Node.js):

import { SecretsManagerClient, GetSecretValueCommand } from '@aws-sdk/client-secrets-manager';

const client = new SecretsManagerClient({ region: 'ap-northeast-1' });

async function getSecret(secretName) {
  const command = new GetSecretValueCommand({ SecretId: secretName });
  const response = await client.send(command);
  return JSON.parse(response.SecretString);
}

// 使用例
const dbConfig = await getSecret('prod/myapp/database');
const pool = new Pool({
  host: dbConfig.host,
  port: dbConfig.port,
  user: dbConfig.username,
  password: dbConfig.password,
  database: dbConfig.dbname,
});

AWS SDK(Python):

import json
import boto3

def get_secret(secret_name: str) -> dict:
    client = boto3.client('secretsmanager', region_name='ap-northeast-1')
    response = client.get_secret_value(SecretId=secret_name)
    return json.loads(response['SecretString'])

# 使用例
db_config = get_secret('prod/myapp/database')

AWS Secrets Manager構成図

自動ローテーションの設定

RDSパスワードの自動ローテーション

Secrets Managerの最大の強みは、DBパスワードの自動ローテーションです。

# ローテーション設定(30日ごと)
aws secretsmanager rotate-secret \
  --secret-id "prod/myapp/database" \
  --rotation-lambda-arn "arn:aws:lambda:ap-northeast-1:123456789012:function:SecretsManagerRotation" \
  --rotation-rules '{"AutomaticallyAfterDays": 30}'

CloudFormationでの設定:

Resources:
  SecretRotationSchedule:
    Type: AWS::SecretsManager::RotationSchedule
    Properties:
      SecretId: !Ref DatabaseSecret
      RotateImmediatelyOnUpdate: true
      RotationLambdaARN: !GetAtt RotationFunction.Arn
      RotationRules:
        AutomaticallyAfterDays: 30

  # シークレットとRDSの紐付け
  SecretTargetAttachment:
    Type: AWS::SecretsManager::SecretTargetAttachment
    Properties:
      SecretId: !Ref DatabaseSecret
      TargetId: !Ref MyRDSInstance
      TargetType: AWS::RDS::DBInstance

ローテーション戦略の選択

Single User Rotation(シンプル):

  • 1つのDBユーザーのパスワードを更新
  • ローテーション中に一瞬だけ接続が切れる可能性
  • 小規模・開発環境向け

Alternating Users Rotation(推奨):

  • 2つのDBユーザーを交互に使用
  • ダウンタイムゼロでローテーション可能
  • 本番環境向け
# Alternating Users Rotation の設定
GenerateSecretString:
  SecretStringTemplate: !Sub '{"username": "app_user_1", "masterarn": "${MasterSecret}"}'
  GenerateStringKey: password
  PasswordLength: 32

カスタムローテーション関数

API キーなど、AWS管理外のシークレットにも自動ローテーションを設定できます。

# Lambda: カスタムローテーション関数
import boto3
import json
import requests

def lambda_handler(event, context):
    secret_id = event['SecretId']
    step = event['Step']
    token = event['ClientRequestToken']

    client = boto3.client('secretsmanager')

    if step == 'createSecret':
        # 新しいAPIキーを外部サービスから生成
        new_key = requests.post('https://api.example.com/keys/rotate').json()
        client.put_secret_value(
            SecretId=secret_id,
            ClientRequestToken=token,
            SecretString=json.dumps({'api_key': new_key['key']}),
            VersionStages=['AWSPENDING']
        )

    elif step == 'setSecret':
        # 外部サービス側で新しいキーをアクティベート
        pending = get_secret_version(client, secret_id, 'AWSPENDING')
        requests.post('https://api.example.com/keys/activate',
                      json={'key': pending['api_key']})

    elif step == 'testSecret':
        # 新しいキーの動作確認
        pending = get_secret_version(client, secret_id, 'AWSPENDING')
        response = requests.get('https://api.example.com/health',
                               headers={'Authorization': f'Bearer {pending["api_key"]}'})
        if response.status_code != 200:
            raise ValueError('新しいAPIキーの検証に失敗')

    elif step == 'finishSecret':
        # ローテーション完了
        client.update_secret_version_stage(
            SecretId=secret_id,
            VersionStage='AWSCURRENT',
            MoveToVersionId=token,
            RemoveFromVersionId=get_current_version(client, secret_id)
        )

アプリケーションとの連携パターン

パターン1: Lambda関数での利用

// Lambda + Secrets Manager
import { SecretsManagerClient, GetSecretValueCommand } from '@aws-sdk/client-secrets-manager';

// Lambda実行環境でのキャッシュ(コールドスタート対策)
let cachedSecret = null;
let cacheExpiry = 0;
const CACHE_TTL = 300000; // 5分

async function getSecretCached(secretName) {
  if (cachedSecret && Date.now() < cacheExpiry) {
    return cachedSecret;
  }

  const client = new SecretsManagerClient({});
  const response = await client.send(
    new GetSecretValueCommand({ SecretId: secretName })
  );

  cachedSecret = JSON.parse(response.SecretString);
  cacheExpiry = Date.now() + CACHE_TTL;
  return cachedSecret;
}

export const handler = async (event) => {
  const dbConfig = await getSecretCached('prod/myapp/database');
  // DB接続して処理実行
};

パターン2: ECSタスクでの利用

{
  "containerDefinitions": [
    {
      "name": "myapp",
      "image": "123456789012.dkr.ecr.ap-northeast-1.amazonaws.com/myapp:latest",
      "secrets": [
        {
          "name": "DB_HOST",
          "valueFrom": "arn:aws:secretsmanager:ap-northeast-1:123456789012:secret:prod/myapp/database:host::"
        },
        {
          "name": "DB_PASSWORD",
          "valueFrom": "arn:aws:secretsmanager:ap-northeast-1:123456789012:secret:prod/myapp/database:password::"
        },
        {
          "name": "STRIPE_API_KEY",
          "valueFrom": "arn:aws:secretsmanager:ap-northeast-1:123456789012:secret:prod/myapp/stripe-api-key:api_key::"
        }
      ]
    }
  ],
  "executionRoleArn": "arn:aws:iam::123456789012:role/ecsTaskExecutionRole"
}

パターン3: EKSでの利用(External Secrets Operator)

# ExternalSecret リソース
apiVersion: external-secrets.io/v1beta1
kind: ExternalSecret
metadata:
  name: myapp-secrets
  namespace: production
spec:
  refreshInterval: 1h
  secretStoreRef:
    name: aws-secrets-manager
    kind: ClusterSecretStore
  target:
    name: myapp-secrets
    creationPolicy: Owner
  data:
    - secretKey: DB_PASSWORD
      remoteRef:
        key: prod/myapp/database
        property: password
    - secretKey: API_KEY
      remoteRef:
        key: prod/myapp/stripe-api-key
        property: api_key

EKSガイドで、Kubernetesとの連携を詳しく解説しています。

IAMポリシーとアクセス制御

最小権限の原則に基づくポリシー設計

{
  "Version": "2012-10-17",
  "Statement": [
    {
      "Sid": "AllowReadSpecificSecrets",
      "Effect": "Allow",
      "Action": [
        "secretsmanager:GetSecretValue",
        "secretsmanager:DescribeSecret"
      ],
      "Resource": [
        "arn:aws:secretsmanager:ap-northeast-1:123456789012:secret:prod/myapp/*"
      ],
      "Condition": {
        "StringEquals": {
          "aws:RequestedRegion": "ap-northeast-1"
        }
      }
    }
  ]
}

リソースポリシーによるクロスアカウント共有

マルチアカウント構成で、本番アカウントのシークレットを他アカウントから参照できます。

{
  "Version": "2012-10-17",
  "Statement": [
    {
      "Sid": "AllowCrossAccountAccess",
      "Effect": "Allow",
      "Principal": {
        "AWS": "arn:aws:iam::987654321098:role/AppRole"
      },
      "Action": "secretsmanager:GetSecretValue",
      "Resource": "*",
      "Condition": {
        "StringEquals": {
          "secretsmanager:ResourceTag/SharedWith": "staging-account"
        }
      }
    }
  ]
}

コスト最適化

料金体系

項目料金(東京リージョン)
シークレット保管$0.40/シークレット/月
API呼び出し$0.05/10,000回
自動ローテーション追加料金なし(Lambda実行料金のみ)

コスト削減のベストプラクティス

1. キャッシュの活用 頻繁にアクセスするシークレットはアプリケーション側でキャッシュし、API呼び出し回数を削減します。

// AWS公式のキャッシュライブラリを使用
import { getSecretValue } from '@aws-sdk/client-secrets-manager';

// 5分間キャッシュ(ローテーション間隔より十分短く設定)
const CACHE_TTL_MS = 300_000;

2. 不要なシークレットの削除 使用されていないシークレットを定期的に棚卸しします。

# 90日以上アクセスされていないシークレットを検出
aws secretsmanager list-secrets \
  --query 'SecretList[?LastAccessedDate < `2025-12-21`].{Name:Name,LastAccess:LastAccessedDate}'

3. Parameter Store との使い分け シークレットではない設定値は、Parameter Store(無料枠)に保管します。

コスト最適化ガイドで、AWS全体のコスト管理を解説しています。

SES現場での実践パターン

パターン1: マルチ環境でのシークレット管理

SES案件では、開発・ステージング・本番の複数環境を管理することが一般的です。

## 命名規則
{environment}/{service}/{secret-type}

例:
- dev/user-service/database
- stg/user-service/database
- prod/user-service/database
- prod/user-service/stripe-api-key
- prod/payment-service/database
- shared/infra/github-token

パターン2: 既存プロジェクトへのSecrets Manager導入

ハードコードされたシークレットをSecrets Managerに移行するステップ:

Step 1: シークレットの洗い出し

# コードベース内のシークレット候補を検出
grep -rn "password\|api_key\|secret\|token" --include="*.js" --include="*.py" --include="*.yml" .

Step 2: Secrets Manager にシークレットを登録

Step 3: アプリケーションコードの修正

Step 4: .envファイル・設定ファイルからシークレットを削除

Step 5: CI/CDパイプラインの更新

パターン3: セキュリティ監査への対応

# CloudTrailでシークレットへのアクセスログを確認
aws cloudtrail lookup-events \
  --lookup-attributes AttributeKey=ResourceType,AttributeValue=AWS::SecretsManager::Secret \
  --max-results 50

IAMセキュリティガイドで、アクセス制御の詳細を解説しています。

まとめ:Secrets Managerでシークレット漏洩リスクをゼロにする

AWS Secrets Managerを導入することで、シークレットのハードコード・.env漏洩のリスクを完全に排除できます。

導入ステップ:

  1. 既存のハードコードされたシークレットを洗い出し、Secrets Managerに登録
  2. アプリケーションコードをSDK経由での取得に修正
  3. RDS認証情報の自動ローテーションを設定
  4. IAMポリシーで最小権限のアクセス制御を実装
  5. CloudTrailでアクセスログを監査

**シークレット管理はセキュリティの基本です。**SES案件でSecrets Managerを使いこなせるエンジニアは、セキュリティ意識の高さを評価され、信頼を得られます。

SES BASEでは、AWS・セキュリティ領域のSES案件を多数掲載しています。案件を検索するからチェックしてみてください。

SES案件をお探しですか?

SES記事をもっと読む →
🏗️

SES BASE 編集長

SES業界歴10年以上のメンバーが在籍する編集チーム。SES企業での営業・エンジニア経験、フリーランス独立経験を持つメンバーが、業界のリアルな情報をお届けします。

📊 業界データに基づく記事制作 🔍 IPA・経済産業省データ参照 💼 SES実務経験者が執筆・監修