Navigation Menu

Skip to content

Instantly share code, notes, and snippets.

@bsamuel-ui
Last active June 5, 2019 17:20
Show Gist options
  • Star 8 You must be signed in to star a gist
  • Fork 4 You must be signed in to fork a gist
  • Save bsamuel-ui/df0eff41160243ca23a2bad58ac7b08f to your computer and use it in GitHub Desktop.
Save bsamuel-ui/df0eff41160243ca23a2bad58ac7b08f to your computer and use it in GitHub Desktop.
Cloudformation template to deploy permissions for deploying a serverless project.
AWSTemplateFormatVersion: 2010-09-09
Description: >
Constructs a managed IAM policy to deploy a serverless project.
This template assumes the stack is being deployed in the current region and account.
You can then attach this policy to other IAM objects, such as users or roles.
Based on the work done in: https://github.com/serverless/serverless/issues/1439
Parameters:
UserName:
Description: >-
The name of the IAM User to construct.
Type: String
# From https://docs.aws.amazon.com/IAM/latest/APIReference/API_UpdateUser.html
AllowedPattern: '[A-Za-z0-9+=,.@-]+' #'
Service:
Description: >-
A name for this serverless service.
Type: String
Stage:
Description: >-
The stage for this project.
Type: String
MayInvoke:
Description: >-
Allow the constructed user to invoke lambdas.
Type: String
AllowedValues: [allow, deny]
Default: deny
MayDeployFunction:
Description: >-
Allow the user to deploy a single function. This is ignored if you don't create a CfnRole.
Type: String
AllowedValues: [allow, deny]
Default: allow
CreateCfnRole:
Description: >-
Create a role to assign to the `provider.cfnRole` variable, rather than rely on the user's permissions.
Type: String
AllowedValues: [create, skip]
Default: skip
Conditions:
AllowInvoke: !Equals [!Ref MayInvoke, allow]
UserFullPermissions: !Or [!Equals [!Ref MayDeployFunction, allow], !Equals [!Ref CreateCfnRole, ignore]]
CreateCfnRole: !Equals [!Ref CreateCfnRole, create]
Resources:
DeployUser:
Type: AWS::IAM::User
Properties:
UserName: !Ref UserName
Policies: [] # Prefer managing policies separately.
CfnRole:
Condition: CreateCfnRole
Type: AWS::IAM::Role
Properties:
Policies: []
AssumeRolePolicyDocument:
Version: 2012-10-17
Statement:
- Effect: Allow
Principal:
Service:
- !Sub 'cloudformation.${AWS::URLSuffix}'
Action:
- sts:AssumeRole
DeployPolicy:
# Cumulative inline policy size cannot exceed 2,048 characters for IAM Users.
# Cloudformation will hang waiting for an update exceeding this amount to complete.
# https://docs.aws.amazon.com/IAM/latest/UserGuide/reference_iam-limits.html
Type: AWS::IAM::ManagedPolicy
Properties:
Users:
- !Ref DeployUser
ManagedPolicyName: !Sub '${Service}-${Stage}-DeployPolicy'
PolicyDocument:
Version: 2012-10-17
Statement:
- Sid: ListDeploymentBucket
Effect: Allow
Action:
- s3:GetBucketLocation
- s3:ListBucket
Resource:
# See https://docs.aws.amazon.com/AmazonS3/latest/dev/s3-arn-format.html
# Also https://docs.aws.amazon.com/govcloud-us/latest/UserGuide/using-govcloud-arns.html
- !Sub 'arn:${AWS::Partition}:s3:::${Service}-${Stage}-serverlessdeploymentbucket-*'
- Sid: ReadWriteAccessToDeploymentObjects
Effect: Allow
Action:
- s3:GetObject*
- s3:PutObject
- s3:DeleteObject
Resource:
- !Sub 'arn:${AWS::Partition}:s3:::${Service}-${Stage}-serverlessdeploymentbucket-*/*'
- Sid: ValidateTemplate
Effect: Allow
Action:
- cloudformation:ValidateTemplate
Resource: '*'
- Sid: ReadAccessToCloudFormation
Effect: Allow
Action:
- cloudformation:Describe*
- cloudformation:List*
- cloudformation:Get*
- cloudformation:PreviewStackUpdate
Resource:
# https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/using-iam-template.html
- !Sub 'arn:${AWS::Partition}:cloudformation:${AWS::Region}:${AWS::AccountId}:stack/${Service}-${Stage}/*'
- Sid: WriteAccessToCloudFormation
Effect: Allow
Action:
- cloudformation:CreateStack
- cloudformation:UpdateStack
- cloudformation:DeleteStack
Resource:
- !Sub 'arn:${AWS::Partition}:cloudformation:${AWS::Region}:${AWS::AccountId}:stack/${Service}-${Stage}/*'
- Sid: GetLambdaRole
Effect: Allow
Action:
- iam:GetRole
Resource:
- !Sub 'arn:${AWS::Partition}:iam::${AWS::AccountId}:role/${Service}-${Stage}-${AWS::Region}-lambdaRole'
DeployViaRole:
Condition: CreateCfnRole
Type: AWS::IAM::Policy
Properties:
Users:
- !Ref DeployUser
PolicyName: !Sub '${Service}-${Stage}-DeployViaRole'
PolicyDocument:
Version: 2012-10-17
Statement:
- Sid: PassRoleToCloudFormation
Effect: Allow
Action:
- iam:PassRole
Resource:
- !GetAtt CfnRole.Arn
UpdateServicePolicy:
Type: AWS::IAM::ManagedPolicy
Properties:
Users:
- !If [UserFullPermissions, !Ref DeployUser, !Ref 'AWS::NoValue']
Roles:
- !If [CreateCfnRole, !Ref CfnRole, !Ref 'AWS::NoValue']
ManagedPolicyName: !Sub '${Service}-${Stage}-UpdateServicePolicy'
PolicyDocument:
Version: 2012-10-17
Statement:
- Sid: DropDeploymentBucket
Effect: Allow
Action:
- s3:DeleteBucket
Resource:
- !Sub 'arn:${AWS::Partition}:s3:::${Service}-${Stage}-serverlessdeploymentbucket-*'
- Sid: ReadAccessToDeploymentObjects
Effect: Allow
Action:
- s3:GetObject*
Resource:
- !Sub 'arn:${AWS::Partition}:s3:::${Service}-${Stage}-serverlessdeploymentbucket-*/*'
- Sid: Lambdas
Effect: Allow
Action:
- lambda:Get*
- lambda:List*
- lambda:UpdateFunctionCode
- lambda:UpdateFunctionConfiguration
- lambda:PublishVersion
- lambda:CreateAlias
- lambda:DeleteAlias
- lambda:UpdateAlias
- lambda:AddPermission
Resource:
- !Sub 'arn:${AWS::Partition}:lambda:${AWS::Region}:${AWS::AccountId}:function:${Service}-${Stage}*'
- Sid: CloudwatchEvents
Effect: Allow
Action:
- events:Put*
- events:Remove*
- events:Delete*
- events:Describe*
Resource:
- !Sub 'arn:${AWS::Partition}:events:${AWS::Region}:${AWS::AccountId}:rule/${Service}-${Stage}*'
- Sid: CloudwatchLogs
Effect: Allow
Action:
- logs:CreateLogGroup
- logs:CreateLogStream
- logs:DeleteLogGroup
- logs:DeleteLogStream
- logs:DescribeLogStreams
- logs:FilterLogEvents
Resource:
- !Sub 'arn:${AWS::Partition}:logs:${AWS::Region}:${AWS::AccountId}:log-group:/aws/lambda/${Service}-${Stage}*:log-stream:*'
- Sid: CloudwatchLogGroups
Effect: Allow
Action:
- logs:DescribeLogGroups
Resource:
- !Sub 'arn:${AWS::Partition}:logs:${AWS::Region}:${AWS::AccountId}:log-group::log-stream:*'
- Sid: IamRole
Effect: Allow
Action:
- iam:GetRole
- iam:PassRole
- iam:CreateRole
- iam:DeleteRole
- iam:DetachRolePolicy
- iam:PutRolePolicy
- iam:AttachRolePolicy
- iam:DeleteRolePolicy
Resource:
- !Sub 'arn:${AWS::Partition}:iam::${AWS::AccountId}:role/${Service}-${Stage}-${AWS::Region}-lambdaRole'
ApiGwPolicy:
Type: AWS::IAM::Policy
Properties:
Users:
- !If [UserFullPermissions, !Ref DeployUser, !Ref 'AWS::NoValue']
Roles:
- !If [CreateCfnRole, !Ref CfnRole, !Ref 'AWS::NoValue']
PolicyName: !Sub '${Service}-${Stage}-ApiGwPolicy'
PolicyDocument:
Version: 2012-10-17
Statement:
- Sid: ApiGwEvents
Effect: Allow
Action:
- apigateway:GET
- apigateway:POST
- apigateway:PUT
- apigateway:DELETE
Resource:
- !Sub 'arn:${AWS::Partition}:apigateway:${AWS::Region}:::/restapis'
- !Sub 'arn:${AWS::Partition}:apigateway:${AWS::Region}:::/restapis/*'
InvokeLambdaPolicy:
Condition: AllowInvoke
Type: AWS::IAM::Policy
Properties:
Users:
- !Ref DeployUser
PolicyName: !Sub '${Service}-${Stage}-InvokeLambdaPolicy'
PolicyDocument:
Version: 2012-10-17
Statement:
- Sid: InvokeFunction
Effect: Allow
Action:
- lambda:InvokeFunction
Resource:
- !Sub 'arn:${AWS::Partition}:lambda:${AWS::Region}:${AWS::AccountId}:function:${Service}-${Stage}*'
Outputs:
cfnRole:
Description: 'The `provider.cfnRole` value to use, or empty string if no role was created.'
Value: !If [CreateCfnRole, !GetAtt CfnRole.Arn, '']
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment