Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat(ecs): support secret environment variables #2994

Merged
merged 30 commits into from
Jul 29, 2019
Merged

Conversation

jogold
Copy link
Contributor

@jogold jogold commented Jun 21, 2019

Add support for runtime secrets in containers by adding a union class to treat secret environment
variable values whether they are pulled from a SSM parameter or a AWS Secrets secret.

https://docs.aws.amazon.com/AmazonECS/latest/developerguide/specifying-sensitive-data.html

Closes #1478


Pull Request Checklist

  • Testing
    • Unit test added (prefer not to modify an existing test, otherwise, it's probably a breaking change)
    • CLI change?: coordinate update of integration tests with team
    • cdk-init template change?: coordinated update of integration tests with team
  • Docs
    • jsdocs: All public APIs documented
    • README: README and/or documentation topic updated
    • Design: For significant features, design document added to design folder
  • Title and Description
    • Change type: title prefixed with fix, feat and module name in parens, which will appear in changelog
    • Title: use lower-case and doesn't end with a period
    • Breaking?: last paragraph: "BREAKING CHANGE: <describe what changed + link for details>"
    • Issues: Indicate issues fixed via: "Fixes #xxx" or "Closes #xxx"
  • Sensitive Modules (requires 2 PR approvers)
    • IAM Policy Document (in @aws-cdk/aws-iam)
    • EC2 Security Groups and ACLs (in @aws-cdk/aws-ec2)
    • Grant APIs (only if not based on official documentation with a reference)

By submitting this pull request, I confirm that my contribution is made under the terms of the Apache-2.0 license.

Add a union class to treat environment variable values whether they are given as clear text, from
a SSM parameter or a secret.

Closes aws#1478

BREAKING CHANGE: `environment` in `ecs.ContainerDefinition` now takes an object whose values are of
`ecs.EnvironmentValue` type.
@jogold jogold requested review from SoManyHs and a team as code owners June 21, 2019 14:21
@@ -65,7 +65,7 @@ export interface LoadBalancedServiceBaseProps {
*
* @default - No environment variables.
*/
readonly environment?: { [key: string]: string };
readonly environment?: { [key: string]: ecs.EnvironmentValue };
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I feel like we might want to use some token magic here.

FWIW, we should have Tokenized representations of secret values already. Can we not use those in some way?

Copy link
Contributor Author

@jogold jogold Jun 21, 2019

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

For the Secrets property, CF expects the ARN of the secret/ssm param, the container will pull that value at startup and set it as env var avoiding passing secrets in clear text. Secret env vars are retrieved at runtime (always up to date), this is not the case with simple env vars (fixed at deploy time)

The class EnvironmentValue will feed either environment or secrets based on the type. This gives a better user experience (higher level of abstraction) than having to specify environment and/or secrets manually (both will become env vars in the running container at the end).

https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-ecs-taskdefinition-containerdefinitions.html#cfn-ecs-taskdefinition-containerdefinition-environment
https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-ecs-taskdefinition-secret.html

The support for the Secrets property was added in the latest release of CF (https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/ReleaseHistory.html).

https://docs.aws.amazon.com/AmazonECS/latest/developerguide/specifying-sensitive-data.html

@jogold
Copy link
Contributor Author

jogold commented Jun 21, 2019

TODO: automatically add proper IAM permissions to task execution role based on referenced parameters/secrets.

@jogold
Copy link
Contributor Author

jogold commented Jul 1, 2019

@eladb build is failing due to breaking changes... what do you suggest here? I think it's nice to have everything expressed as environment...

Copy link

@ScottBrenner ScottBrenner left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks for this! Quick typo fixes..

packages/@aws-cdk/aws-ecs/lib/container-definition.ts Outdated Show resolved Hide resolved
packages/@aws-cdk/aws-ecs/lib/container-definition.ts Outdated Show resolved Hide resolved
packages/@aws-cdk/aws-ecs/lib/container-definition.ts Outdated Show resolved Hide resolved
jogold and others added 3 commits July 4, 2019 15:50
Co-Authored-By: Scott Brenner <scott@scottbrenner.me>
Co-Authored-By: Scott Brenner <scott@scottbrenner.me>
Co-Authored-By: Scott Brenner <scott@scottbrenner.me>
@jogold
Copy link
Contributor Author

jogold commented Jul 18, 2019

@eladb @rix0rrr this is breaking.

Two solutions here:

  • Leave environment as-is and add a secrets prop for SSM and AWS Secrets pulled env vars. This is what CF does.
  • Leave environment as-is and add a environmentVariables prop (name?) that does what this PR currently suggests (= one general concept for container env vars).

The CF support for secret env vars was a highly requested feature (aws/containers-roadmap#97) and should be supported with cdk...

@eladb
Copy link
Contributor

eladb commented Jul 21, 2019

I think the secrets approach makes more sense.

@jogold jogold requested a review from a team as a code owner July 22, 2019 08:28
return new Secret({ secret });
}

constructor(public readonly props: SecretProps) {}
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is a bit unnecessarily convoluted I think. Why not just accept an “arn” string here? This will remove the need for SecretProps and the special casing in renderContainerDefintion

Copy link
Contributor Author

@jogold jogold Jul 22, 2019

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

How do you suggest granting read (secret.grantRead() or parameter.grantRead()) to the task execution role in renderContainerDefinition? With a .fromArn() there? (there's no way to import from ARN currently in SSM, works for AWS Secrets)

Copy link
Contributor Author

@jogold jogold Jul 22, 2019

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It is also possible to do taskDefintion.obtainExecutionRole().addToPolicy(...) but I find that duplicating SSM/Secrets read IAM permissions is not a elegant solution...

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Something like that (polymorphism ;-)):

abstract class Secret {

  public static fromSecretsManager(secret: ISecret): Secret {
    return {
      arn: secret.secretArn,
      grantRead: grantee => secret.grantRead(grantee)
    };
  }
  
  public abstract readonly arn: string;
  public abstract grantRead(grantee: IGrantee): Grant;
}

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Nice

packages/@aws-cdk/aws-ecs/lib/container-definition.ts Outdated Show resolved Hide resolved
return new Secret({ secret });
}

constructor(public readonly props: SecretProps) {}
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Something like that (polymorphism ;-)):

