Search code examples
amazon-web-servicesamazon-ecsaws-cdkaws-fargateaws-secrets-manager

Using secrets from AWS Secrets Manager in a CDK stack using ECS + Fargate


I have defined a CDK app stack using TypeScript (sensitive information rendomized in the code below):

import * as cdk from "@aws-cdk/core";
import * as ec2 from "@aws-cdk/aws-ec2";
import * as ecs from "@aws-cdk/aws-ecs";
import * as ecr from "@aws-cdk/aws-ecr";
import * as ecr_assets from "@aws-cdk/aws-ecr-assets";
import * as ecs_patterns from "@aws-cdk/aws-ecs-patterns";
import * as sm from "@aws-cdk/aws-secretsmanager";

export class CdkAppStack extends cdk.Stack {
  constructor(scope: cdk.Construct, id: string, props?: cdk.StackProps) {
    super(scope, id, props);

    // Create a Docker image and upload it to the Amazon Elastic Container Registry (ECR)
    const dockerImage = new ecr_assets.DockerImageAsset(this, "ApiDockerImage", {
      directory: "/home/ec2-user/environment/node-test"
    });

    // Create a new VPC and NAT Gateway
    const vpc = new ec2.Vpc(this, "ApiVpc", {
      maxAzs: 3 // Default is all AZs in region
    });

    // Create a new Amazon Elastic Container Service (ECS) cluster
    const cluster = new ecs.Cluster(this, "ApiCluster", {
      vpc: vpc
    });

    // Create a load-balanced Fargate service and make it public
    new ecs_patterns.ApplicationLoadBalancedFargateService(this, "ApiFargateService", {
      cluster: cluster, // Required
      cpu: 512, // Default is 256
      desiredCount: 2, // Default is 1
      taskImageOptions: {
        image: ecs.ContainerImage.fromDockerImageAsset(dockerImage),
        containerPort: 8080,
        enableLogging: true,
        secrets: sm.Secret.fromSecretCompleteArn(this, "ImportedSecret", "arn:aws:secretsmanager:ap-south-1:762589711820:secret:/api/production/FrOibp")
      },
      memoryLimitMiB: 2048, // Default is 512
      publicLoadBalancer: true // Default is false
    });
  }
}

Deployment with cdk deploy is successful if I remove the secrets key from taskImageOptions but with the secrets there, I get this error when trying to deploy:

ec2-user:~/environment/cdk-app (master) $ cdk deploy
⨯ Unable to compile TypeScript:
lib/cdk-app-stack.ts:42:9 - error TS2322: Type 'ISecret' is not assignable to type '{ [key: string]: Secret; }'.
  Index signature is missing in type 'ISecret'.

42         secrets: secret
           ~~~~~~~

Subprocess exited with error 1

I'm doing something wrong here in trying to use secrets from Secrets Manager. What is the right way to reference secrets in a ApplicationLoadBalancedFargateService?


Solution

  • There are two issues here:

    1. secrets is of type index signature. you should therefore name your secret (this is the environment variable that will be exposed in your container)
    2. an ecs.Secret is expected (you can create it from an sm.Secret)

    here is a working version:

    new ecs_patterns.ApplicationLoadBalancedFargateService(this, "ApiFargateService", {
      cluster: cluster, // Required
      cpu: 512, // Default is 256
      desiredCount: 2, // Default is 1
      taskImageOptions: {
        image: ecs.ContainerImage.fromDockerImageAsset(dockerImage),
        containerPort: 8080,
        enableLogging: true,
        secrets: {
          "MY_SECRET": ecs.Secret.fromSecretsManager( sm.Secret.fromSecretCompleteArn(this, "ImportedSecret", "arn:aws:secretsmanager:ap-south-1:762589711820:secret:/api/production/FrOibp"))
        }
      },
      memoryLimitMiB: 2048, // Default is 512
      publicLoadBalancer: true // Default is false
    });