Niall Parker
Niall Parker

Reputation: 207

AWS SAM Multiple Functions with same Inline Policy

In the AWS SAM .yaml template I can declare an inline policy for each lambda function like so:

AWSTemplateFormatVersion: '2010-09-09'
Transform: 'AWS::Serverless-2016-10-31'
Resources:
  MyFunction:
    Type: 'AWS::Serverless::Function'
    Properties:
      Handler: index.handler
      Runtime: nodejs8.10
      CodeUri: 's3://my-bucket/function.zip'
      Policies:
      - Statement:
        - Sid: SSMDescribeParametersPolicy
          Effect: Allow
          Action:
          - ssm:DescribeParameters
          Resource: '*'
        - Sid: SSMGetParameterPolicy
          Effect: Allow
          Action:
          - ssm:GetParameters
          - ssm:GetParameter
          Resource: '*'

However if I want multiple functions to share the same inline policy document, do we declare it in the 'Globals' section of the template?

So far the documentation leads me to believe that the cleanest way to do this would be creating a role with the attached policies and simply declaring the role to each function instead like so:

AWSTemplateFormatVersion: '2010-09-09'
Transform: 'AWS::Serverless-2016-10-31'
Resources: 
  MyFunction:
    Type: 'AWS::Serverless::Function' 
    Properties:
      Handler: index.handler
      Runtime: nodejs8.10
      CodeUri: 's3://my-bucket/function.zip' 
      Role: arn:aws:iam::111111111111:role/SAMPolicy

Is there a way to declare an inline policy within the template and simply reference it on each function instead?

Upvotes: 9

Views: 2923

Answers (3)

codemutation
codemutation

Reputation: 178

What you want to do ought to work, but it currently doesn't.

What you can do is define a AWS::IAM::Role which can be assumed by one or more functions. Then define your AWS::IAM::Policy policies individually and apply each of them to one or more roles.

Function1:
  Type: AWS::Serverless::Function
  Properties:
    FunctionName: function-1
    CodeUri: functions/func-1
    Description: Does stuff with DynamoDB and calls another Lambda function
    Role: !GetAtt Role1.Arn
    Environment:
      Variables:
        TABLE_NAME: !Ref DynamoDBTable1

Function2:
  Type: AWS::Serverless::Function
  Properties:
    FunctionName: function-2
    CodeUri: functions/func-2
    Description: Does stuff with the main database
    Role: !GetAtt Role2.Arn
    Layers:
      - !Ref Libraries
    Environment:
      Variables:
        PGHOST: !GetAtt MainDB.Endpoint.Address
        PGPORT: !GetAtt MainDB.Endpoint.Port

Role1:
  Type: AWS::IAM::Role
  Properties:
    ManagedPolicyArns:
      - arn:aws:iam::aws:policy/service-role/AWSLambdaBasicExecutionRole
    AssumeRolePolicyDocument:
      Version: "2012-10-17"
      Statement:
        - Effect: Allow
          Principal:
            Service:
              - lambda.amazonaws.com
          Action:
            - sts:AssumeRole
    Policies:
      - PolicyName: allow-dynamodb-write
        PolicyDocument:
          Version: 2012-10-17
          Statement:
            - Action: dynamodb:PutItem
              Resource: !GetAtt EventTable.Arn
              Effect: Allow

Role2:
  Type: AWS::IAM::Role
  Properties:
    ManagedPolicyArns:
      - arn:aws:iam::aws:policy/service-role/AWSLambdaBasicExecutionRole
    AssumeRolePolicyDocument:
      Version: "2012-10-17"
      Statement:
        - Effect: Allow
          Principal:
            Service:
              - lambda.amazonaws.com
          Action:
            - sts:AssumeRole

AllowInvokeFunctionPolicy:
  Type: AWS::IAM::Policy
  Properties:
    PolicyName: allow-invoke-function
    PolicyDocument:
      Version: 2012-10-17
      Statement:
        - Action: lambda:InvokeFunction
          Resource: !GetAtt LogEventFunction.Arn
          Effect: Allow
    Roles:
      - Ref: Role1
        Ref: Role2

AllowDBAccessPolicy:
  Type: AWS::IAM::Policy
  Properties:
    PolicyName: allow-rds-connect
    PolicyDocument:
      Version: 2012-10-17
      Statement:
        - Action: rds-db:connect
          Resource: !Sub arn:aws:rds:${AWS::Region}:${AWS::AccountId}:db:${MainDB}
          Effect: Allow
    Roles:
      - Ref: Role2

Upvotes: 2

petey
petey

Reputation: 17170

If I want multiple functions to share the same inline policy document, do we declare it in the 'Globals' section of the template? Yes. Here is an example:

AWSTemplateFormatVersion: '2010-09-09'
Transform: 'AWS::Serverless-2016-10-31'

Globals:
  Function:
    Policies:
      - Statement:
          - Sid: SSMDescribeParametersPolicy
            Effect: Allow
            Action:
              - ssm:DescribeParameters
            Resource: '*'
          - Sid: SSMGetParameterPolicy
            Effect: Allow
            Action:
              - ssm:GetParameters
              - ssm:GetParameter
            Resource: '*'

Resources:
  MyFunction:
    Type: 'AWS::Serverless::Function'
    Properties:
      Handler: index.handler
      Runtime: nodejs8.10
      CodeUri: 's3://my-bucket/function.zip'
  MyOtherFunction:
    Type: 'AWS::Serverless::Function'
    Properties:
      Handler: index.handler
      Runtime: nodejs8.10
      CodeUri: 's3://my-bucket/other-function.zip'

Upvotes: 0

Dennis Traub
Dennis Traub

Reputation: 51684

An inline policy can’t be referenced and reused. However, you can create and reference an AWS Managed Policy or a SAM policy template instead of an inline policy.

If you want to use a reusable custom policy, you will have to create a Customer Managed Policy and attach to the Lambda functions via the Role property.

Upvotes: 2

Related Questions