abstract class Secret {

  public static fromSecretsManager(secret: ISecret): Secret {
    return {
      arn: secret.secretArn,
      grantRead: grantee => secret.grantRead(grantee)
    };
  }
  
  public abstract readonly arn: string;
  public abstract grantRead(grantee: IGrantee): Grant;
}

Copy link
Contributor

@eladb eladb left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please update README

@@ -29,6 +29,13 @@ export interface QueueProcessingServiceBaseProps extends BaseProps {
*/
readonly enableLogging?: boolean;

/**
* The environment variables to pass to the container.
*
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is this really the default or will it always be passed?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This part is not mine, it seems that it's always passed, I can update the doc.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks, that would be nice

@@ -1,3 +1,5 @@
export * from './base/props';
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Do we really need this exported? The base interface e doesn’t need to be public

Copy link
Contributor Author

@jogold jogold Jul 23, 2019

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can you do this with jsii?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

OK, need to add @internal for this to work.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

What happens if you just not export this file here?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

error TS9999: JSII: Unable to resolve referenced type '@aws-cdk/aws-ecs-patterns.BaseProps'. Type may be @internal or unexported

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

ahhh... apologies for the hassle... Let's revert this base struct... On second thought, it does not really make sense for these to be shared between the patterns...

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Sorry!

@jogold
Copy link
Contributor Author

jogold commented Jul 29, 2019

Is this ok? Can this be merged?

@eladb eladb merged commit bc233fa into aws:master Jul 29, 2019
@jogold jogold deleted the ecs-secrets branch July 29, 2019 08:49
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

Support secret for ecs fargate task definition
4 participants