secrets managerを使ってみる
これ
概念
blackbelt
ベストプラクティス、料金などはこちらを参照
parameter storeとの使い分け
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 で参照できます。
特徴
- シークレット情報(パスワード等)を安全に管理
- 別リージョンへ自動レプリケーション
- プログラムを書き換えずに手動・自動ローテーションが可能
- IAMでのアクセス制御
- マネージドなサービス統合によりSecretsManagerに容易にアクセス
図
blackbelt12ページより引用
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
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関数
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
ポイント
- 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
で引っかかる
同名のシークレットを作成しようとする
とこのようにひっかかるパターンがある
$ 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の削除には復旧期間があるらしいので考慮する必要があるみたいです
delete時に--force-delete-without-recovery
を指定すればよし