55

My team has a pipeline which runs under an execution IAM role. We want to deploy code to AWS through CloudFormation or the CDK.

In the past, we would upload some artifacts to S3 buckets before creating/updating our CloudFormation stack, using the execution IAM role.

We recently switched to the CDK, and are trying to get as much automated with using CDK Deploy as possible, but are running into a lot of permission items we need to add which we didn't have prior (for instance, cloudformation:GetTemplate).

We don't want to just grant * (we want to follow least privilege) but I can't find any clear documented list.

Is there a standard list of permissions that CDK Deploy relies on? Are there any "nice to have's" beyond a standard list?

6 Answers 6

104
+500
Answer recommended by AWS Collective

The CDK v2 now brings and assumes its own roles. No more manual permission management required. You only need to grant permission to assume the cdk roles:

{
    "Version": "2012-10-17",
    "Statement": [
        {
            "Effect": "Allow",
            "Action": [
                "sts:AssumeRole"
            ],
            "Resource": [
                "arn:aws:iam::*:role/cdk-*"
            ]
        }
    ]
}

These roles are created via cdk bootstrap, which then of course requires the permission to create the roles and policies. After the bootstrapping though, this no longer is required. So you could run this manually with a privileged role.

Apparently CDK proceeds if any of the cdk roles cannot be assumed. So it's still possible to manually manage a CDK policy as below, but it might now requires additional permissions.

Be aware, the CFN role has the Administrator policy attached.


Previous answer for CDK v1:

I'm using below policy to deploy CDK apps. Besides CFN full access and S3 full access to the CDK staging bucket, it grants permission to do everything through CloudFormation.

{
    "Version": "2012-10-17",
    "Statement": [
        {
            "Action": [
                "cloudformation:*"
            ],
            "Resource": "*",
            "Effect": "Allow"
        },
        {
            "Condition": {
                "ForAnyValue:StringEquals": {
                    "aws:CalledVia": [
                        "cloudformation.amazonaws.com"
                    ]
                }
            },
            "Action": "*",
            "Resource": "*",
            "Effect": "Allow"
        },
        {
            "Action": "s3:*",
            "Resource": "arn:aws:s3:::cdktoolkit-stagingbucket-*",
            "Effect": "Allow"
        },
        {
            "Effect": "Allow",
            "Action": [
                "ssm:GetParameter"
            ],
            "Resource": "arn:aws:ssm::*:parameter/cdk-bootstrap/*"
        }
    ]
}

You might want to add some explicit denies for things you don't want to allow.

Also, be aware that above condition does not mean the principal is limited to things possible with CloudFormation. A potential attack vector would be to create a custom CFN resource, backed by a Lambda function. When creating resources through that custom resource you then could do anything in the Lambda, because it is triggered via CloudFormation.

When you use lookups (those are the .fromXxx(...) methods), the CDK will make read/list requests to the related service at runtime - while the CDK synth is running, not the CloudFormation deploy. Which permissions you need, of course, depends on the lookups you have in your code. For example, if you would have a Vpc.fromLookup() you should allow the action ec2:DescribeVpcs. Of course you could attach the ReadOnlyAccess policy, if you have no concerns about accessing sensitive content.

7
  • 4
    It seems like the ec2:Describe* operations are needed, as well, to allow a CDK app to resolve AMIs and stuff like that.
    – solidsnack
    Oct 31, 2020 at 21:22
  • Good call, yeah, that's for lookups, things CDK looks up via API. But that's very specific to your use case.
    – udondan
    Nov 1, 2020 at 9:00
  • 1
    Lookups seem to be baked into a lot of CDK functionality.
    – solidsnack
    Nov 2, 2020 at 16:24
  • I added a note about lookups to the answer. Of course that's highly specific to the lookups you make in your code, so that cannot be part of a general one-size-fits-all policy.
    – udondan
    Nov 5, 2021 at 8:02
  • @udondan regarding CDK v2 solution... where should I attach this policy. I tried creating a policy and attaching it to the user but it's not working.
    – alayor
    Feb 1, 2022 at 3:00
