Secrets Manager への値の格納と取得

チュートリアルに書いてある内容をためしてみる。CLI からまずはシークレットの作成を行う

$ aws secretsmanager create-secret --name tutorials/MyFirstSecret --description "Basic Create Secret" --secret-string S3@tt13R0cks

続いて格納したシークレットのメタデータ、およびシークレットそのものを取得する

$ aws secretsmanager describe-secret --secret-id tutorials/MyFirstSecret
{
    "ARN": "...",
    "Name": "tutorials/MyFirstSecret",
    "Description": "Basic Create Secret",
    "LastChangedDate": ...,
    "LastAccessedDate": ...,
    "VersionIdsToStages": {
        "...": [
            "AWSCURRENT"
        ]
    }
}

$ aws secretsmanager get-secret-value --secret-id tutorials/MyFirstSecret --version-stage AWSCURRENT
{
    "ARN": "...",
    "Name": "tutorials/MyFirstSecret",
    "VersionId": "...",
    "SecretString": "S3@tt13R0cks",
    "VersionStages": [
        "AWSCURRENT"
    ],
    "CreatedDate": ...
}

Secrets Manager に格納した値を Lambda から取得する

Lambda 関数の実装を以下のように行う

# -*- coding: utf-8 -*-
import os
import json
import boto3

SecretId = os.environ["SecretId"]
secrets = boto3.client(service_name='secretsmanager')


def lambda_handler(event, _):
    res = secrets.get_secret_value(SecretId=SecretId)

    # 注: 動作確認のため出力しているが、
    # CWLogs に記録されるので実際のプロダクトでは絶対にこのようなコードは書かない
    print(res)
    return json.loads(res['SecretString'])

SAM テンプレートは以下のような感じ

AWSTemplateFormatVersion: '2010-09-09'
Transform: AWS::Serverless-2016-10-31

Globals:
  Function:
    Timeout: 10
    Runtime: python3.8
    Environment:
      Variables:
        SecretId: !Ref TestSecret
Resources:
  TestSecret:
    Type: AWS::SecretsManager::Secret
    Properties:
      Description: 'Secrets Test'
      GenerateSecretString:
        SecretStringTemplate: '{"username": "admin"}'
        GenerateStringKey: 'password'
        PasswordLength: 16
        ExcludeCharacters: '"@/\'
  WorkerFunction:
    Type: AWS::Serverless::Function
    Properties:
      CodeUri: worker/
      Handler: app.lambda_handler
      Policies:
        - AWSSecretsManagerGetSecretValuePolicy:
            SecretArn: !Ref TestSecret
  WorkerFunctionLogGroup:
    Type: AWS::Logs::LogGroup
    Properties:
      LogGroupName: !Sub /aws/lambda/${WorkerFunction}
      RetentionInDays: 1

CDK で Secret を管理する

TypeScript で Lambda を次のように実装

const AWS = require('aws-sdk')

const secretsmanager = new AWS.SecretsManager({apiVersion: '2017-10-17'})
const env = process.env

const handler = async function (event: any) {
  const { SecretString } = await secretsmanager.getSecretValue({ SecretId: env.SecretId }).promise()

  # 注: 動作確認のため出力しているが、
  # CWLogs に記録されるので実際のプロダクトでは絶対にこのようなコードは書かない
  console.log(SecretString)
  return {}
};

export { handler };

CDK は次のような具合

import * as lambda from "@aws-cdk/aws-lambda";
import * as logs from "@aws-cdk/aws-logs";
import * as secretsmanager from "@aws-cdk/aws-secretsmanager";
import * as cdk from "@aws-cdk/core";

export class TsLambdaStack extends cdk.Stack {
  constructor(scope: cdk.App, id: string, props?: cdk.StackProps) {
    super(scope, id, props);
    const secret = new secretsmanager.Secret(this, 'Secret', {
      generateSecretString: {
        secretStringTemplate: JSON.stringify({ username: 'user' }),
        generateStringKey: 'password',
      },
    });

    const helloFunction = new lambda.Function(this, "HelloFunction", {
      runtime: lambda.Runtime.NODEJS_10_X,
      code: lambda.Code.fromAsset("lambda"),
      handler: "hello.handler",
      environment: {
        SecretId: secret.secretFullArn!
      }
    });
    secret.grantRead(helloFunction)

    const _ = new logs.LogGroup(this, "HelloFunctionLogGroup", {
      logGroupName: "/aws/lambda/" + helloFunction.functionName,
      retention: logs.RetentionDays.ONE_DAY,
    });


  }
}

SAM テンプレートから Secret を取得してみる

以下のようにして Secrets Manager の SecureString の取得が可能

Parameters:
  Test:
    Type: String
    Default: '{{resolve:secretsmanager:test:SecretString:test}}'

番外編: Parameter Store を使ってみる

  • Systems Manager に Parameter Store という機能があります
  • String, StringList, Secure-String の 3 つの値を CloudFormation テンプレートから参照できます

String 値の取得

Parameters:
  FuncName:
    Type: String
    Default: '{{resolve:ssm:FunctionName:2}}'

Resources:
  WorkerFunction:
    Type: AWS::Serverless::Function
    Properties:
      FunctionName: !Ref FuncName
      CodeUri: worker/
      Handler: app.lambda_handler

Secure-String 値の取得

以下のような形式で取得できるが、リストにあるリソース-パラメータにしか使えない

'{{resolve:ssm-secure:Himitsu:}}'
Copyright © 53ningen.com