ECSでRailsアプリをCDKで実装する方法(RDSのパスワードなどをSecrets Manager経由で参照させる)

はじめに

先日、Rails 7.2で作ったアプリをECSで動かすことをやりました。

miyohide.hatenablog.com

ここで課題として挙げたCDKでの実装をやってみたので、そのやり方を紹介します。

RDSの作成とパスワードなどの情報をSecrets Managerに登録する

aws-cdk-lib/aws-rdsで作成したRDSのパスワードは、デフォルトではSecrets Managerに登録されます。このことはCDKのドキュメントにも記載されています。

docs.aws.amazon.com

Secrets ManagerのARNを取得する

先日、ECSの環境変数としてSecrets Managerで登録されている値をみる方法を実装しました。詳細は以下を参照してください。

miyohide.hatenablog.com

上記の記事でも書きましたが、ここで必要になるのがSecrets ManagerのARNです。

Secrets ManagerのARNを取得する方法を探していたのですが、結果としては作成したRDSのインスタンスに対してsecret!.secretArnを呼び出せばOKです。

docs.aws.amazon.com

ECSの環境変数としてSecrets Managerを指定する

あとはCDKでECSの環境変数を設定します。以下のような実装になりました。

        // タスク定義の作成
        const taskDef = new FargateTaskDefinition(this, "EcsTaskDefinition", {
            cpu: 256,
            memoryLimitMiB: 512,
            runtimePlatform: {
                cpuArchitecture: CpuArchitecture.X86_64,
            },
        });
        // ログドライバーを作成
        const logDriver = new AwsLogDriver({
            streamPrefix: "ecs",
            logRetention: RetentionDays.ONE_DAY,
        });

        // Secrets Managerの取得。propsにRDSのインスタンスが格納されていることを前提
        const secretsManager = props.rdsInstance.secret!;

        // コンテナ定義を追加
        taskDef.addContainer("EcsContainer", {
            image: ContainerImage.fromEcrRepository(props.ecrRepository, "latest"),
            portMappings: [{
                containerPort: 3000
            }],
            logging: logDriver,
            environment: {
                POSTGRES_HOST: props.rdsInstance.instanceEndpoint.hostname,
                RAILS_ENV: "production",
                RAILS_LOG_TO_STDOUT: "1",
                RAILS_SERVE_STATIC_FILES: "1",
                RAILS_MASTER_KEY: props.railsMasterKey,
            },
            // Secrets Managerの値を参照するようにする
            secrets: {
                POSTGRES_USER: Secret.fromSecretsManager(secretsManager, "username"),
                POSTGRES_PASSWORD: Secret.fromSecretsManager(secretsManager, "password"),
            },
        });

ポイントは、secretsの部分でSecret.fromSecretsManagerを使う点です。これで、Secrets ManagerのARN:キー名::の文字列を生成することができます。

タスク実行ロール

先日、AWSコンソール上ではタスク実行ロールにSecrets Managerの参照権限を手作業で付与しました。これを踏まえ、以下のような実装を考えたのですが...

        taskDef.addToExecutionRolePolicy(new PolicyStatement({
            effect: Effect.ALLOW,
            resources: [secretsManager.secretArn],
            actions: [
                'secretsmanager:GetResourcePolicy',
                'secretsmanager:GetSecretValue',
                'secretsmanager:DescribeSecret',
                'secretsmanager:ListSecretVersionIds'
            ]
        }));

実際にはこの記述は不要でした。CDKがいい感じに必要となる権限を設定してくれました。

考察

ECS上でRailsを動かすことを実装してみました。AWSコンソール上でやるのは分かりやすいのですが、何回も繰り返しやる場合にはCDKで実装しておくのが楽なのでなんとかその実装方法を見つけるために、色々と試行錯誤しました。そのうちの一つが今回取り上げたSecrets Managerの所得でしたり、以下の記事で取り上げたパラメータだったりします。

miyohide.hatenablog.com

結構CDKでいろんなことができると考えていたのですが、新しいことに取り組むと知らないことも多く、今回もまた勉強になりました。