4
votes

I feel this question has been asked quite a bit but nothing is working for me from the current answers.

I am trying the deploy an app with Serverless. My serverless.yml is:

app: product-events-api

service: product-events
custom:
  secrets: ${ssm:/aws/reference/secretsmanager/serverless-product-events-${self:provider.stage}~true, ''}
  provider:
    name: aws
    runtime: nodejs10.x
    region: eu-west-1
    stage: ${opt:stage, 'preview'}
    timeout: 30
    # Role ARN must adhere to the RegEx: arn:(aws[a-zA-Z-]*)?:iam::\d{12}:role/?[a-zA-Z_0-9+=,.@\-_/]+
    role: arn:aws:iam::${self:custom.secrets.AWS_ACCOUNT_ID}:role/${self:custom.secrets.IAM_ROLE_NAME}
    vpc: ${self:custom.secrets.vpc}
    environment:
      STAGE: ${self:provider.stage}
      NODE_ENV: production
      DB_NAME: ${self:custom.secrets.DB_NAME}
      DB_URL: ${self:custom.secrets.DB_URL}

functions:
  getProductEvents:
    handler: src/routes/api/handler.events
    memorySize: 1024
    description: Get product event
    events:
      - http:
          path: /events
          method: get

The role evals to an absolute ARN of arn:aws:iam::<Account ID>:role/lambda_basic_execution.

Running sls deploy --stage production gave me the error:

An error occurred: GetProductEventsLambdaFunction - The role defined for the function cannot be assumed by Lambda. (Service: AWSLambdaInternal; Status Code: 400; Error Code: InvalidParameterValueException; Request ID: 4750b33e-329c-4383-abd4-a61ec4d326b2).

This IAM Role is used by almost every lambda we have. I turned to this answer to attempt to define the role just by the name at function level but got:

The CloudFormation template is invalid: Template error: instance of Fn::GetAtt references undefined resource lamba_basic_execution

If I run; aws iam get-role --role-name lambda_basic_execution, I am returned with:

{
    "Role": {
        "AssumeRolePolicyDocument": {
           "Version": "2012-10-17",
            "Statement": [
                {
                    "Action": "sts:AssumeRole",
                    "Principal": {
                        "Service": "lambda.amazonaws.com"
                    },
                    "Effect": "Allow",
                    "Sid": ""
                }
            ]
        },
        "MaxSessionDuration": 3600,
        "RoleId": "<Role ID>",
        "CreateDate": "2015-10-13T15:06:34Z",
        "RoleName": "lambda_basic_execution",
        "Path": "/",
        "Arn": "arn:aws:iam::<Account ID>:role/lambda_basic_execution"
    }
}

If I remove declaring the role from the template, deployment works & then I can add the role manually via the console. I imagine this is a serverless issue.

1
I have two suggestions to your problem. I would first try to role: !Sub "arn:aws:iam::${self:custom.secrets.AWS_ACCOUNT_ID}:role/${self:custom.secrets.IAM_ROLE_NAME}" For the second suggestion, please see the comment below: - Anoop
@Anoop that suggestion throws back the error: Unsupported role provided: "{"Fn::Sub":"arn:aws:iam::<Account ID>:role/lamba_basic_execution"}". So it is correctly evalling the string just not an unsupported format I assume? - wmash

1 Answers

0
votes

As you mentioned that you have few lambdas which uses the same IAM role, I would suggest that you create an IAM role as part of your serverless.yml script. The benefit of this approach is that you can easily add or remove any permissions based on your future needs. You can do something like

  YourIAMRole:
     Type: AWS::IAM::Role 
     Properties: 
       AssumeRolePolicyDocument: 
         Statement: 
          - Effect: Allow 
            Principal: 
              Service: lambda.amazonaws.com 
            Action: sts:AssumeRole 

       Path: / 
       ManagedPolicyArns: 
       - arn:aws:iam::aws:policy/service-role/AWSLambdaBasicExecutionRole 
       Policies: 
         - # Any permission you want to add, For an example I am adding S3
          PolicyName: "resources_access" 
          PolicyDocument: 
            Version: "2012-10-17" 
            Statement: 
             - 
              Effect: "Allow" 
              Action: "s3:Get*" 
              Resource: !Join
                - ''
                - - "arn:aws:s3:::"
                  - !Ref YourParameteredBucketName

Once you do that, you can assign this role to your function as follows:

 Role: !GetAtt YourIAMRole.Arn