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

custom-resources: cannot make custom resource lambda function depend on a managed policy #27782

Closed
toxygene opened this issue Oct 31, 2023 · 4 comments
Labels
@aws-cdk/custom-resources Related to AWS CDK Custom Resources bug This issue is a bug. effort/medium Medium work item – several days of effort p2

Comments

@toxygene
Copy link

toxygene commented Oct 31, 2023

Describe the bug

I am trying to create an AwsCustomResource with a VPC and role. The role has a managed policy attached to it, which grants the ec2 actions necessary to create a Lambda function within a VPC. I have also manually set the managed policy as a dependency of the AwsCustomResource.

Expected Behavior

Deploys successfully.

Current Behavior

The deploy fails with the following message:

Resource handler returned message: "The provided execution role does not have permissions to call CreateNetworkInterface on EC2 (Service: Lambda, Status Co
de: 400, Request ID: 7fdc9ef3-f44a-4f4f-8f87-b3b438ca9ebd)" (RequestToken: 519f5445-5cd6-1b0e-e5b1-fc55d1ee9e06, HandlerErrorCode: InvalidRequest)

Reproduction Steps

class MyStack extends Stack {
  constructor(scope: Construct, id: string, options: StackProps) {
    super(scope, id, options);

    const vpc = Vpc.fromLookup(
      this,
      'Vpc',
      {
        tags: {
          AccountResourceId: 'Vpc'
        }
      }
    );

    const topic = new Topic(
      this,
      'Topic'
    );

    const role = new Role(
      this,
      'Role',
      {
        assumedBy: new ServicePrincipal('lambda.amazonaws.com')
      }
    );

    const managedPolicy = new ManagedPolicy(
      this,
      'ManagedPolicy',
      {
        roles: [role],
        statements: [
          new PolicyStatement({
            actions: [
              'ec2:CreateNetworkInterface',
              'ec2:DescribeNetworkInterfaces',
              'ec2:DeleteNetworkInterface',
              'ec2:AssignPrivateIpAddresses',
              'ec2:UnassignPrivateIpAddresses',
            ],
            effect: Effect.ALLOW,
            resources: ['*']
          }),
          new PolicyStatement({
            actions: [
              'sns:SetTopicAttributes'
            ],
            effect: Effect.ALLOW,
            resources: [topic.topicArn]
          })
        ]
      }
    );

    const customResource = new AwsCustomResource(
      this,
      'CustomResource',
      {
        onCreate: {
          service: 'sns',
          action: 'SetTopicAttributes',
          parameters: {
            AttributeName: 'SQSSuccessFeedbackSampleRate',
            AttributeValue: '100',
            TopicArn: topic.topicArn,
            Version: '2010-03-31'
          },
          physicalResourceId: PhysicalResourceId.of(`${topic.topicName}-SQSSuccessFeedbackSampleRate`)
        },
        role: role,
        vpc: vpc,
        vpcSubnets: {
          subnetType: SubnetType.PRIVATE_WITH_EGRESS
        }
      }
    );

    customResource.node.addDependency(managedPolicy);
  }
}

Possible Solution

Is it possible to make the AwsCustomResource construct a dependency of the Lambda Function it creates, thus preserving user-space constructs with the AwsCustomResource?

this.node.addDependency(provider);

Additional Information/Context

It is possible to work around this issue by creating the managed policy, then passing it to the constructor of the role.

    const managedPolicy = new ManagedPolicy(
      this,
      'ManagedPolicy',
      {
        statements: [
          new PolicyStatement({
            actions: [
              'ec2:CreateNetworkInterface',
              'ec2:DescribeNetworkInterfaces',
              'ec2:DeleteNetworkInterface',
              'ec2:AssignPrivateIpAddresses',
              'ec2:UnassignPrivateIpAddresses',
            ],
            effect: Effect.ALLOW,
            resources: ['*']
          }),
          new PolicyStatement({
            actions: [
              'sns:SetTopicAttributes'
            ],
            effect: Effect.ALLOW,
            resources: [topic.topicArn]
          })
        ]
      }
    );

    const role = new Role(
      this,
      'Role',
      {
        assumedBy: new ServicePrincipal('lambda.amazonaws.com'),
        managedPolicies: [managedPolicy]
      }
    );

This work around isn't obvious, as it took me a while before I realized it.

CDK CLI Version

2.103.1

Framework Version

No response

Node.js Version

v18.18.2

OS

MacOs 13.6

Language

TypeScript

Language Version

No response

Other information

No response

@toxygene toxygene added bug This issue is a bug. needs-triage This issue or PR still needs to be triaged. labels Oct 31, 2023
@github-actions github-actions bot added the @aws-cdk/custom-resources Related to AWS CDK Custom Resources label Oct 31, 2023
@pahud
Copy link
Contributor

pahud commented Nov 1, 2023

You will need to make sure the custom managed policy would attach to the role before the creation of the custom resource.

One option as you mentioned above is to create the role with your managed policies

const role = new Role(
      this,
      'Role',
      {
        assumedBy: new ServicePrincipal('lambda.amazonaws.com'),
        managedPolicies: [managedPolicy]
      }
    );

Another option is to make the role depend on the managed policies like

role.node.addDependency(managedPolicy)

This ensures the managedPolicy to be created first, and then the role and eventually the custom resource which implicitly depends on the role.

@pahud pahud added response-requested Waiting on additional info and feedback. Will move to "closing-soon" in 7 days. p2 effort/medium Medium work item – several days of effort and removed needs-triage This issue or PR still needs to be triaged. labels Nov 1, 2023
@toxygene
Copy link
Author

toxygene commented Nov 2, 2023

Perhaps this would be better labeled as an enhancement. I'm proposing adding a dependency between the CustomResource created within the AwsCustomResource and the AwsCustomResource. This change will "chain" any dependencies down to the Lambda Function is created.

To illustrate this, I have created a fork of aws-cdk with these proposed modifications.

https://github.com/toxygene/aws-cdk/tree/toxygene/custom-resources-dependency

My changes can be seen in this commit: toxygene@de3209b

@github-actions github-actions bot removed the response-requested Waiting on additional info and feedback. Will move to "closing-soon" in 7 days. label Nov 2, 2023
@toxygene
Copy link
Author

Closing in favor of new feature request: #28049

Copy link

⚠️COMMENT VISIBILITY WARNING⚠️

Comments on closed issues are hard for our team to see.
If you need more assistance, please either tag a team member or open a new issue that references this one.
If you wish to keep having a conversation with other community members under this issue feel free to do so.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
@aws-cdk/custom-resources Related to AWS CDK Custom Resources bug This issue is a bug. effort/medium Medium work item – several days of effort p2
Projects
None yet
Development

No branches or pull requests

2 participants