Secrets Managerを使用して、ランダムなパスワードを生成する

Secrets Managerを使用して、ランダムなパスワードを生成する

Secrets Managerを使用して、ランダムなパスワードを生成する

Secrets Managerを使用すると、ランダムなパスワードを生成することができます。

https://docs.aws.amazon.com/ja_jp/secretsmanager/latest/userguide/cfn-example_secret.html

本ページでは、上記のページを参考にして、ランダムパスワードを生成します。
また生成したパスワード情報に、AWS CLIおよびLambda関数からアクセスします。

構築する環境

Diagram of using Secrets Manager to generate random password

Secrets Managerにシークレットを作成します。

今回はシークレット作成時に、自動的にパスワードを生成します。

生成したパスワードをAWS CLIおよびLambda関数から取得します。
Lambda関数のランタイム環境はPython3.8とします。

CloudFormationテンプレートファイル

上記の構成をCloudFormationで構築します。
以下のURLにCloudFormationテンプレートを配置しています。

https://github.com/awstut-an-r/awstut-fa/tree/main/126

テンプレートファイルのポイント解説

Secrets Manager

Resources:
  Secret:
    Type: AWS::SecretsManager::Secret
    Properties:
      Description: test secret
      GenerateSecretString:
        ExcludeCharacters: ""
        ExcludeLowercase: false
        ExcludeNumbers: false
        ExcludePunctuation: false
        ExcludeUppercase: false
        GenerateStringKey: !Ref PasswordKey
        IncludeSpace: false
        PasswordLength: !Ref PasswordLength
        RequireEachIncludedType: true
        SecretStringTemplate: !Sub '{"${PasswordKey}": "hogehoge"}'
      KmsKeyId: alias/aws/secretsmanager
      Name: !Ref Prefix
Code language: YAML (yaml)

GenerateSecretStringプロパティで、生成するパスワードに関する設定を行います。
今回は以下の条件でパスワードを設定します。

  • 大文字・小文字・数字・記号(スペース除く)を含む。
  • パスワードの長さは64文字とする。
  • 「{“password”: “[password]”}」の形式で出力する。

パスワードの形式ですが、GenerateStringKeyおよびSecretStringTemplateプロパティで設定します。
前者がJSONのキーを指定するものですから、後者の該当箇所に統一的に「password」を指定します。
なおJSONの値に関する箇所(「hogehoge」)については、後ほど生成されるパスワード文字列に置き換えられます。

Lambda関数

Resources:
  Function:
    Type: AWS::Lambda::Function
    Properties:
      Architectures:
        - !Ref Architecture
      Environment:
        Variables:
          SECRET_ARN: !Ref Secret
      Code:
        ZipFile: |
          import boto3
          import json
          import os

          secret_arn = os.environ['SECRET_ARN']
          client = boto3.client('secretsmanager')

          def lambda_handler(event, context):
            response = client.get_secret_value(
              SecretId=secret_arn
            )
            secret_dict = json.loads(response['SecretString'])
            return secret_dict['password']
      FunctionName: !Sub "${Prefix}-function"
      Handler: !Ref Handler
      Runtime: !Ref Runtime
      Role: !GetAtt FunctionRole.Arn
Code language: YAML (yaml)

Lambda関数で実行するコードをインライン形式で記載します。
詳細につきましては、以下のページをご確認ください。

https://awstut.com/2022/02/02/3-patterns-for-creating-lambda-with-cloudformation

コードの内容ですが、boto3でSecrets Manager用のクライアントオブジェクトを作成後、get_secret_valueメソッドを実行して、シークレット文字列を取得します。

今回はJSON形式でパスワード情報を保存していますので、json.loadsで辞書型に変換した上で、パスワードにアクセスします。

以下が本関数用のIAMロールです。

Resources:
  FunctionRole:
    Type: AWS::IAM::Role
    DeletionPolicy: Delete
    Properties:
      AssumeRolePolicyDocument:
        Version: 2012-10-17
        Statement:
          - Effect: Allow
            Action: sts:AssumeRole
            Principal:
              Service:
                - lambda.amazonaws.com
      ManagedPolicyArns:
        - arn:aws:iam::aws:policy/service-role/AWSLambdaBasicExecutionRole
      Policies:
        - PolicyName: GetSecretValuePolicy
          PolicyDocument:
            Version: 2012-10-17
            Statement:
              - Effect: Allow
                Action:
                  - secretsmanager:GetSecretValue
                Resource:
                  - !Ref Secret
Code language: YAML (yaml)

Secrets Managerに保存されているシークレット情報を取得するための権限を付与します。

環境構築

CloudFormationを使用して、本環境を構築し、実際の挙動を確認します。

CloudFormationスタックを作成し、スタック内のリソースを確認する

CloudFormationスタックを作成します。
スタックの作成および各スタックの確認方法については、以下のページをご確認ください。

https://awstut.com/2021/12/02/cloudformation-nested-stacks

各スタックのリソースを確認した結果、今回作成された主要リソースの情報は以下の通りです。

  • シークレット名:fa-126
  • Lambda関数:fa-126-function

AWSマネージメントコンソールから各種リソースを確認します。

Secrets Managerを確認します。

Detail of Secrets Manager 01.

確かにシークレットが作成されています。
シークレットキー名が「password」、シークレットの値がランダムに生成された文字列です。

このようにSecrets Managerを使用すると、ランダムパスワードを生成することができます。

Lambda関数を確認します。

Detail of Lambda 01.

こちらも正常に作成されています。

動作確認

AWS CLIからSecrets Managerにアクセス

準備が整いましたので、AWS CLIからSecrets Managerに保存されているシークレット情報を取得します。

$ aws secretsmanager get-secret-value --secret-id fa-126
{
    "ARN": "arn:aws:secretsmanager:ap-northeast-1:[account-id]:secret:fa-126-b9sPdb",
    "Name": "fa-126",
    "VersionId": "02433ea8-08cd-412e-8717-26bb08eb8f64",
    "SecretString": "{\"password\":\"q8BP.(PO{X2F7D)b&w~@k{\\\"!dAQ8FYsV>iSZR7vaEjz>3r=/CtD5=A+3d_P{0NZ:\"}",
    "VersionStages": [
        "AWSCURRENT"
    ],
    "CreatedDate": "2023-04-01T07:43:25.603000+00:00"
}
Code language: Bash (bash)

確かにAWS CLIからシークレット情報にアクセスすることができました。

Lambda関数からSecrets Managerにアクセス

Lambda関数を実行して、Secrets Managerに保存されているシークレット情報を取得します。
以下が実行結果です。

Detail of Lambda 02.

パスワード文字列が返ってきました。

このように、AWS CLIやLambda関数からSecrets Managerにアクセスし、シークレット情報を取得することができます。

まとめ

Secrets Managerを使用して、ランダムパスワードを生成しました。
また生成したパスワード情報に、AWS CLIおよびLambda関数からアクセスしました。