概要
RDSのパスワードはSecretManagerから取得して登録することは可能ですが、
そもそもそのSecretManagerに登録するパスワードをCDKで作成して、
CDKでRDSを作成する際にそのパスワードを取得するようにしたい!と思いました。
実現できたので、その方法を紹介します。
前提
RDS作成(L1コンストラクト)の際にmaster_username
やmaster_user_password
を指定することは可能ですが、これだとハードコーディングで指定する必要があります。
rds_instance = rds.CfnDBInstance(
self, "sample-RDS",
db_instance_identifier="sample-RDS",
db_instance_class="db.t3.micro",
db_name="sampledb",
engine="mysql",
engine_version="8.0.39",
allocated_storage="20",
max_allocated_storage=100,
db_subnet_group_name=rds_subnet_group.ref,
vpc_security_groups=[rds_security_group.ref],
master_username="admin",
master_user_password="password",
publicly_accessible=False,
tags=[{
"key": "Name",
"value": "sample-RDS"
}]
)
直接コードで指定する方法だとセキュリティや手間の問題があるので、AWS側に発行&管理してもらおう!というのが今回の趣旨です。
サンプルコード
下記のコードで、secretsmanager
で40文字のパスワードを自動生成できます。
rds_secret = secretsmanager.Secret(
self, "sample-RDSSecret",
secret_name="sample-db-variables",
generate_secret_string=secretsmanager.SecretStringGenerator(
secret_string_template='{"username":"admin"}',
generate_string_key="password",
exclude_characters='@/\\\'" ',
password_length=40
)
)
generate_secret_string
を使用して、ユーザー名とパスワードを自動生成することができます。
secret_string_template
ではJSON形式でユーザー名を指定し、generate_string_key でパスワードを生成します。
参考:
ここで作成したパスワードをRDSに紐づける場合は、以下のようにsecret_value_from_json
を使って取得することができます。
db_name = "sampledb"
rds_instance = rds.CfnDBInstance(
self, "sample-RDS",
db_instance_identifier="sample-mysql8",
db_instance_class="db.t3.micro",
db_name=db_name,
engine="mysql",
engine_version="8.0.41",
allocated_storage="20",
max_allocated_storage=100,
db_subnet_group_name=rds_subnet_group.ref,
vpc_security_groups=[rds_security_group.security_group_id],
master_username=rds_secret.secret_value_from_json("username").unsafe_unwrap(),
master_user_password=rds_secret.secret_value_from_json("password").unsafe_unwrap(),
publicly_accessible=False,
)
secret_value_from_json(json_field)
Interpret the secret as a JSON object and return a field’s value from it as a SecretValue.
https://docs.aws.amazon.com/cdk/api/v2/python/aws_cdk.aws_secretsmanager/Secret.html
unsafe_unwrap()
を使用して、シークレットの値を文字列として取得しています。
Lambdaの環境変数にも設定できる
これは、たとえばLambdaの環境変数に当てたい場合も同様に可能です。
rds_secret.secret_value_from_json("password").unsafe_unwrap()
を使えば、上記で作成したSecretManagerのパスワードを取得することができます。
lambda_sample_function = _lambda.Function(
self, "Sample-Lambda",
function_name="sample-function",
runtime=_lambda.Runtime.PYTHON_3_12,
handler="sample.lambda_handler",
code=_lambda.Code.from_asset("lambda/sample"),
role=lambda_role,
vpc=private_subnets_vpc,
security_groups=[lambda_security_group],
environment={
"DB_HOST": rds_instance.attr_endpoint_address,
"DB_PORT": rds_instance.attr_endpoint_port,
"DB_NAME": db_name,
"DB_USER": rds_secret.secret_value_from_json("username").unsafe_unwrap(),
"DB_PASSWORD": rds_secret.secret_value_from_json("password").unsafe_unwrap(),
}
)
このように記載すればパスワードをハードコーディングせずともCDKを実行できて良いですね。
参考記事