Closed7

secrets managerを使ってみる

not75743not75743

これ
https://aws.amazon.com/jp/secrets-manager/

概念
https://docs.aws.amazon.com/ja_jp/secretsmanager/latest/userguide/getting-started.html

blackbelt
ベストプラクティス、料金などはこちらを参照
https://pages.awscloud.com/rs/112-TZM-766/images/AWS-Black-Belt_2023_AWS-Secrets-Manager_0901_v1.pdf

parameter storeとの使い分け
https://aws.amazon.com/jp/systems-manager/faq/

Q: Secrets Manager と Parameter Store の違いは何ですか?
AWS シークレットマネージャーは、ローテーション、監査、アクセスコントロールと言った組織でのシークレットのライフサイクルを中央で管理するためのサービスです。Secrets Manager を使うと、シークレットを自動的にローテーションできるようになるので、セキュリティとコンプライアンスの要件を満たすのに役立ちます。シークレットマネージャーは MySQL、PostgreSQL、Amazon Aurora on Amazon RDS への統合を組み込むことができ、これは Lambda 関数のカスタマイズで他のタイプのシークレットにも拡張できます。
AWS Systems Manager Parameter Store には、設定データ管理のためのセキュアで、階層的なストレージがあり、これにはシークレットも含みます。データベース接続タイプ、文字れる、パスワードとライセンスコードはパラメータ値として保存され、監査とアクセスコントロールが可能です。保存された値はプレーンテキストでも暗号化されたデータでも構いません。値はパラメータ固有の名前で参照できます。システムマネージャーパラメータを参照してジェネリック設定と自動化スクリプトを構築して、Amazon ECS や AWS CloudFormation など様々な AWS サービスにわたって使用できます。

Q: Parameter Store と Secrets Manager のどちらを使えば良いですか?
設定とシークレットにひとつのストアが欲しい場合、パラメータストアをお使いください。ライフサイクル管理を備えたシークレット専用のストアが欲しい場合、シークレットマネージャーをお使いください。パラメータストアは追加料金なしで、パラメータ数 10,000 個の制限でお使いいただけます。詳細については、Secrets Manager の料金ページを参照してください。

Q: Parameter Store と Secrets Manager のセキュリティモデルには違いはありますか?
ありません。シークレットマネージャーとパラメータストアは両方とも同じように安全です。これらのサービスは両方ともカスタマーの所有する KMS キーを用いて保管中の暗号化をサポートしています。Parameter Store でどのように KMS を使用するかの詳細については、KMS デベロッパーガイドの Parameter Store での AWS KMS の使用方法を参照してください。

Q: Secrets Manager を Parameter Store と共に使えますか?
はい。Secrets Manager のシークレットを Parameter Store で参照できます。

not75743not75743

cliで試す

シークレット作成

$ aws secretsmanager create-secret \
	--name test-secret-1 \
	--secret-string "secret-one"

$ aws secretsmanager create-secret \
	--name test-secret-2 \
	--secret-string '{"key1":"value1","key2":"value2"}'

シークレット取得

$ aws secretsmanager get-secret-value \
	--secret-id test-secret-1 | jq ".SecretString"
"secret-one"

$ aws secretsmanager get-secret-value \
	--secret-id test-secret-2 | jq ".SecretString"
"{\"key1\":\"value1\",\"key2\":\"value2\"}"

シークレット一覧

