Qinjie
Qinjie

Reputation: 1928

AWS CDK How to Set Permission Boundary to New Roles Created within Pipeline?

Some new roles are created during execution of cdk-pipelines. How can we force attachment of Permission Boundary to these newly created role?

Background: Our AWS account only allow creation of role with a specific permission boundary. Role creation will fail if no permission bounary is specified.

My CDK project failed when it tries to create new roles within the pipeline.

API: iam:CreateRole User: arn:aws:sts::305326993135:assumed-role/cdk-hnb659fds-cfn-exec-role-305326993135-ap-southeast-1/AWSCloudFormation is not authorized to perform: iam:CreateRole on resource: arn:aws:iam::305326993135:role/whitespace-web-cloudfront-CustomS3AutoDeleteObject-16P4QGQ0QPJIR with an explicit deny

Upvotes: 1

Views: 3976

Answers (4)

Richard Hudson
Richard Hudson

Reputation: 41

Theres a new runtime context property that works

Add this to your cdk json

"@aws-cdk/core:permissionsBoundary": {
  "name": "YourPermissionBoundaryPolicyName"
}

You wont require an aspect, it will automatically attach to all created roles.

ref - https://docs.aws.amazon.com/cdk/api/v2/docs/aws-cdk-lib.aws_iam-readme.html#bootstrap-permissions-boundary

Upvotes: 3

Oleksandr Lykhonosov
Oleksandr Lykhonosov

Reputation: 1388

You don't need an aspect for adding permissions boundary globally anymore because the latest versions of CDK support this out of the box:

// This imports an existing policy.
const boundary = iam.ManagedPolicy.fromManagedPolicyArn(this, 'Boundary', 'arn:aws:iam::123456789012:policy/boundary');

// This creates a new boundary
const boundary2 = new iam.ManagedPolicy(this, 'Boundary2', {
  statements: [
    new iam.PolicyStatement({
      effect: iam.Effect.DENY,
      actions: ['iam:*'],
      resources: ['*'],
    }),
  ],
});

// Directly apply the boundary to a Role you create
declare const role: iam.Role;
iam.PermissionsBoundary.of(role).apply(boundary);

// Apply the boundary to an Role that was implicitly created for you
declare const fn: lambda.Function;
iam.PermissionsBoundary.of(fn).apply(boundary);

// Apply the boundary to all Roles in a stack
iam.PermissionsBoundary.of(this).apply(boundary);

// Remove a Permissions Boundary that is inherited, for example from the Stack level
declare const customResource: CustomResource;
iam.PermissionsBoundary.of(customResource).clear();

https://docs.aws.amazon.com/cdk/api/v2/docs/aws-cdk-lib.aws_iam-readme.html#permissions-boundaries https://docs.aws.amazon.com/cdk/api/v2/python/aws_cdk.aws_iam/PermissionsBoundary.html

Upvotes: 3

Qinjie
Qinjie

Reputation: 1928

I found following class from somewhere when I searched for solution some time ago. (Sorry, cannot remember where is the origin)

import cdk = require("@aws-cdk/core");

export class PermissionsBoundary implements cdk.IAspect {
  private readonly permissionsBoundaryArn: string;

  constructor(permissionBoundaryArn: string) {
    this.permissionsBoundaryArn = permissionBoundaryArn;
  }

  public visit(node: cdk.IConstruct): void {
    if (
      cdk.CfnResource.isCfnResource(node) &&
      node.cfnResourceType === "AWS::IAM::Role"
    ) {
      node.addPropertyOverride(
        "PermissionsBoundary",
        this.permissionsBoundaryArn
      );
    }
  }
}

In your code, add permission boudary to your pipeline stack, where AWS_POLICY_PERM_BOUNDARY is ARN of your permission boundary.

  cdk.Aspects.of(pipelineStack).add(
    new PermissionsBoundary(AWS_POLICY_PERM_BOUNDARY)
  );

Upvotes: 0

lynkfox
lynkfox

Reputation: 2400

The Automatically generated roles of any construct within CDK can be accessed and modified with the your_construct.Role attribute. You can then use (using python since im most familiar, but they exist in all CDK languages) various methods like your_construct.Role.add_to_principle_policy or add_policy to add additional statements to the existing in-line policy or even entirely new ones (from the aws_iam.PolicyStatement or aws_iam.Policy constructs.)

You can also define a role yourself using the aws_iam.Role constructs and attach it to the pipeline (using the role property of its constructor). If you do that, it overrides the automatically generated role so make sure you know all the permissions that role would need before attaching it and you have defined them yourself (This is actually a good end goal in any case as it allows you to lock down and give minimal permissions to all your constructs in order to have good best practice security)

Upvotes: 0

Related Questions