I understand that SAM is built on top of CloudFormation, and there are some facilities within SAM to make it easier to construct the stack template.
I created a SAM Condition like:
Conditions:
ProductTag: !Equals
- 'aws:ResourceTag/Joba:Product'
- !Ref Product
EnvironmentTag: !Equals
- 'aws:ResourceTag/Joba:Environment'
- !Ref Environment
TagsPolicy: !And
- !Condition ProductTag
- !Condition EnvironmentTag
And I tried to reference the TagsPolicy in the AWS::IAM::Role policies (last line).
DownloadBrokerageNotesStateMachineExecutionRole:
Type: "AWS::IAM::Role"
Properties:
AssumeRolePolicyDocument:
Version: "2012-10-17"
Statement:
- Effect: "Allow"
Principal:
Service:
- !Sub states.${AWS::Region}.amazonaws.com
Action: "sts:AssumeRole"
Path: "/"
Policies:
- PolicyName: LambdaExecute
PolicyDocument:
Version: "2012-10-17"
Statement:
- Effect: Allow
Action:
- "lambda:InvokeFunction"
Resource:
- !GetAtt RicoRobotAuthenticateFunction.Arn
Condition: TagsPolicy
Running sam validate --link gives me:
template.yaml is a valid SAM Template. This is according to basic SAM Validation
W8001 Condition TagsPolicy not used.
But running sam deploy, throws the following error:
Syntax errors in policy. (Service: AmazonIdentityManagement; Status Code: 400; Error Code: MalformedPolicyDocument; Request ID: d215f541-4f16-4050-ac48-04bda830e9dc; Proxy: null)
The following resource(s) failed to create: [DownloadBrokerageNotesStateMachineExecutionRole]. Rollback requested by user.
How can I reference the TagsPolicy there?
The Condition key has several distinct usages in a template. You're mixing them up a bit.
The template's top-level Condition section defines rules governing the conditional creation of resources. The conditions are then optionally applied within resource definitions, also using the Condition key. CloudFormation evaluates these conditions at deploy-time, deploying only those resources where the condition is true. This isn't what you want.
IAM policy statements accept an optional, unrelated Condition element to narrow the policy's applicability. Define the policy conditions in the statement itself. The conditions are part of the policy definition and are applied at run-time when the policy is evaluated.
DownloadBrokerageNotesStateMachineExecutionRole:
Type: "AWS::IAM::Role"
# Meaning #1: Applies a defined condition. Role is created only if the condition is true.
# Not what you want
Condition: IsProduction
Properties:
AssumeRolePolicyDocument:
Version: "2012-10-17"
Statement:
- Effect: "Allow"
Principal:
Service:
- !Sub states.${AWS::Region}.amazonaws.com
Action: "sts:AssumeRole"
Path: "/"
Policies:
- PolicyName: LambdaExecute
PolicyDocument:
Version: "2012-10-17"
Statement:
- Effect: Allow
Action:
- "lambda:InvokeFunction"
Resource:
- !GetAtt RicoRobotAuthenticateFunction.Arn
# Meaning #2: Defines the conditions under which the IAM policy applies.
# This is what you want
Condition:
StringEquals:
"aws:ResourceTag/Joba:Product": !Ref Product
"aws:ResourceTag/Joba:Environment": !Ref Environment
Related
I was looking at the Condition Function Fn::If: to create or provision a resource only if a condition is evaluated to true. In my case, created a policy if the environment is prod.
Parameters:
Env:
Description: Environment
Type: String
Conditions:
IsProd: !Equals [!Ref Env, 'prod']
I know how to do it for a property, but not for the entire resource block.
Type: 'AWS::IAM::Policy'
Properties:
PolicyName: root
PolicyDocument:
Version: 2012-10-17
Statement:
- Effect: Allow
Action: '*'
Resource: '*'
Roles:
- !Ref RootRole
Is this something possible?
You can do it using Condition: resource attribute. For example:
Resources:
MyIAMPolicy:
Condition: IsProd
Type: 'AWS::IAM::Policy'
Properties:
PolicyName: root
PolicyDocument:
Version: 2012-10-17
Statement:
- Effect: Allow
Action: '*'
Resource: '*'
Roles:
- !Ref RootRole
More on this can be found here:
Conditionally launch AWS CloudFormation resources based on user input
I'm trying to launch a scheduled instance which will be stopped and start at a specified time in each day (in AWS CloudFormation template).
it's my IAM role and policy that I defined for the lambda function:
RootRole:
Type: 'AWS::IAM::Role'
Properties:
AssumeRolePolicyDocument:
Version: 2012-10-17
Statement:
- Effect: Allow
Action:
- logs:CreateLogGroup
- logs:CreateLogStream
- logs:PutLogEvents
Resource: arn:aws:logs:*:*:*
- Effect: Allow
Action:
- ec2:Start*
- ec2:Stop*
Resource: "*"
when I create a stack, it return an error in the console(CREATE_FAILED) and the status reason is:
Has prohibited field Resource (Service: AmazonIdentityManagement; Status Code: 400; Error Code: MalformedPolicyDocument; Request ID: 3094b9eb-9f45-4763-8f21-9c3f2496fc52)
And after this error all the services related to this role are failed by this error:
The following resource(s) failed to create: [InternetGateway, SNSTopicNameCreate, LambdaInvocationsAlarm, RootRole, VPC, LambdaInvocationsAnomalyDetector]. . Rollback requested by user.
Your policy appears to be confusing the "Assume Role" section, which defines the Trust Policy, with the "Policy" section, which grants permissions to the IAM Role.
Try this:
AWSTemplateFormatVersion: 2010-09-09
Resources:
LambdaRole:
Type: AWS::IAM::Role
Properties:
RoleName: Lambda-Role
AssumeRolePolicyDocument:
Version: 2012-10-17
Statement:
- Effect: Allow
Principal:
Service: lambda.amazonaws.com
Action: sts:AssumeRole
Policies:
- PolicyName: AllowLogsAndEC2
PolicyDocument:
Version: 2012-10-17
Statement:
- Effect: Allow
Action:
- logs:CreateLogGroup
- logs:CreateLogStream
- logs:PutLogEvents
Resource: arn:aws:logs:*:*:*
- Effect: Allow
Action:
- ec2:StartInstances
- ec2:StopInstances
Resource: "*"
Typically, the easiest way to create a policy is to copy an existing policy and make minor changes, or use the policy editor in the IAM console to generate most of what you want. You can then tweak the policy it provides.
I'm creating a CloudFormation stack that has a CodeBuild and an IAM role as a resource. I'd like to know if is there a condition that allows only resources created in the same stack to assume the role.
Currently, my stack is defined this way:
CodeBuildProjectIAMRole:
Type: AWS::IAM::Role
Properties:
AssumeRolePolicyDocument:
Version: '2012-10-17'
Statement:
- Effect: Allow
Principal:
Service: codebuild.amazonaws.com
Action: sts:AssumeRole
CodeBuildProject:
Type: AWS::CodeBuild::Project
The problem is that any CodeBuild project can assume the role above.
When I try to add a condition specifying that only principals with aws:cloudformation:stack-name equal stack name can assume the role:
CodeBuildProjectIAMRole:
Type: AWS::IAM::Role
Properties:
AssumeRolePolicyDocument:
Version: '2012-10-17'
Statement:
- Effect: Allow
Principal:
Service: codebuild.amazonaws.com
Action: sts:AssumeRole
Condition:
StringEquals:
aws:PrincipalTag/aws:cloudformation:stack-name: !Ref 'AWS::StackName'
, I get this error:
Condition can contain only one colon. (Service: AmazonIdentityManagement; Status Code: 400; Error Code: MalformedPolicyDocument)
Based on these docs I don't believe what you're trying to do is possible a this time.
Specifically:
You cannot limit permissions to pass a role based on tags attached to that role using the ResourceTag/key-name condition key
I am trying to define a trust relationship policy document between a role and a user in cloudformation (yaml).
For specifying the ARN of the user in the role's AssumeRolePolicyDocument, I want to reference the ARN from the actual cloudformation resource, instead of having to construct the ARN string.
But, it doesn't work. When I use !Ref rUser, I get an error when creating the cloudformation stack "invalid principal in policy".
When I just paste the ARN string as the value, it works. Is it because !Ref rUser returns a user object type and does not evaluate to a string? If so, how can I reference the ARN from the resource?
Code:
rUser:
Type: "AWS::IAM::User"
Properties:
UserName: "my_user"
rRole:
DependsOn: rRole
Type: "AWS::IAM::Role"
Properties:
RoleName: "my_role"
AssumeRolePolicyDocument:
Version: "2012-10-17"
Statement:
-
Effect: "Allow"
Principal:
AWS:
# this does not work, gives error "Invalid Principal in policy"
- !Ref rUser
# this does work (just hard coding the ARN string):
# - "arn:aws:iam::111111111111:user/my_user"
Action:
- "sts:AssumeRole"
Just figured it out ... quite simple using the GetAtt function:
rRole:
DependsOn: rRole
Type: "AWS::IAM::Role"
Properties:
RoleName: "my_role"
AssumeRolePolicyDocument:
Version: "2012-10-17"
Statement:
-
Effect: "Allow"
Principal:
AWS:
- !GetAtt rExternalUser.Arn # use the GetAtt function
Action:
- "sts:AssumeRole"
I have defined an IAM policy for Dynamodb cloud formation template as shown below, and I am getting the following error:
Value of property Users must be of type List of String
Any ideas what am I doing wrong?
myDynamoPolicy:
Type: AWS::IAM::Policy
Properties:
PolicyDocument:
Version: 2012-10-17
Statement:
Sid: AllAPIActionsOnBooks
Effect: Allow
Action: dynamodb:*
Resource:
Ref: myDynamoDBTable
PolicyName: DynamoDBOwnerPolicy
Users:
Ref: IAMUsers
Per AWS documentation, the Users property must be an array. It should look like this:
myDynamoPolicy:
Type: AWS::IAM::Policy
Properties:
PolicyDocument:
Version: 2012-10-17
Statement:
Sid: AllAPIActionsOnBooks
Effect: Allow
Action: dynamodb:*
Resource:
Ref: myDynamoDBTable
PolicyName: DynamoDBOwnerPolicy
Users:
-
Ref: "IAMUsers"
CloudFormation template reference can be found here.