7

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?

petey
  • 16,914
  • 6
  • 65
  • 97
Niall Parker
  • 177
  • 7

3 Answers3

2

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.

Dennis Traub
  • 50,557
  • 7
  • 93
  • 108
  • Unfortunately I don't have dispensation to create custom managed policies to reference, otherwise I agree this would be cleaner. – Niall Parker Oct 25 '20 at 16:48
  • A `AWS::IAM::Policy` resource doesn't get included by being referenced. Rather, any number of roles can be specified under its `Roles:` property, which it will then be attached to. – webninja Sep 11 '21 at 10:53
  • 1
    I would say that this feels unintuitive (it seems like listing `!Ref`s to custom policies under a `Role` or `Function` definition would be appropriate. However, that functionality currently appears to be unavailable. – webninja Sep 11 '21 at 10:56
1

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'
petey
  • 16,914
  • 6
  • 65
  • 97
  • Thanks this is exactly what I was looking for! – Niall Parker Oct 25 '20 at 16:47
  • 1
    I don't think this is possible - `Policies` is not supported in Globals: https://docs.aws.amazon.com/serverless-application-model/latest/developerguide/sam-specification-template-anatomy-globals.html – Liam Hanninen Apr 29 '21 at 20:28
  • 1
    This does not work unfortunately: "samtranslator.plugins.globals.globals.InvalidGlobalsSectionException: ('Globals', "'Policies' is not a supported property of 'Function'. Must be one of the following values..." – Selçuk Cihan Sep 06 '21 at 10:02
  • This would attach those policies to every function in the stack (if it did work). – webninja Sep 11 '21 at 10:50
1

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
webninja
  • 118
  • 1
  • 7