$ aws secretsmanager list-secrets
{
    "SecretList": [
        {
            "ARN": "arn:aws:secretsmanager:ap-northeast-1:xxxxxxxxxxxx:secret:test-secret-1-xxxxxx",
            "Name": "test-secret-1",
            "LastChangedDate": "2023-12-31T09:52:06.041000+09:00",
            "LastAccessedDate": "2023-12-31T09:00:00+09:00",
            "SecretVersionsToStages": {
                "xxxx": [
                    "AWSCURRENT"
                ]
            },
            "CreatedDate": "2023-12-31T09:52:05.874000+09:00"
        },
// 略

シークレット更新

$ aws secretsmanager update-secret \
	--secret-id test-secret-1 \
	--secret-string "secret-one-update"

シークレット削除

$ aws secretsmanager delete-secret \
	--secret-id test-secret-1
not75743not75743

Lambdaからシークレットを取得する

理解のためLambda統合は利用しない

適当なjsonをシークレットにする

$ cat secret.json 
{
    "username": "testuser1",
    "password": "password"
}

$ aws secretsmanager create-secret \
> --name lambda-secret \
> --secret-string file://secret.json

terraform

Lambdaからシークレットを取得するtf
data "aws_secretsmanager_secret" "main" {
  name = "lambda-secret"
}

### IAMロール
resource "aws_iam_role" "main" {
  assume_role_policy = jsonencode({
    Version = "2012-10-17"
    Statement = {
      Effect = "Allow"
      Action = "sts:AssumeRole"
      Principal = {
        Service = "lambda.amazonaws.com"
      }
    }
  })
}

resource "aws_iam_policy" "main" {
  policy = jsonencode({
    Version = "2012-10-17"
    Statement = [
      {
        Effect = "Allow"
        Action = [
          "logs:CreateLogGroup",
          "logs:CreateLogStream",
          "logs:PutLogEvents"
        ]
        Resource = [
          aws_cloudwatch_log_group.main.arn,
          "${aws_cloudwatch_log_group.main.arn}:*"
        ]
      },
      {
        Effect = "Allow"
        Action = [
          "secretsmanager:GetSecretValue"
        ],
        Resource = [
          data.aws_secretsmanager_secret.main.arn
        ]
      }
    ]
  })
}

resource "aws_iam_role_policy_attachment" "main" {
  role       = aws_iam_role.main.name
  policy_arn = aws_iam_policy.main.arn
}

### cloudwatch logs
resource "aws_cloudwatch_log_group" "main" {
  name              = "/aws/lambda/${aws_lambda_function.main.function_name}"
  retention_in_days = 30
}

### Lambda
data "archive_file" "main" {
  type        = "zip"
  source_dir  = "${path.root}/lambda_function"
  output_path = "${path.root}/lambda_function/src.zip"
}

resource "aws_lambda_function" "main" {
  function_name    = "get-secretsmanager"
  handler          = "lambda_function.lambda_handler"
  runtime          = "python3.10"
  filename         = data.archive_file.main.output_path
  source_code_hash = filebase64sha256(data.archive_file.main.output_path)
  role = aws_iam_role.main.arn
}

Lambda関数

lambda_function.py
import json

import boto3
from botocore.exceptions import ClientError


def lambda_handler(event, context):

    secret_name = "lambda-secret"
    region_name = "ap-northeast-1"

    session = boto3.session.Session()
    client = session.client(
        service_name='secretsmanager',
        region_name=region_name
    )

    try:
        get_secret_value_response = client.get_secret_value(
            SecretId=secret_name
        )
        secret = get_secret_value_response['SecretString']
        secret_dict = json.loads(secret)
        print(secret_dict)
        print(secret_dict.get("username"))
        print(secret_dict.get("password"))
        return {
        'statusCode': 200,
        'body': json.dumps('Secret retrieved successfully!')
        }
    except ClientError as e:
        raise e
not75743not75743

ポイント

  • secretsmanagerの受け取り
    • 既存のデータはdata.aws_secretsmanager_secret.main.arnで取得
  • IAMポリシーはこんな感じ
        {
            "Action": [
                "secretsmanager:GetSecretValue"
            ],
            "Effect": "Allow",
            "Resource": [
                "arn:aws:secretsmanager:ap-northeast-1:xxxxxxxx:secret:lambda-secret-xxxxxx"
            ]
        }

権限が誤っていると

get-secretsmanager is not authorized to perform: secretsmanager:GetSecretValue on resource: lambda-secret because no identity-based policy allows the secretsmanager:GetSecretValue action

で引っかかる

not75743not75743

同名のシークレットを作成しようとする

とこのようにひっかかるパターンがある

$ aws secretsmanager create-secret --name lambda-secret --secret-string file://secret.json

An error occurred (InvalidRequestException) when calling the CreateSecret operation: You can't create this secret because a secret with this name is already scheduled for deletion.

secretの削除には復旧期間があるらしいので考慮する必要があるみたいです
https://dev.classmethod.jp/articles/secrets-manager-error-recovery-window/

delete時に--force-delete-without-recoveryを指定すればよし

このスクラップは2023/12/31にクローズされました