amazon-web-servicesaws-lambdaamazon-iamaws-roles

Why lambda function cannot be created in AWS NodeJS SDK after assuming Role with external ID?


AWS.Lambda.createFunction returns error message: "Failed to create Lambda function: InvalidParameterValueException: The role defined for the function cannot be assumed by Lambda."

I am trying to create a lambda function to a third party AWS account via IAM Role delegation. https://docs.aws.amazon.com/IAM/latest/UserGuide/id_roles_common-scenarios_third-party.html?icmpid=docs_iam_console

In the third party account, the IAM Role was created with an external ID. https://docs.aws.amazon.com/IAM/latest/UserGuide/id_roles_create_for-user_externalid.html

Role ARN: 'arn:aws:iam::11111111111:role/Third-party'

{
    "Version": "2012-10-17",
    "Statement": [
        {
            "Effect": "Allow",
            "Principal": {
                "AWS": [
                    "arn:aws:iam::000000000000:user/admin"
                ],
                "Service": "lambda.amazonaws.com"
            },
            "Action": "sts:AssumeRole",
            "Condition": {
                "StringEquals": {
                    "sts:ExternalId": "abcde"
                }
            }
        }
    ]
}

Following parameter is used to assume the role. It returns the credentials.

const assumeRoleRequestParam: AWS.STS.AssumeRoleRequest = {
    RoleArn: 'arn:aws:iam::11111111111:role/Third-party',
    ExternalId: 'abcde',
    RoleSessionName: 'DeployLambaFunction'
}

Lambda function is created as follows.

const lambda = new AWS.Lambda({
    accessKeyId: accessKeyID,
    secretAccessKey: secretAccessKey,
    sessionToken: sessionToken
});

const functionParams: AWS.Lambda.CreateFunctionRequest = {
    FunctionName: 'deploy-test',
    Runtime: 'nodejs14.x',
    Handler: 'index.handler',
    Role: 'arn:aws:iam::11111111111:role/Third-party',
    Code: {
        ZipFile: fs.readFileSync("helloworld.js.zip")
    },
};

lambda.createFunction(functionParams, (err, data) => {
    if (err) {
        console.error('Failed to create Lambda function:', err);
    } else {
        console.log('Lambda function created successfully:', data);
    }
});

It returns the error message given above. But it works if I don't use the external ID in the Role.

I expect creating lambda function should work fine when I use external ID in the IAM role, as it works when I do not use external ID. I checked the AWS documentations and the internet for similar issues, but I find none. Am I missing something?


Solution

  • As commented by @luk2302, the issue is because lambda service itself cannot assume the role with the external ID.

    Solution is to split the role policy into two statements, one for the manual assume-role with the external ID condition and one for the assume-role from the lambda service without such a condition.

    Example:

    {
        "Version": "2012-10-17",
        "Statement": [
            {
                "Effect": "Allow",
                "Principal": {
                    "AWS": "arn:aws:iam::000000000000:user/admin"
                },
                "Action": "sts:AssumeRole",
                "Condition": {
                    "StringEquals": {
                        "sts:ExternalId": "abcde"
                    }
                }
            },
            {
                "Sid": "Statement1",
                "Effect": "Allow",
                "Principal": {
                    "Service": "lambda.amazonaws.com"
                },
                "Action": "sts:AssumeRole"
            }
        ]
    }