AWS CFT template IAM Policy - amazon-web-services

I'm using CFT to create an IAM policy that allows access to only one S3 bucket alone (which is also created in the same CFT itself). Here is the part of the CFT where the problem lies
{
"AWSTemplateFormatVersion": "2010-09-09",
"Resources": {
"BucketCreation":{
"Type": "AWS::S3::Bucket",
"Properties": {
"BucketName":"samplebucket",
}
},
"IAMPolicy":{
"Type": "AWS::IAM::Policy",
"Properties": {
"PolicyName": "ListS3BucketsPolicy",
"PolicyDocument": {
"Statement": [{
"Effect": "Allow",
"Action": [
"s3:*"
],
"Resource": "Fn::GetAtt" : [ "BucketCreation" , "Arn" ]
}]
}
}
}
}
}
Now the above cft creates a IAM policy with a resource statement "Resource": "arn:aws:s3:::bucketname" well this gives only bucket access and not object level access. What I need is the resource section to look like this "Resource": "arn:aws:s3:::bucketname/*".Is this possible in CFT?

Yes you can, see here
You can use wildcards as part of the resource ARN. You can use
wildcard characters (* and ?) within any ARN segment (the parts
separated by colons). An asterisk (*) represents any combination of
zero or more characters, and a question mark (?) represents any single
character. You can use multiple * or ? characters in each segment, but
a wildcard cannot span segments.
This ARN uses the wildcard * in the relative-ID part of the ARN to
identify all objects in the example bucket.
Update:
To concatinate /* look at intrinsic functions like Join

Thanks to #titogeo. I've found the solution.Here it is
{
"AWSTemplateFormatVersion": "2010-09-09",
"Resources": {
"BucketCreation":{
"Type": "AWS::S3::Bucket",
"Properties": {
"BucketName":"samplebucket"
}
},
"IAMPolicy":{
"Type": "AWS::IAM::Policy",
"Properties": {
"PolicyName": "ListS3BucketsPolicy",
"PolicyDocument": {
"Statement": [{
"Effect": "Allow",
"Action": [
"s3:*"
],
"Resource":{
"Fn::Join":["",[
{
"Fn::GetAtt" : [ "BucketCreation" , "Arn" ]
},
"/*"
]
]
}
}]
}
}
}
}
}
P.S: Sorry for the poor indendation. I'm Frustrated with it, if someone could fix it, that would be helpful.

Related

AWS Role with a PolicyDocument assuming itself

I am trying to understand code written by coworker that has left.
Can anyone tell me why we have a Policy that assume the role it's attached too, what is it suppose to do?
{
"Role1": {
"Type": "AWS::IAM::Role",
"Properties": {
"AssumeRolePolicyDocument": {
"Version": "2012-10-17",
"Statement": [
{
"Action": "sts:AssumeRole",
"Effect": "Allow",
"Principal": {
"Service": "ec2.amazonaws.com"
}
}
]
},
"ManagedPolicyArns": [],
"Policies": []
},
"AssumeRolePermissions": {
"Type": "AWS::IAM::Policy",
"DependsOn": "Role1",
"Properties": {
"PolicyDocument": {
"Version": "2012-10-17",
"Statement": [
{
"Effect": "Allow",
"Action": "sts:AssumeRole",
"Resource": { "Fn::GetAtt": [ "Role1", "Arn" ] }
}
]
},
"PolicyName": "Assume_Role",
"Roles": [{ "Ref": "Role1" }]
}
}
}
}
I know a trust policy is useful in the case I want Role2 to assume Role1's permissions.
From the new update (https://aws.amazon.com/blogs/security/announcing-an-update-to-iam-role-trust-policy-behavior/) if seems in that case I need both of them in the trust policy but what if I don't do that, is there a use case for assuming its own role?
Thanks
"Role1": {
"Type": "AWS::IAM::Role",
"Properties": {
"AssumeRolePolicyDocument": {
"Version": "2012-10-17",
"Statement": [
{
"Action": "sts:AssumeRole",
"Effect": "Allow",
"Principal": {
"AWS": { "Fn::GetAtt": [ "Role1", "Arn" ] }
}
}
]
},
"ManagedPolicyArns": [],
"Policies": []
}
Thanks to #JohnRotenstein and AWS support:
A role assuming itself is a rare use case that while valid isn't an AWS best practice, with AWS recommending using multiple roles instead.
Some of these use cases involve self-assuming in conjunction with a 'scoped-down' policy to obtain a different privilege level, or using a single role and policy throughout the development => build => test => production environment, or can be used to rotate the access/secret keys used by the role since when you role chain the session only last one hour.
All that being said in the majority of cases a self assuming role is a step that depends on use case.

Custom resource name for IAM role defined in user-pool-group-precedence.json Amplify

I have an Amplify project and want to have a custom resource string per environment. For example I have the below defined in my user-pool-group-precedence.json file:
[{
"groupName": "example",
"precedence": 1,
"customPolicies": [
{
"PolicyName": "example-policy",
"PolicyDocument": {
"Version": "2012-10-17",
"Statement": [
{
"Sid": "Policy01",
"Action": ["s3:GetObject"],
"Resource": ["arn:aws:s3:::s3bucket-*/"],
"Effect": "Allow"
}
]
}
]
}]
I have multiple s3 buckets (1 per environment). For example s3bucket-dev and s3bucket-qa. Currently the above policy grants access to all my s3 buckets in different environments. How do I go about defining a single bucket per environment? Ideally I want something like
arn:aws:s3:::s3bucket-${aws:env}/
I looked at using conditions but was unsure how to implement them in order to achieve my goal.
Since this policy will be added to the amplify cloudformation template, Amplify already provides the parameter env in that target template. I suppose you will just have to reference it in your policy like this to make it dynamic as per your environment (Fn::Join does what you need):
[{
"groupName": "example",
"precedence": 1,
"customPolicies": [
{
"PolicyName": "example-policy",
"PolicyDocument": {
"Version": "2012-10-17",
"Statement": [
{
"Sid": "Policy01",
"Action": ["s3:GetObject"],
"Resource": {
"Fn::Join": [
"",
[
"arn:aws:s3:::s3bucket-",
{
"Ref": "env"
},
"/"
]
]
},
"Effect": "Allow"
}
]
}
]
}]

In CloudFormation, does "A DependsOn B" ensure that A is deleted before B?

We are using CloudFormation to set up a role and a policy for it. The policy is set to depend on the role using the "DependsOn" property like so:
Role definition:
"LambdaExecutionRole": {
"Type": "AWS::IAM::Role",
"Properties": {
[...]
Policy definition:
"lambdaexecutionpolicy": {
"DependsOn": [
"LambdaExecutionRole"
],
"Roles": [
{
"Ref": "LambdaExecutionRole"
}
],
[...]
From the official documentation, I understand that this DependsOn relation between the two entities should ensure that the policy is always deleted before the role.
Resource A is deleted before resource B.
However, we encounter an error where it appears that the system tries to delete the role before the policy:
Resource Name: [...] (AWS::IAM::Role)
Event Type: delete
Reason: Cannot delete entity, must delete policies first. (Service: AmazonIdentityManagement; Status Code: 409; Error Code: DeleteConflict; Request ID: [...]; Proxy: null)
I'm not sure how that's even possible, as I would have considered the "A DependsOn B" to ensure that the system never tries to delete B before deleting A. Is my understanding wrong here? Can there be a situation where the system tries to delete B before A?
And yes, I understand that in this case the obvious solution is to use an inline policy, as the policy is only used for this specific role. But as this behavior seems to conflict with my intuitive understanding of the official documentation, I want to properly understand what the "DependsOn" property actually means.
TL;DR Unable to replicate the error. DependsOn does not seem to be the culprit.
I used the CDK to create two versions of a minimum test stack with only two resources, AWS::IAM::Role and AWS::IAM::ManagedPolicy. V1 had no explicit policy dependency set on the role. V2, like the OP, did. The difference made no difference. Both versions deployed and were destroyed without error.
Version 1: CDK-Generated Default: no 'depends on' in the template
Version 2 (as in OP): has explicit dependency - Policy depends on the Role. The CDK added one line to the template: "DependsOn": [ "TestRole6C9272DF" ] under "TestPolicyCC05E598"
The two versions differed only by that single DependsOn. Both versions deployed and destroyed as expected without error.
// resource section of CDK-generated Cloud Formation Template
"Resources": {
"TestRole6C9272DF": {
"Type": "AWS::IAM::Role",
"Properties": {
"AssumeRolePolicyDocument": {
"Statement": [
{
"Action": "sts:AssumeRole",
"Effect": "Allow",
"Principal": {
"Service": "lambda.amazonaws.com"
}
}
],
"Version": "2012-10-17"
}
},
"Metadata": {
"aws:cdk:path": "TsCdkPlaygroundIamDependencyStack/TestRole/Resource"
}
},
"TestPolicyCC05E598": {
"Type": "AWS::IAM::ManagedPolicy",
"Properties": {
"PolicyDocument": {
"Statement": [
{
"Action": [
"logs:CreateLogGroup",
"logs:CreateLogStream",
"logs:PutLogEvents"
],
"Effect": "Allow",
"Resource": "*"
}
],
"Version": "2012-10-17"
},
"Description": "",
"Path": "/",
"Roles": [
{
"Ref": "TestRole6C9272DF"
}
]
},
"DependsOn": [
"TestRole6C9272DF" // <-- The difference that makes no difference
],
"Metadata": {
"aws:cdk:path": "TsCdkPlaygroundIamDependencyStack/TestPolicy/Resource"
}
},

Cross account Cloudformation macro

I am trying to create a cross account macro which will will be used in Cloudformation.
According to the doc - https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/template-macros.html we have to create macros in different accounts but the underlying lambda can be re-used by making it cross account accessible.
Sample Example:
Account A
In Account_A(2
22222222222) I have created a lambda function "TestMacroFunction" which is used in the macro.
I have added following trust policy:
{
"Version": "2012-10-17",
"Statement": [
{
"Effect": "Allow",
"Principal": {
"Service": "lambda.amazonaws.com",
"AWS": "arn:aws:iam::483427547108:role/service-role/TestLambdaInvoker-role-lu7aa94t"
},
"Action": "sts:AssumeRole"
}
]
}
Account B
In Account_B(111111111111) which will have a cloudformation stack for Macro and another stack which will use the macro.
CFN for macro
{
"AWSTemplateFormatVersion": "2010-09-09",
"Resources": {
"SageMakerEndpointAlarmsMacro": {
"Type": "AWS::CloudFormation::Macro",
"Properties": {
"Name": "ExternalMacro",
"FunctionName": "arn:aws:lambda:us-east-2:111111111111:function:TestMacroFunction",
"LogGroupName": "MacroLogGroup"
}
}
}
}
CFN for Stack using macro:
{
"AWSTemplateFormatVersion": "2010-09-09",
"Transform": [
"ExternalMacro"
],
"Resources": {
"TestBucket": {
"Type": "AWS::S3::Bucket",
"Properties": {}
}
}
}
While running the CFN stack I provide a Role which has following policy attached:
{
"Version": "2012-10-17",
"Statement": [
{
"Action": [
"lambda:InvokeFunction"
],
"Resource": "arn:aws:lambda:us-east-2:111111111111:function:TestMacroFunction",
"Effect": "Allow"
}
]
}
But still I am getting error in cloudformation. The transform in not executing. Also the lambda function is not getting invoked.
Has anyone created a lambda which is used by macros in other account?

aws cloudformation 2 sqspolicy for a single queue

I use cloudformation templates to create a sqs queue and apply two policies based on the user parameters. I created 2 sqs QueuePolicy resources and which refer to the queue. However when I try to apply two policies to a queue using Cloudformation templates, only the second one comes into effect. The cloudformation stack says two sqs policy resources have been created. However the admin console for sqs shows only the second one. The aws documentation for SQS says multiple policies could be applied to a single queue; however the cloudformation QueuePolicy does not have explicit mention on whether this is allowed or not. I tried swapping the policies and the second comes into effect all the time. My policy snippet has been attached.
"QueuePolicy1": {
"Type": "AWS::SQS::QueuePolicy",
"Properties": {
"PolicyDocument": {
"Id": "QueuePolicy1",
"Statement": [
{
"Sid": "QueuePolicy1-ReceiveMesasges",
"Effect": "Allow",
"Principal": {
"AWS": "*"
},
"Action": [
"sqs:GetQueueAttributes",
"sqs:GetQueueUrl",
"sqs:ReceiveMessage",
"sqs:DeleteMessage",
"sqs:ChangeMessageVisibility"
],
"Resource": "*",
"Condition": {
"ArnEquals": {
"aws:SourceArn": {
"Ref": "QOwnerArnParam"
}
}
}
}
]
},
"Queues": [
{
"Ref": "Queue1"
}
]
},
"Metadata": {
"AWS::CloudFormation::Designer": {
"id": "124145a7-3ad1-48e4-9478-04a930498db5"
}
},
"Condition": "Condition1"
},
"QueuePolicy2": {
"Type": "AWS::SQS::QueuePolicy",
"Properties": {
"PolicyDocument": {
"Id": "QueuePolicy2",
"Statement": [
{
"Sid": "QueuePolicy2-SendMessage-To-Queue-From-SNS-Topic",
"Effect": "Allow",
"Principal": {
"AWS": "*"
},
"Action": [
"sqs:SendMessage"
],
"Resource": "*",
"Condition": {
"ArnEquals": {
"aws:SourceArn": {
"Ref": "TopicArnParam"
}
}
}
}
]
},
"Queues": [
{
"Ref": "Queue1"
}
]
},
"Metadata": {
"AWS::CloudFormation::Designer": {
"id": "124145a7-3ad1-48e4-9478-04a930498db5"
}
},
"Condition": "Condition2"
},
There's not really a question here, but I'll add that you can add multiple statements to a single policy. I think a Queue has only a single policy containing multiple statements.
In my experience so far I've found that the AWS docs are very precise (sometimes almost too precise) and I think this is one of those cases.
The AWS CF docs for QueuePolicy say The AWS::SQS::QueuePolicy type applies a policy to SQS queues.
I know that when you first read this it might seem like your standard self-explanatory, didnt-know-what-else-to-write doc comment, but I think this is written very literally to imply / explain that the policy is simply set - i.e. it's not added to a list of policies.
I know this is probably not ideal for what you wanted to achieve, but I think your solution for the time being would be to merge the 2 policies.