skip to Main Content

I have an account DEV trying to create a lambda in account Module. When the code (a lambda that gets triggered by S3) in DEV attempts to create the lambda in MODULE I get the error "Cross-account pass role is not allowed"[Symbol]

The process goes like this: I add a file to DEV S3 this lambda gets triggered and is supposed to call lambda await getLambdaClient(opts).send(new CreateFunctionCommand(params)) where opts are the temporary STS creds obtained using the moduleAssumeRole

I am using CDK/Typescript:

In my MODULE account I create role:

// Basic role for module lambdas created on the fly
const moduleAssumeRole = new Role(this, 'ModuleAssumeRole', {
  roleName: 'moduleAssumeRole',
  assumedBy: new CompositePrincipal(
    new AccountPrincipal(DEV_ACCOUNT_ID),
    new ServicePrincipal('lambda.amazonaws.com')
  )
})
moduleAssumeRole.addToPolicy(
  new PolicyStatement({
    actions: [
      'iam:*',
      'sts:*',
      'lambda:*',
      'logs:*',
      'xray:PutTelemetryRecords',
      'xray:PutTraceSegments'
    ],
    resources: ['*']
  })
)

In my dev stack:

const moduleDeployerLamdba =  new NodejsFunction(this, 'DeployLambda', {
  ...  
  environment: {
    MODULE_ASSUME_ROLE: moduleAssumeRoleArn
  }
))

// I dont think these are needed here but hey... trying passrole everywhere
moduleDeployer.addToRolePolicy(
  new PolicyStatement({
    actions: ['lambda:*', 'logs:*', 's3:*'],
    resources: ['*']
  })
)

moduleDeployer.addToRolePolicy(
  new PolicyStatement({
    actions: ['sts:AssumeRole'],
    resources: ['*']
  })
)

moduleDeployer.addToRolePolicy(
  new PolicyStatement({
    actions: ['iam:PassRole'],
    resources: ['*']
  })
)

In my deploy code on DEV I use the STS client and pass it the moduleAssumeRoleArn to get credentials to use to deploy lambda to MODULE account.

Reading the dozens of posts/blogs on this I cannot find an answer. Docs keep referring to a user having permission to pass a role – not sure what user they are talking about here but the CDK is deployed with AdministratorAccess API keys.

Any ideas?

2

Answers


  1. Chosen as BEST ANSWER

    So I am leaving this question with my silly mistake up because the error message made it a bit vague for me to find the culprit so perhaps will help someone. All my CDK code was correct but I messed up passing the assumed temp credentials to the lambda client. I use a little config merge utility and it essentially discarded the assumed creds in the process. Bad coder. No pizza.


  2. Some least-priviledge adjustments and clean-ups:

    ModuleAssumeRole should narrowly trust the DEV Lambda Role only. The Account Principal is overly broad. The Lambda service principal is invalid.

    const moduleAssumeRole = new Role(this, 'ModuleAssumeRole', {
      roleName: 'moduleAssumeRole',
      assumedBy: new CompositePrincipal(
        new ArnPrincipal(DEV_LAMBDA_ROLE_ARN), // best option for least-privilege access
        new AccountPrincipal(DEV_ACCOUNT_ID),  // valid, but very broad
      )
    })
    

    For least-privilege, the DEV DeployLambdaRole should be allowed to assume ModuleAssumeRole only, not every role.

    moduleDeployer.addToRolePolicy(
      new PolicyStatement({
        actions: ['sts:AssumeRole'],
        resources: [MODULE_ASSUME_ROLE_ARN] // "*" valid, but not least-privilege
      })
    )
    

    Remove the other moduleDeployer.addToRolePolicy calls. Not needed.

    Note the circular dependency between the two roles when least-privilege is applied. ModuleAssumeRole needs the DeployLambdaRole ARN for its trust policy. DeployLambdaRole needs the ModuleAssumeRole ARN for its permissions policy. The easiest way to deal with this is to use explicit role names instead of CDK generated names in this case. Or don’t use least-privilege.

    Login or Signup to reply.
Please signup or login to give your own answer.
Back To Top
Search