I have a IAM policy which fails to deploy using the Serverless Framework. The error message is (Service: AmazonIdentityManagement; Status Code: 400; Error Code: MalformedPolicyDocument;). The policy looks like this:
DtcServiceFunctionRole:
Type: AWS::IAM::Role
Properties:
Path: "/"
RoleName: DtcServiceFunctionRole
AssumeRolePolicyDocument:
Version: '2012-10-17'
Statement:
- Effect: Allow
Principal:
Service:
- lambda.amazonaws.com
Action: sts:AssumeRole
Policies:
- PolicyName: dtc-invoke-policy
PolicyDocument:
Version: '2012-10-17'
Statement:
- Effect: Allow
Action:
- "lambda:InvokeFunction"
Resource:
- "arn:aws:lambda:us-east-1:xxxxxxxxxxxxx:function:NotificationServiceFunction"
- PolicyName: dtc-dynamodb-policy
PolicyDocument:
Version: '2012-10-17'
Statement:
- Effect: Allow
Action:
- "dynamodb:BatchGetItem"
- "dynamodb:BatchWriteItem"
- "dynamodb:DeleteItem"
- "dynamodb:GetItem"
- "dynamodb:PutItem"
- "dynamodb:Query"
- "dynamodb:Scan"
- "dynamodb:UpdateItem"
Resource:
- "arn:aws:dynamodb:us-east-1:xxxxxxxxxxxxx:table/VehicleDtcTable"
- "arn:aws:dynamodb:us-east-1:xxxxxxxxxxxxx:table/DtcTable"
- Effect: Allow
Any help to point me in the right direction is appreciated. Thanks.
It looks like your yaml is not correctly indented at :
Statement:
- Effect: Allow
Action:
- "dynamodb:BatchGetItem"
- "dynamodb:BatchWriteItem"
- "dynamodb:DeleteItem"
- "dynamodb:GetItem"
- "dynamodb:PutItem"
- "dynamodb:Query"
- "dynamodb:Scan"
- "dynamodb:UpdateItem"
it should be:
DtcServiceFunctionRole:
Type: AWS::IAM::Role
Properties:
Path: "/"
RoleName: DtcServiceFunctionRole
AssumeRolePolicyDocument:
Version: '2012-10-17'
Statement:
- Effect: Allow
Principal:
Service:
- lambda.amazonaws.com
Action: sts:AssumeRole
Policies:
- PolicyName: dtc-invoke-policy
PolicyDocument:
Version: '2012-10-17'
Statement:
- Effect: Allow
Action:
- "lambda:InvokeFunction"
Resource:
- "arn:aws:lambda:us-east-1:xxxxxxxxxxxxx:function:NotificationServiceFunction"
- PolicyName: dtc-dynamodb-policy
PolicyDocument:
Version: '2012-10-17'
Statement:
- Effect: Allow
Action:
- "dynamodb:BatchGetItem"
- "dynamodb:BatchWriteItem"
- "dynamodb:DeleteItem"
- "dynamodb:GetItem"
- "dynamodb:PutItem"
- "dynamodb:Query"
- "dynamodb:Scan"
- "dynamodb:UpdateItem"
Resource:
- "arn:aws:dynamodb:us-east-1:xxxxxxxxxxxxx:table/VehicleDtcTable"
- "arn:aws:dynamodb:us-east-1:xxxxxxxxxxxxx:table/DtcTable"
- Effect: Allow
Related
I need to add a managed policy to a large number of lambda and ecs task roles across many cloudformation yaml files. Some of them already have this array field with items in it while some do not. I need to add an item to the ManagedPolicyArns array field where that item contains cloudformation shorthand such as !Sub. I'm using yq, which is a fantastic tool, but I can't figure out handling this shorthand using the docs.
cloudformation.yaml:
AWSTemplateFormatVersion: "2010-09-09"
Parameters:
MyPrefix:
Description: MyPrefix
Type: String
Resources:
MyRole:
Type: AWS::IAM::Role
Properties:
ManagedPolicyArns:
- Fn::ImportValue: !Sub "${MyPrefix}-my-policy-arn"
AssumeRolePolicyDocument:
Version: '2012-10-17'
Statement:
- Effect: Allow
Principal:
Service:
- ecs-tasks.amazonaws.com
- lambda.amazonaws.com
Action:
- sts:AssumeRole
- sts:TagSession
Path: /
Expected output .yaml:
AWSTemplateFormatVersion: "2010-09-09"
Parameters:
MyPrefix:
Description: MyPrefix
Type: String
Resources:
MyRole:
Type: AWS::IAM::Role
Properties:
ManagedPolicyArns:
- Fn::ImportValue: !Sub "${MyPrefix}-my-policy-arn"
- Fn::ImportValue: !Sub "${MyPrefix}-my-new-policy-arn"
AssumeRolePolicyDocument:
Version: '2012-10-17'
Statement:
- Effect: Allow
Principal:
Service:
- ecs-tasks.amazonaws.com
- lambda.amazonaws.com
Action:
- sts:AssumeRole
- sts:TagSession
Path: /
My failed attempt:
add_policy.yq:
( .Resources[] |=
select(.Properties.AssumeRolePolicyDocument.Statement[].Principal.Service.[] == "ecs-tasks.amazonaws.com" or .Properties.AssumeRolePolicyDocument.Statement[].Principal.Service.[] == "lambda.amazonaws.com")
.Properties.ManagedPolicyArns += {"Fn::ImportValue": {"!Sub": "${MyPrefix}-my-new-policy-arn"} }
)
command:
yq --from-file add_policy.yq cloudformation.yaml
which outputs:
AWSTemplateFormatVersion: "2010-09-09"
Parameters:
MyPrefix:
Description: MyPrefix
Type: String
Resources:
MyRole:
Type: AWS::IAM::Role
Properties:
ManagedPolicyArns:
- Fn::ImportValue: !Sub "${MyPrefix}-my-policy-arn"
- Fn::ImportValue:
'!Sub': ${MyPrefix}-my-new-policy-arn
AssumeRolePolicyDocument:
Version: '2012-10-17'
Statement:
- Effect: Allow
Principal:
Service:
- ecs-tasks.amazonaws.com
- lambda.amazonaws.com
Action:
- sts:AssumeRole
- sts:TagSession
Path: /
How do I get
- Fn::ImportValue: !Sub "${MyPrefix}-my-policy-arn"
- Fn::ImportValue: !Sub "${MyPrefix}-my-new-policy-arn"
instead of
- Fn::ImportValue: !Sub "${MyPrefix}-my-policy-arn"
- Fn::ImportValue:
'!Sub': ${MyPrefix}-my-new-policy-arn
?
Use the tag operator
add_policy.yq:
( .Resources[] |=
select(.Properties.AssumeRolePolicyDocument.Statement[].Principal.Service.[] == "ecs-tasks.amazonaws.com" or .Properties.AssumeRolePolicyDocument.Statement[].Principal.Service.[] == "lambda.amazonaws.com")
.Properties.ManagedPolicyArns += {"Fn::ImportValue": "${AuthAuditBucketStackName}-logging-policy-arn" | . tag = "!Sub" }
)
results in:
- Fn::ImportValue: !Sub "${MyPrefix}-my-policy-arn"
- Fn::ImportValue: !Sub ${MyPrefix}-my-new-policy-arn
Now I'm not sure why the string value isn't quoted.
I have a situation:
Resources:
- ${file(resources/default-role.yml)}
- ${file(resources/secondary-role.yml)}
where default-role.yml:
Resources:
DefaultRoleForLambdas:
Type: AWS::IAM::Role
Properties:
RoleName: defaultRoleForLambdas
AssumeRolePolicyDocument:
Version: "2012-10-17"
Statement:
- Effect: Allow
Principal:
Service:
- lambda.amazonaws.com
Action: sts:AssumeRole
ManagedPolicyArns:
- arn:aws:iam::aws:policy/service-role/AWSLambdaVPCAccessExecutionRole
Policies:
- PolicyName: defaultPolicyForLambdas
PolicyDocument:
Version: "2012-10-17"
Statement:
- ${file(iam/s3-iam.yml):S3Policies}
- ${file(iam/dynamodb-iam.yml):DynamoDbPolicies}
So this would be my default role for provider iam roles.
In serverless:
iam:
role: DefaultRoleForLambdas
But I want to have some functions with role that have those 2 basic privileges + some others, so in secondary-role I have. I overwrite that role in this function:
handler: src/some-handler
role: SecondaryRoleForLambdas
Resources:
SecondaryRoleForLambdas:
Type: AWS::IAM::Role
Properties:
RoleName: secondaryRoleForLambdas
AssumeRolePolicyDocument:
Version: "2012-10-17"
Statement:
- Effect: Allow
Principal:
Service:
- lambda.amazonaws.com
Action: sts:AssumeRole
Policies:
- PolicyName: secondaryPolicyForLambdas
PolicyDocument:
Version: "2012-10-17"
Statement:
- ${file(iam/s3-iam.yml):S3Policies}
- ${file(iam/dynamodb-iam.yml):DynamoDbPolicies}
- ${file(iam/sqs-iam.yml):SqSPolicies}
For example sqs-iam.yml:
SqsIam:
Effect: Allow
Action:
- sqs:SendMessage
- sqs:ReceiveMessage
- sqs:DeleteMessage
- sqs:GetQueueAttributes
Resource:
- !Sub arn:aws:sqs:eu-west-1:${AWS::AccountId}:${self:service}-${self:provider.stage}*
I think you get my point now. I tried to add many roles for functions but it is not possible in serverelss AFAIK. (So when I have a default role - with s3 and dynamodb , I am not able to assign 2 roles to functions, so that 1 particular function would end up having those 3 polices), thats why I had to create a seperate role and repeat my two default policies and add particular one.
I thought I could improve my solution by having sth like this, but it does not work:
default-role.yml:
...
Statement:
- ${file(iam/common-iam.yml)}
secondary-role.yml:
...
- ${file(iam/common-iam.yml)}
- $file{(iam/sqs-iam.yml)}
where iam/common-iam.yml:
- ${file(iam/s3-iam.yml)}
- ${file(iam/dynamodb-iam.yml)}
But it does not work? Any ideas if that is even possible.
I used this article to create my stack.
https://aws.amazon.com/blogs/infrastructure-and-automation/scheduling-automatic-deletion-of-aws-cloudformation-stacks/
But getting an error:
User:
arn:aws:sts::xxx:assumed-role/deleteCurrent-DeleteAfter-DeleteCFNLambdaExecution-T1WHQG2UTLWM/DeleteCFNLambda-deleteCurrent
is not authorized to perform: ssm:DeleteParameter on resource:
arn:aws:ssm:us-east-1:xxx:parameter/CFN-DemoParameter-plOl5Hg4QuI5
(Service: AmazonSSM; Status Code: 400; Error Code:
AccessDeniedException;
The template can be viewed here...
https://datameetgeobk.s3.amazonaws.com/cftemplates/delete_after_5m.template
Any suggestion to correct the error will be appreciated.
The error says that your lambda execution role does not have permissions to execute ssm:DeleteParameter role. Thus you can add the missing permission to the lambda role:
Resources:
DeleteCFNLambdaExecutionRole:
Type: "AWS::IAM::Role"
Properties:
AssumeRolePolicyDocument:
Version: "2012-10-17"
Statement:
- Effect: "Allow"
Principal:
Service: ["lambda.amazonaws.com"]
Action: "sts:AssumeRole"
Path: "/"
Policies:
- PolicyName: "lambda_policy"
PolicyDocument:
Version: "2012-10-17"
Statement:
- Effect: "Allow"
Action:
- "logs:CreateLogGroup"
- "logs:CreateLogStream"
- "logs:PutLogEvents"
Resource: "arn:aws:logs:*:*:*"
- Effect: "Allow"
Action:
- "cloudformation:DeleteStack"
Resource: !Sub "arn:aws:cloudformation:${AWS::Region}:${AWS::AccountId}:stack/${StackName}/*"
- Effect: "Allow"
Action:
- "ssm:DeleteParameter"
Resource: "*"
I am trying to create a parameter and would like to combine !Sub and !Import several times.
Parameters:
Environment:
Description: Stackname of Environment
Type: String
Resources:
IAMRole:
Type: AWS::IAM::Role
Properties:
AssumeRolePolicyDocument:
Statement:
- Effect: Allow
Principal:
Service: '*'
Action: ['sts:AssumeRole']
Path: /
Policies:
- PolicyName: S3Files
PolicyDocument:
Statement:
- Sid: 'S3Files'
Effect: Allow
Action:
- 's3:DeleteObjectTagging'
- 's3:GetObjectRetention'
- 's3:ListMultipartUploadParts'
- 's3:PutObject'
- 's3:GetObjectAcl'
- 's3:GetObject'
- 's3:AbortMultipartUpload'
- 's3:PutObjectRetention'
- 's3:GetObjectVersionAcl'
- 's3:GetObjectTagging'
- 's3:PutObjectTagging'
- 's3:DeleteObject'
- 's3:PutObjectAcl'
- 's3:GetObjectVersion'
Resource: !Sub
- '${ARN}/*'
- ARN:
Fn::ImportValue: !Sub ${Environment}:S3:Arn
According to the documentation it should be possible, but unfortunately I always get an error message
Template contains errors.: [/Resources/IAMRole/Type/Policies/0/PolicyDocument/Statement/0/Resource/Fn::Sub/1/ARN] 'null' values are not allowed in templates
How could the UseCase work?
There is a space issue in the Resource section.
Resource: !Sub
- '${ARN}/*'
- ARN:
Fn::ImportValue: !Sub ${Environment}:S3:Arn
It should be
Resource: !Sub
- '${ARN}/*'
- ARN:
Fn::ImportValue: !Sub ${Environment}:S3:Arn
Note: Fn starts under N of ARN instead of A.
Explanation: With the first indentation the line with Fn::ImportValue is considered as an input for !Sub, with the second indentation it becomes the value for ARN: defined the line above it.
Side note: Use 2 spaces or 4 spaces or tabs uniformly throughout the template.
In cloud-trail, I can select the existing log group CloudTrail/DefaultLogGroup under CloudWatch Logs section. Is it possible to complete this step using cloudformation Template?
Assuming you are creating the log group with CloudFormation as well:
LogGroup: # A new log group
Type: AWS::Logs::LogGroup
Properties:
RetentionInDays: 365 # optional
CloudTrailLogsRole: # A role for your trail
Type: AWS::IAM::Role
Properties:
AssumeRolePolicyDocument:
Statement:
- Action: sts:AssumeRole
Effect: Allow
Principal:
Service: cloudtrail.amazonaws.com
Version: '2012-10-17'
CloudTrailLogsPolicy: # The policy for your role
Type: AWS::IAM::Policy
Properties:
PolicyDocument:
Statement:
- Action:
- logs:PutLogEvents
- logs:CreateLogStream
Effect: Allow
Resource:
Fn::GetAtt:
- LogGroup
- Arn
Version: '2012-10-17'
PolicyName: DefaultPolicy
Roles:
- Ref: CloudTrailLogsRole
CloudTrail: # The trail
Type: AWS::CloudTrail::Trail
Properties:
IsLogging: true
CloudWatchLogsLogGroupArn:
Fn::GetAtt:
- LogGroup
- Arn
CloudWatchLogsRoleArn:
Fn::GetAtt:
- CloudTrailLogsRole
- Arn
DependsOn:
- CloudTrailLogsPolicy
- CloudTrailLogsRole
If using an existing log group:
CloudTrailLogsRole: # A role for your trail
Type: AWS::IAM::Role
Properties:
AssumeRolePolicyDocument:
Statement:
- Action: sts:AssumeRole
Effect: Allow
Principal:
Service: cloudtrail.amazonaws.com
Version: '2012-10-17'
CloudTrailLogsPolicy: # The policy for your role
Type: AWS::IAM::Policy
Properties:
PolicyDocument:
Statement:
- Action:
- logs:PutLogEvents
- logs:CreateLogStream
Effect: Allow
Resource: <your existing log group arn here>
Version: '2012-10-17'
PolicyName: DefaultPolicy
Roles:
- Ref: CloudTrailLogsRole
CloudTrail: # The trail
Type: AWS::CloudTrail::Trail
Properties:
IsLogging: true
CloudWatchLogsLogGroupArn: <your existing log group arn here>
CloudWatchLogsRoleArn:
Fn::GetAtt:
- CloudTrailLogsRole
- Arn
DependsOn:
- CloudTrailLogsPolicy
- CloudTrailLogsRole