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

fix(pipelines): Reduce template size by combining IAM roles and policies #9243

Merged
merged 3 commits into from Jul 28, 2020

Conversation

njlynch
Copy link
Contributor

@njlynch njlynch commented Jul 24, 2020

This change combines the two roles (and policies) per pipeline asset into a
single role + policy for all assets in a pipeline. In a small pipeline with only
3 assets, this reduced the overall template size by a third.

With a pipeline stack with 30 assets, this change reduces the template size from
363111 bytes to 190223 bytes.

Tested on a cross-account pipeline to verify permissions were retained.

fixes #9066
mitigates #9225
mitigates #9237


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

This change combines the two roles (and policies) per pipeline asset into a
single role + policy for all assets in a pipeline. In a small pipeline with only
3 assets, this reduced the overall template size by a third.

With a pipeline stack with 30 assets, this change reduces the template size from
363111 bytes to 190223 bytes.

Tested on a cross-account pipeline to verify permissions were retained.

fixes #9066
mitigates #9225
mitigates #9237
@njlynch njlynch requested a review from a team July 24, 2020 13:15
@njlynch njlynch self-assigned this Jul 24, 2020
@mergify mergify bot added the contribution/core This is a PR that came from AWS. label Jul 24, 2020
// Modeled after the CodePipeline role and 'CodePipelineActionRole' roles.
// Late-binding here to prevent creating the role in cases where no asset actions are created.
if (!this.assetRole) {
this.assetRole = new iam.Role(this, 'Role', {
Copy link
Contributor

Choose a reason for hiding this comment

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

What is the eventual IAM policy that will be generated for this role?

We need to be careful here because this role is an important component of our security model so the policy must be least privilege.

The main risk is docker builds in which arbitrary 3rd party code can run.

There are a few things that we should ensure (ideally enforce through unit tests):

  1. Docker publishing roles must not be able to access the s3 assets bucket in order to mitigate the threat of injecting compromised templates that can deploy malicious resources through nested stacks.
  2. The role must be able to assume only the specific cross-account roles in the specified target environments in which it needs to publish into to mitigate the blast radius of a compromised publisher).

Copy link
Contributor Author

Choose a reason for hiding this comment

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

I think this change breaks point 1 above; point 2 I believe is already broken, given the overly-permissive sts:AssumeRole statement in the pipeline asset policy (assuming arn:*:iam::*:role/*-file-publishing-role-*).

Here is a gist with the before/after of the relevant roles and policies: https://gist.github.com/njlynch/b3364ace98559757a1ca4a1a3aab2f6d

I've replaced my account ID with __$PIPELINEACCOUNT__ in the output, but otherwise it's exactly as it appears in the synthesized output. As you can see, there are no other account(s)/environment(s) explicitly referenced, despite this template being for a cross-account, multi-region pipeline.

Copy link
Contributor

Choose a reason for hiding this comment

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

We should raise an issue to fix this policy. The remote role ARNs should actually come from the user app and not be hard coded in the pipelines library. Users are allowed to specify any role ARNs they want for publishing.

I can't seem to find the s3:PutObject permissions in the referenced gist. Are these policies for publishing both docker & s3 assets? We should still separate these into two policies in order to ensure that docker publishers cannot upload files to the S3 asset store.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

We should raise an issue to fix this policy.

Ok. I created #9271 to address this.

I can't seem to find the s3:PutObject permissions in the referenced gist.

s3:PutObject appears as an action on both the "PipelineRoleDefaultPolicy" (used by CodePipeline), the "PipelineBuildSynthCdkBuildProjectRoleDefaultPolicy" (used by CodeBuild as part of the build action), as well as in the policy attached to the *-file-publishing-role-* Role. I believe it's the latter that enables the actual asset publishing 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.

The roles being touched in this PR are not the ones that do the actual publishing; instead, they are the roles that enable the roles that do the actual publishing.

The first role/policy (PipelineAssetsFileAssetNCodePipelineActionRole* in the "before" example) is used by CodePipeline to start/stop the CodeBuild builds. This role is the one assumed by the CodePipeline CodeBuild action. Lumping these all together means there is a single role with the ability to start/stop the CodeBuild builds; I don't think there's a security risk here.

The second role is the one used by CodeBuild itself (PipelineAssetsFileAssetNCodePipelineActionRoleDefaultPolicy* in the "before" example). This role has permissions to create asset-named log groups, CodeBuild report groups, has S3 and KMS get permissions on the entire asset bucket to read and decrypt the manifest, and lastly has permissions to assume the bootstrapped file and image publishing roles. The only elements of this policy that are in any way asset-specific are the named log groups and report groups. So risks here would be a malicious build writing to the wrong logs, maybe?

The main risk is docker builds in which arbitrary 3rd party code can run.

There are a few things that we should ensure (ideally enforce through unit tests):

  1. Docker publishing roles must not be able to access the s3 assets bucket in order to mitigate the threat of injecting compromised templates that can deploy malicious resources through nested stacks.
  2. The role must be able to assume only the specific cross-account roles in the specified target environments in which it needs to publish into to mitigate the blast radius of a compromised publisher).

So the actual asset publishing is controlled by the PublishAssetsAction class, which creates a CodeBuild project that installs cdk-assets, and then executes a series of publish commands. For example:

cdk-assets --path "assembly-CdkpipelinesDemoPipelineStack-PreProdAccount1/CdkpipelinesDemoPipelineStackPreProdAccount1WebService1F433423.assets.json" --verbose publish "0a1ddcc82faef3c47aaafb9516057a34961187be09202edaf14bb4b28a6cb115:ACCOUNT1-eu-west-1"

This reads from the generated *.assets.json files, which have encoded within them the source asset name, destination bucket, object, region, and environment-specific (account & region) role ARN to assume to do the publishing. cdk-assets itself does the STS AssumeRole call, gets environment-specific credentials, and then does the publishing. This is where the above two restrictions are being enforced; a combination of the code that generates the assets.json files and cdk-asset executing it. I don't see a path here for combining the initial two roles causing a breakdown in that chain.

@mergify
Copy link
Contributor

mergify bot commented Jul 28, 2020

Thank you for contributing! Your pull request will be updated from master and then merged automatically (do not update manually, and be sure to allow changes to be pushed to your fork).

@aws-cdk-automation
Copy link
Collaborator

AWS CodeBuild CI Report

  • CodeBuild project: AutoBuildProject6AEA49D1-qxepHUsryhcu
  • Commit ID: 2619720
  • Result: SUCCEEDED
  • Build Logs (available for 30 days)

Powered by github-codebuild-logs, available on the AWS Serverless Application Repository

@mergify
Copy link
Contributor

mergify bot commented Jul 28, 2020

Thank you for contributing! Your pull request will be updated from master and then merged automatically (do not update manually, and be sure to allow changes to be pushed to your fork).

@mergify mergify bot merged commit 1ac6863 into master Jul 28, 2020
@mergify mergify bot deleted the njlynch/pipelines-asset-roles branch July 28, 2020 09:10
curtiseppel pushed a commit to curtiseppel/aws-cdk that referenced this pull request Aug 11, 2020
…ies (aws#9243)

This change combines the two roles (and policies) per pipeline asset into a
single role + policy for all assets in a pipeline. In a small pipeline with only
3 assets, this reduced the overall template size by a third.

With a pipeline stack with 30 assets, this change reduces the template size from
363111 bytes to 190223 bytes.

Tested on a cross-account pipeline to verify permissions were retained.

fixes aws#9066
mitigates aws#9225
mitigates aws#9237


----

*By submitting this pull request, I confirm that my contribution is made under the terms of the Apache-2.0 license*
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
contribution/core This is a PR that came from AWS.
Projects
None yet
Development

Successfully merging this pull request may close these issues.

[@aws-cdk/pipelines] have ability to use the same IAM role for multiple deploying assets
3 participants