27

Since I couldn't find any documentation anywhere I had to do some trial and error to get this to work.

Apart from the permissions you need to create the actual resources you define in your stack, you need to give the following:

cloudformation:DescribeStacks
cloudformation:CreateChangeSet
cloudformation:DescribeChangeSet
cloudformation:ExecuteChangeSet
cloudformation:DescribeStackEvents
cloudformation:DeleteChangeSet
cloudformation:GetTemplate

To the stack ARN you are creating, as well as the bootstrap stack:

arn:aws:cloudformation:${AWS::Region}:${AWS::AccountId}:stack/CDKToolkit/*

You also need s3 permissions to the bucket that the boostrap added (otherwise you get that dreaded Forbidden: null error):

s3:*Object
s3:ListBucket
s3:GetBucketLocation

to

arn:aws:s3:::cdktoolkit-stagingbucket-*
2
  • 2
    For anyone finding this, you will also need s3:GetBucketLocation as an s3 permission for the cdktoolkit bucket. Oct 1, 2020 at 22:49
  • 1
    I also needed cloudformation:GetTemplate.
    – Aleksi
    Sep 7, 2021 at 12:31
9

CDK has two phases the bootstrap and the synth/deploy.

In the case of bootstrap the IAM role or profile used must have the following policy permissions:

{
    "Version": "2012-10-17",
    "Statement": [
        {
            "Sid": "StsAccess",
            "Effect": "Allow",
            "Action": [
                "sts:AssumeRole",
                "iam:*Role*"
            ],
            "Resource": [
                "arn:aws:iam::${AWS_ACCOUNT_ID}:role/cdk-*"
            ]
        },
        {
            "Action": [
                "cloudformation:*"
            ],
            "Resource": [
                "arn:aws:cloudformation:${AWS_REGION}:${AWS_ACCOUNT_ID}:stack/CDKToolkit/*"
            ],
            "Effect": "Allow"
        },
        {
            "Sid": "S3Access",
            "Effect": "Allow",
            "Action": [
                "s3:*"
            ],
            "Resource": [
                "*"
            ]
        },
        {
            "Sid": "ECRAccess",
            "Effect": "Allow",
            "Action": [
                "ecr:SetRepositoryPolicy",
                "ecr:GetLifecyclePolicy",
                "ecr:PutImageScanningConfiguration",
                "ecr:DescribeRepositories",
                "ecr:CreateRepository",
                "ecr:DeleteRepository"
            ],
            "Resource": [
                "arn:aws:ecr:${AWS_REGION}:${AWS_ACCOUNT_ID}:repository/cdk-*"
            ]
        },
        {
            "Effect": "Allow",
            "Action": [
                "ssm:GetParameter*",
                "ssm:PutParameter*",
                "ssm:DeleteParameter*"
            ],
            "Resource": "arn:aws:ssm:${AWS_REGION}:${AWS_ACCOUNT_ID}:parameter/cdk-bootstrap/*"
        }
    ]
}

While in the case of deployment, the role or profile must have the following as mandatory permission:

{
    "Version": "2012-10-17",
    "Statement": [
        {
            "Effect": "Allow",
            "Action": [
                "iam:PassRole"
            ],
            "Resource": "*"
        },
        {
            "Effect": "Allow",
            "Action": [
                "sts:AssumeRole"
            ],
            "Resource": [
                "arn:aws:iam::*:role/cdk-*"
            ]
        }
    ]
}

Plus with all the permissions needed for the infrastructure you're deploying.

The thing I can recommend is to use two different roles so that you have more security, and in case you're using GitHub workflow to take advantage of the OpenIdConnect.

The bootstrap policy could be improved by restricting permissions but the documentation is lacking so I do not delve into specific aspects (example s3)

4
  • Thank you! This really helps. Can you share where you got the information for the permissions required for bootstrapping?
    – SweetFeet
    Jul 6, 2022 at 14:10
  • Adding to the GitHub access via OIDC token, you can also restrict this access on the IAM side to GitHub environments. GitHub environments can be configured to require an explicit approval. This can be configured as a Condition in the trust-relationship of the role which is assumed by CDK
    – Felix
    May 18, 2023 at 21:43
  • This post is useful for the bootstrapping permissions: stackoverflow.com/a/71923639/4665923. You can also use the CDK CLI and run: cdk bootstrap --show-template > bootstrap-template.yaml This provides the bootstrap cloudwatch template used.
    – Joelster
    Jun 10, 2023 at 13:10
  • 1
    I needed to add: "ecr:PutLifecyclePolicy" Jun 20, 2023 at 18:45
0

We also needed to add below permissions as well.

ssm:PutParameter
ecr:SetRepositoryPolicy
ecr:GetLifecyclePolicy
ecr:PutImageScanningConfiguration
ssm:GetParameters
ecr:DescribeRepositories
0

I'm using this for automate deploy from GitHub actions, and the only way that it works, it was grant the permissions

    {
      "Sid": "PolicyForSpecificStack",
      "Effect": "Allow",
      "Action": "cloudformation:*",
      "Resource": "arn:aws:cloudformation:<region>:*:stack/<my-stack-name>/*"
    },
    {
      "Sid": "S3Access",
      "Effect": "Allow",
      "Action": ["s3:*"],
      "Resource": ["*"]
    }

to the policy that use to deploy my cloudformation stack, my final policy looks likethis

{
  "Version": "2012-10-17",
  "Statement": [
    {
      "Effect": "Allow",
      "Action": ["iam:PassRole"],
      "Resource": "*"
    },
    {
      "Effect": "Allow",
      "Action": ["sts:AssumeRole"],
      "Resource": ["arn:aws:iam::*:role/cdk-*"]
    },
    {
      "Sid": "PolicyForSpecificStack",
      "Effect": "Allow",
      "Action": "cloudformation:*",
      "Resource": "arn:aws:cloudformation:<region>:*:stack/<my-stack-name>/*"
    },
    {
      "Sid": "S3Access",
      "Effect": "Allow",
      "Action": ["s3:*"],
      "Resource": ["*"]
    }
  ]
}
0

Please note that while udondan solution for CDK v2 works, it doesen't follow the least privilege principle by default. As he mentioned in his post, the CloudFormation execution role created during bootstrapping has arn:aws:iam::aws:policy/AdministratorAccess. So everyone who has been granted the CDK roles via AssumeRole will have admin access.

This can be fixed by creating a custom IAM policy and using this role during bootstrapping:

cdk bootstrap aws://<account_id>/eu-west-1 --cloudformation-execution-policies \ 
"arn:aws:iam::$ACCOUNT_ID:policy/cdkCFExecutionPolicy"

This will limit the execution role to whatever you have defined in your custom policy. A suitable custom policy might look like the following (taken from Least deployment privilege with CDK Bootstrap by Maciej Radzikowski). But you should make sure that the policy is tailored to your requirements.

cdkCFExecutionPolicy

{
  "Version": "2012-10-17",
  "Statement": [
    {
      "Effect": "Allow",
      "Action": [
        "apigateway:*",
        "cloudwatch:*",
        "lambda:*",
        "logs:*",
        "s3:*",
        "ssm:*"
      ],
      "Resource": "*",
      "Condition": {
        "StringEquals": {
          "aws:RequestedRegion": "eu-west-1"
        }
      }
    },
    {
      "Effect": "Allow",
      "Action": [
        "cloudfront:*"
      ],
      "Resource": "*"
    },
    {
      "Effect": "Allow",
      "Action": [
        "iam:*Role*",
        "iam:GetPolicy",
        "iam:CreatePolicy",
        "iam:DeletePolicy",
        "iam:*PolicyVersion*"
      ],
      "NotResource": [
        "arn:aws:iam::*:role/cdk-*",
        "arn:aws:iam::*:policy/cdkCFExecutionPolicy"
      ]
    }
  ]
}

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.