Allow other AWS services to invoke Lambda using IAM

amazon-api-gatewayamazon-iamamazon-lambdaamazon-web-services

Is it possible to grant AWS services (e.g. API gateway, Secrets Manager) permission to invoke a Lambda function using only IAM roles? Normally this is done in the function's policy (resource-based policy), but I wonder if this is the only way. The advantage of using IAM is that one policy can allow multiple Lambdas to be executed, without the overhead of managing one policy per function. (Note that I am not asking about Lambda IAM +execution roles+, which determine permissions as the function executing.)

Documentation on the Lambda Permissions Model suggests that IAM roles can be used in place of Lambda function policies:

Instead of using a Lambda function policy, you can create another IAM role that grants the event sources (for example, Amazon S3 or DynamoDB) permissions to invoke your Lambda function. However, you might find that resource policies are easier to set up and they make it easier for you to track which event sources have permissions to invoke your Lambda function.

In my digging, however, I have not been able to achieve the advertised effect. I've tried to grant two two services permission to invoke Lambdas: API gateway and Secrets Manager. In both cases, I found these services require access to be granted within the function policy, not an IAM role.

Service 1: Secrets Manager

I am rotating RDS credentials in Secrets Manager. Normally, Secrets Manager creates Lambdas to perform the rotation once you configure the secret's rotation schedule, but in my case I did not like the long custom names of the Lambda functions and created my own. I attempted to grant Secrets Manager permission to invoke any Lambda using IAM roles, so I created the following role:

Trust relationship:

{
  "Version": "2012-10-17",
  "Statement": [
    {
      "Sid": "AllowApiGatewayToAssumeRole",
      "Effect": "Allow",
      "Principal": {
        "Service": "apigateway.amazonaws.com"
      },
      "Action": "sts:AssumeRole"
    }
  ]
}

Permissions:

{
    "Version": "2012-10-17",
    "Statement": [
        {
            "Sid": "AllowInvokeAnyLambda",
            "Effect": "Allow",
            "Action": "lambda:InvokeFunction",
            "Resource": "*"
        }
    ]
}

At the time of this writing, the AWS console does not have a way set a custom Lambda for rotating RDS credentials, so I used the CLI:

$ aws secretsmanager rotate-secret --secret-id 'rds/my-db/account' --rotation-lambda-arn 'arn:aws:lambda:us-east-1:xxxxxxxxxxxx:function:rotate-rds-secret' --rotation-rules AutomaticallyAfterDays=1

An error occurred (AccessDeniedException) when calling the RotateSecret operation: Secrets Manager cannot invoke the specified Lambda function. Ensure that the function policy grants access to the principal secretsmanager.amazonaws.com

So it looks like Secrets Manager does not use this IAM role to invoke the Lambda. And there does not seem to be a way to configure Secrets Manager to use a specific IAM role.

Service 2: API Gateway

I am using API Gateway to call my Lambda function. API Gateway has two different integration types which support invoking a Lambda: (1) Lambda function and (2) AWS Service (https://docs.aws.amazon.com/apigateway/latest/developerguide/integrating-api-with-aws-services-lambda.html).

When using Lambda function integration, it's the same story as with Secrets Manager—you need to use function policies to grant API Gateway invoke access. But with AWS Service integration, you actually specify which IAM role API Gateway should use to invoke the Lambda. This makes sense to me, because how would a service like API Gateway know which IAM role to use to invoke a Lambda? Yet there is no way to choose an IAM role when using the Lambda function integration. Or is there…


Cross-posted on: https://forums.aws.amazon.com/message.jspa?messageID=844660#844660

Best Answer

If I understood correctly. You are looking for IAM role to use in LambdaProxy integration. LambdaProxy does allow to use IAM role. Here is a snippet that I use:

Resources:
  APILambdaInvokeRole:
    Type: AWS::IAM::Role
    Properties:
      AssumeRolePolicyDocument:
        Version: 2012-10-17
        Statement:
          - Effect: Allow
            Principal:
              Service:
                - "apigateway.amazonaws.com"
            Action:
              - "sts:AssumeRole"
  APILambdaInvokePolicy:
    Type: AWS::IAM::Policy
    Properties:
      PolicyName: LambdaInvokePolicy
      PolicyDocument:
        Version: 2012-10-17
        Statement:
          - Effect: Allow
            Action: "lambda:InvokeFunction"
            Resource: "*"
      Roles:
        - !Ref APILambdaInvokeRole