It would be really helpful if there were a documented set of permissions necessary for sam package and sam deploy to work. We're slowly adding permissions to our deploy role until we get a success.
+1
Due to the complex security structure of AWS (which I personally am a fan of), this becomes a bottleneck when trying to adopt SAM in our development teams. Our development roles are defined by security, and it would be far easier to work with them with a preexisting list of permissions needed rather than having to go back-and-forth.
Any news on this?
FWIW, here's what I used (as part of a role definition in my SAM template) to get this working today (it was a pain to iterate to get to this, so hopefully it'll help someone here). See notes below.
AdditionalPermissionPolicy:
Type: "AWS::IAM::Policy"
Properties:
PolicyName: "root"
PolicyDocument:
Version: "2012-10-17"
Statement:
-
Effect: "Allow"
Action:
- "s3:PutObject"
- "s3:GetObject"
- "s3:CreateMultipartUpload"
Resource:
- "arn:aws:s3:::{BUCKET_NAME}"
- "arn:aws:s3:::{BUCKET_NAME}/*"
-
Effect: "Allow"
Action:
- "cloudformation:DescribeStacks"
- "cloudformation:CreateChangeSet"
- "cloudformation:ExecuteChangeSet"
- "cloudformation:DescribeChangeSet"
Resource:
- !Sub "arn:aws:cloudformation:${AWS::Region}:${AWS::AccountId}:stack/{STACK_NAME}/*"
- "arn:aws:cloudformation:us-east-1:aws:transform/Serverless-2016-10-31"
-
Effect: "Allow"
Action:
- "cloudformation:GetTemplateSummary"
Resource: "*"
-
Effect: "Allow"
Action:
- "iam:GetRole"
Resource:
- !Sub "arn:aws:iam::${AWS::AccountId}:role/{STACK_NAME}-{FUNCTION_NAME}Role-*"
-
Effect: "Allow"
Action:
- "lambda:UpdateFunctionCode"
- "lambda:ListTags"
- "lambda:TagResource"
- "lambda:UntagResource"
- "lambda:GetFunctionConfiguration"
Resource:
- !Sub "arn:aws:lambda:${AWS::Region}:${AWS::AccountId}:function:{STACK_NAME}-{FUNCTION_NAME}-*"
Notes:
{BUCKET_NAME} with the bucket name you're using for code upload{STACK_NAME} with your stack name (see below){FUNCTION_NAME} with your function name; this is FirstFunction by default in the python cookiecutter template{STACK_NAME} instead of ${AWS::StackName}, but you can probably use that+1 for this. Piecemealing through which roles to assign is becoming a grueling process and involves us going to the infosec team again and again for approvals. There's got to be a better way.
how on Earth is this NOT documented _anywhere_?!?!?! I've spent the entire day trying to figure out what permissions need to be added to even run the samples provided in this repo:
First, I couldn't create the bucket from the CLI, so I had to login and make a bucket and get those permissions correct....then this:
~/repos/github/my-project [master ?]> sam deploy --template-file serverless-output.yml --stack-name my-stack --capabilities CAPABILITY_IAM
An error occurred (AccessDenied) when calling the DescribeStacks operation: User: <my-user> is not authorized to perform: cloudformation:DescribeStacks on resource: <my-stack>
How on earth is anyone supposed to figure this all out. PLEASE....at least provided the details needed to even run the examples....
@scoates Awesome, awesome job. Thanks for tackling this before I spent my afternoon or longer on it.
I ended up having to add lambda:ListVersionsByFunction, lambda:UpdateAlias and lambda:PublishVersion for arn:aws:lambda:${AWS::Region}:${AWS::AccountId}:function:[function_name] as well, in case that helps anyone.
Ohhh. This was annoying...
My set of permissions.
CIInstanceRole - a role that is attached to the EC2 instance where the CI is running. Must be assumed by the CI Job. Replace {ACCOUNT} with your number.
{
"Version": "2012-10-17",
"Statement": [
{
"Effect": "Allow",
"Action": [
"cloudformation:DescribeStacks",
"cloudformation:CreateChangeSet",
"cloudformation:ExecuteChangeSet",
"cloudformation:DescribeChangeSet"
],
"Resource": [
"arn:aws:cloudformation:us-east-1:aws:transform/Serverless-2016-10-31",
"arn:aws:cloudformation:*:*:stack/*/*"
]
},
{
"Effect": "Allow",
"Action": [
"cloudformation:GetTemplateSummary"
],
"Resource": "*"
},
{
"Sid": "PassRoleToSAM",
"Effect": "Allow",
"Action": [
"iam:PassRole"
],
"Resource": "arn:aws:iam::{ACCOUNT}:role/CICloudFormationSharedDeploymentRole"
}
]
}
CICloudFormationSharedDeploymentRole - a CI role that must be passed with --role-arn arn:aws:iam::{ACCOUNT}:role/CICloudFormationSharedDeploymentRole. Pay attention that iam:PassRole is configured for this resource in the role above.
This does not include API Gateway and DynamoDB permissions, add them if you need.
Replace {SAM_S3_BUCKET}, SAM_STACK_NAME with your number.
{
"Version": "2012-10-17",
"Statement": [
{
"Effect": "Allow",
"Action": [
"s3:PutObject",
"s3:GetObject"
],
"Resource": [
"arn:aws:s3:::{SAM_S3_BUCKET}",
"arn:aws:s3:::{SAM_S3_BUCKET}/*"
]
},
{
"Effect": "Allow",
"Action": [
"cloudformation:DescribeStacks",
"cloudformation:CreateChangeSet",
"cloudformation:ExecuteChangeSet",
"cloudformation:DescribeChangeSet"
],
"Resource": [
"arn:aws:cloudformation:us-east-1:aws:transform/Serverless-2016-10-31",
"arn:aws:cloudformation:*:*:stack/{SAM_STACK_NAME}/*"
]
},
{
"Effect": "Allow",
"Action": [
"cloudformation:GetTemplateSummary"
],
"Resource": "*"
},
{
"Effect": "Allow",
"Action": [
"iam:GetRole",
"iam:CreateRole",
"iam:PassRole",
"iam:DeleteRole",
"iam:GetRolePolicy",
"iam:PutRolePolicy",
"iam:AttachRolePolicy",
"iam:DetachRolePolicy",
"iam:DeleteRolePolicy",
"iam:TagRole",
"iam:UntagRole"
],
"Resource": [
"arn:aws:iam::*:role/{SAM_STACK_NAME}-*"
]
},
{
"Effect": "Allow",
"Action": [
"events:*"
],
"Resource": [
"arn:aws:events:*:*:rule/{SAM_STACK_NAME}-*"
]
},
{
"Effect": "Allow",
"Action": [
"lambda:*"
],
"Resource": [
"arn:aws:lambda:*:*:function:{SAM_STACK_NAME}-*"
]
}
]
}
Some permissions raise questions, i.e "iam:PassRole" for role/{SAM_STACK_NAME}-*, but id didn't work without it. Also I had to add deleting permissions in case of the stack failure.
The role must also have Trust relationship configured as in the example so CI can pass the CICloudFormationSharedDeploymentRole to SAM:
{
"Version": "2012-10-17",
"Statement": [
{
"Effect": "Allow",
"Principal": {
"AWS": "arn:aws:iam::{ACCOUNT}:role/CIInstanceRole"
},
"Action": "sts:AssumeRole"
},
{
"Effect": "Allow",
"Principal": {
"Service": "cloudformation.amazonaws.com"
},
"Action": "sts:AssumeRole"
}
]
}
And the SAM command example:
sam deploy \
--region us-east-1 \
--stack-name {SAM_STACK_NAME} \
--s3-bucket {SAM_S3_BUCKET} \
--s3-prefix {SAM_STACK_NAME} \
--tags Creator=sam sam=Owned \
--template-file packaged.yaml \
--capabilities CAPABILITY_IAM \
--role-arn arn:aws:iam::{ACCOUNT}:role/CICloudFormationSharedDeploymentRole \
--no-fail-on-empty-changeset
Hey, some additional permissions that I found missing:
API Gateway:
Action = [
"apigateway:GET",
"apigateway:PATCH",
"apigateway:POST",
"apigateway:PUT"
]
Lambda:
Action = [
"lambda:CreateFunction",
"lambda:AddPermission"
]
Hello guys, I had to also add s3:ListBucket
Another one to allow: cloudformation:DescribeStackEvents, not to be confused with DescribeStacks
Does no one else have concerns over the need to pass this:
{
"Effect": "Allow",
"Action": [
"iam:GetRole",
"iam:CreateRole",
"iam:PassRole",
"iam:DeleteRole",
"iam:GetRolePolicy",
"iam:PutRolePolicy",
"iam:AttachRolePolicy",
"iam:DetachRolePolicy",
"iam:DeleteRolePolicy",
"iam:TagRole",
"iam:UntagRole"
],
"Resource": [
"arn:aws:iam::*:role/{SAM_STACK_NAME}-*"
]
},
To automate this would mean granting permissions to an entity to create a new role with any set of permissions in it, which is a bit of a no-go for me.
I suspect there might be a way around this with permissions boundaries, but for the life of me I haven't been able to figure it out as yet.
I had managed to avoid the issue of PutRolePolicy and AttachRolePolicy (just for function code deployments) prior to adding a PreTrafficHook, but after doing so they appear to be required, so I'm a bit stuck.
So for some context on those permissions, if you're creating IAM roles, you need to have the necessary permissions, and they are powerful permissions to have. If you want to get around this, there are two approaches:
- Action:
- iam:AttachRolePolicy
- iam:CreateRole
- iam:DeleteRolePolicy
- iam:DetachRolePolicy
Effect: Allow
Resource: '*'
Condition:
StringEquals:
iam:PermissionsBoundary: !Sub 'arn:${AWS::Partition}:iam::${AWS::AccountId}:policy/my-app-${AWS::Region}-PermissionsBoundary'
That way, an IAM role can only be created if the permissions boundary you specify is included with it, and SAM provides a field to easily include this.
In any case, either of those workarounds should help you reduce the necessary permissions scope as you develop your applications further.
So far this policy is the smallest policy I managed to get sam deploy to release a new version of Lambda, YMMV! Not sure if it can be done with a smaller policy though ¯_(ツ)_/¯
{
"Version": "2012-10-17",
"Statement": [
{
"Sid": "IAM",
"Effect": "Allow",
"Action": [
"iam:GetRole",
"iam:PassRole"
],
"Resource": [
"arn:aws:iam::{ACCOUNT_ID}:role/{LAMBDA_ROLE}"
]
},
{
"Sid": "S3",
"Effect": "Allow",
"Action": [
"s3:PutObject",
"s3:GetObject"
],
"Resource": [
"arn:aws:s3:::{SAM_S3_BUCKET}/*"
]
},
{
"Sid": "Lambda",
"Effect": "Allow",
"Action": [
"lambda:UpdateFunctionCode",
"lambda:UpdateFunctionConfiguration",
"lambda:TagResource",
"lambda:ListTags",
"lambda:GetFunctionConfiguration",
"lambda:UntagResource"
],
"Resource": [
"arn:aws:lambda:*:{ACCOUNT_ID}:function:{LAMBDA}"
]
},
{
"Sid": "CloudFormation",
"Effect": "Allow",
"Action": "cloudformation:*",
"Resource": [
"arn:aws:cloudformation:*:{ACCOUNT_ID}:stack/{LAMBDA_STACK}/*",
"arn:aws:cloudformation:*:{ACCOUNT_ID}:stack/{SAM_MANAGED_STACK}/*",
"arn:aws:cloudformation:us-west-2:aws:transform/Serverless-2016-10-31"
]
}
]
}
If you use Lambda layers (to extract dependencies, etc):
-
Effect: "Allow"
Action:
- "lambda:PublishLayerVersion"
- "lambda:GetLayerVersion"
- "lambda:DeleteLayerVersion" # Required for Lambda upgrades
Resource:
- !Sub "arn:aws:lambda:${AWS::Region}:${AWS::AccountId}:layer:${LayerName}"
- !Sub "arn:aws:lambda:${AWS::Region}:${AWS::AccountId}:layer:${LayerName}:*"
If you use 3rd party layers (like for monitoring systems):
-
Effect: "Allow"
Action:
- "lambda:GetLayerVersion"
Resource:
- !Sub "arn:aws:lambda:${AWS::Region}:464622532012:layer:Datadog-*:*"
To bind Lambda to some source like SQS queue (but usually it is required for first deploy only):
-
Action:
- "lambda:CreateEventSourceMapping"
- "lambda:GetEventSourceMapping"
Effect: Allow
Resource: '*'
That way, an IAM role can only be created if the permissions boundary you specify is included with it, and SAM provides a field to easily include this.
Damn, looks complicated! @awood45, can you please tell in more details how to do it? How permissions boundary should look like? I can't assemble this puzzle.
Most helpful comment
FWIW, here's what I used (as part of a role definition in my SAM template) to get this working today (it was a pain to iterate to get to this, so hopefully it'll help someone here). See notes below.
Notes:
{BUCKET_NAME}with the bucket name you're using for code upload{STACK_NAME}with your stack name (see below){FUNCTION_NAME}with your function name; this isFirstFunctionby default in the python cookiecutter template{STACK_NAME}instead of${AWS::StackName}, but you can probably use that