Search code examples
amazon-iamamazon-ecsaws-cdk

AWS CDK - How to pass Access Key Secret and Secret Key Id as Env Param to Container


I'm using CDK to build our infra on AWS. I create my IAM User for my microservices to talk to AWS Services under the defined policies. My issue is I cannot get aws secret key and id and then, pass as Env variable to my container. See below:

First, I create my IAM user which will be used by my microservices.

const user = new User(this, "user", {
  userName: `${myAppEnv}-api-iam-user`,
});

Second, I'm trying to create Access Key.

const accessKey = new CfnAccessKey(this, "ApiUserAccessKey", {
      userName: user.userName,
});

const accessKeyId = new CfnOutput(this, "AccessKeyId", {
      value: accessKey.ref,
});

const accessKeySecret = new CfnOutput(this, "SecretAccessKeyId", {
      value: accessKey.attrSecretAccessKey,
});

Next, I want to pass it as an env variable.

const apiContainer = apiTaskDefinition.addContainer(containerId, {
      image: apiImage,
      environment: {
        APP_ENV: myAppEnv,
        AWS_ACCESS_KEY_ID: awsAccessKeyId.value || ":(",
        AWS_SECRET_ACCESS_KEY: awsSecretAccessKey.value || ":(",
        NOTIFICATIONS_TABLE_ARN: notificationsTableDynamoDBArn,
        NOTIFICATIONS_QUEUE_URL: notificationsQueueUrl,
      },
      cpu: 256,
      memoryLimitMiB: 512,
      logging: new AwsLogDriver({ streamPrefix: `${myAppEnv}-ec-api` }),
    });

When my CDK deploy finishes successfully, I see the below printed out :/

Outputs:
staging-ecstack.AccessKeyId = SOMETHING
staging-ecstack.SecretAccessKeyId = SOMETHINGsy12X21xSSOMETHING2X2

Do you have any idea how I can achieve this?


Solution

  • In short, find the answer in my blogpost here: https://blog.michaelfecher.com/i-tell-you-a-secret-provide-database-credentials-to-an-ecs-fargate-task-in-aws-cdk

    To explain a bit more detailled on your issue:

    1. Avoid custom created IAM Roles and use the generated ones by CDK. They are aligned and using the least-privilege principle. In my blog post, the manual IAM role creation isn't necessary. Yes, I know... I need to update that. ;)
    2. Use the grant* method of the corresponding resource, e.g. taskDefinition. This will create a policy statement for the generated role of 1)
    3. Don't use environment variables for secrets. There are a lot of resources on the web, which tell you why. One is this here: https://security.stackexchange.com/questions/197784/is-it-unsafe-to-use-environmental-variables-for-secret-data Especially, when working with ECS, make use of the secrets argument in the task definition (see the blog post).
    4. It seems, that you're passing the token instead of the actual secret value. That doesn't work. The token is resolved during synth / Cloud Formation generation.
    5. You won't need the CfnOutput. Use the direct Stack -> Stack passing of fields. The CfnOutput is really sth., which you should avoid, when having all Stacks under control in one CDK application. That only makes sense, if you want to share between CDK applications, which are separated deployments and repositories.

    If something is unclear, don't hesitate asking questions.