AWS Role with a PolicyDocument assuming itself - amazon-web-services

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.

Related

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"
}
]
}
]
}]

Allow access to file only from specific Lambda [s3]

A s3 bucket (static web hosting) have a certain policy that deny access to everyone concerning a certain file.
How can I allow only a specific lambda function to access it ? (using only the bucket policy)
{
"Version": "2012-10-17",
"Statement": [
{
"Sid": "Authentication",
"Effect": "Allow",
"Principal": "*",
"Action": "s3:GetObject",
"NotResource": "arn:aws:s3:::web/auth.html"
}
]
}
UPDATE : Changing the previous policy with this one gives the desired result
{
"Version": "2012-10-17",
"Id": "Policy1477651215159",
"Statement": [
{
"Sid": "Console administration",
"Effect": "Allow",
"NotPrincipal": {
"AWS": "arn:aws:iam::XXXX:role/role_lambda"
},
"Action": "s3:GetObject",
"NotResource": "arn:aws:s3:::web/auth.html"
}
]
}
Lambda functions run in a Execution Role. You can make a customer IAM Role for your lambda function. See this
Then you can use that IAM Role to grant access to that S3 Object. See this article for steps to follow.
This is a CloudFormation snippet. You can allow your Lambda role access to S3 using the following IAM policy statement:
"LambdaRolePolicy" : {
"Type": "AWS::IAM::Policy",
"Properties": {
"PolicyName": "Lambda",
"PolicyDocument": {
"Statement" : [ {
"Action" : [
"s3:PutObject",
"s3:PutObjectAcl"
],
"Effect" : "Allow",
"Resource" : {
"Fn::Join": [ "", [
"arn:aws:s3:::",
{ "Ref": "S3Bucket" },
"/*"
] ]
}
} ]
},
"Roles" : [ { "Ref": "RootRole" } ]
}
}
S3Bucket resource is your S3 bucket and RootRole is the Lambda role.

CloudFormation: The role defined for the function cannot be assumed by Lambda

I've been searching for this error and nothing really answers how I can fix it with my CloudFormation template. From the events log, I can see that the role was created before the Lambda functions.
Could you please help?
You are probably missing an AssumeRolePolicyDocument allowing Lambda (lambda.amazonaws.com) to assume your IAM role.
Example:
...
"LambdaRole": {
"Type": "AWS::IAM::Role",
"Properties": {
"AssumeRolePolicyDocument": {
"Version": "2012-10-17",
"Statement": [{
"Effect": "Allow",
"Principal": {"Service" : "lambda.amazonaws.com"},
"Action": ["sts:AssumeRole"]
}]
},
"Path": "/",
"Policies": [...]
}
}
...

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.

IAM to restrict Instance Type

I am trying to set up some restriction on the type of instances that people can launch. I have the following policy
{
"Version": "2012-10-17",
"Statement": [
{
"Effect": "Allow",
"Action": "ec2:RunInstances",
"Resource": [
"arn:aws:ec2:us-east-1:123:key-pair/CI",
"arn:aws:ec2:us-east-1:123:instance/*",
"arn:aws:ec2:us-east-1:123:image/ami-*",
"arn:aws:ec2:us-east-1:123:subnet/*",
"arn:aws:ec2:us-east-1:123:network-interface/*",
"arn:aws:ec2:us-east-1:123:volume/*",
"arn:aws:ec2:us-east-1:123:security-group/sg-a363xxxx"
]
},
{
"Effect": "Deny",
"Action": "ec2:RunInstances",
"Resource": [
"*"
],
"Condition": {
"StringNotEquals": {
"ec2:InstanceType": "m4.4xlarge"
}
}
}
]
The first part of the statement works fine, but I am trying to add the Deny piece.
{
"DryRun": true,
"ImageId": "ami-5f709f34",
"KeyName": "FE-CI",
"SecurityGroupIds": [
"sg-a363bada"
],
"UserData": "",
"InstanceType": "m4.4xlarge",
"SubnetId": "subnet-xxxxx",
"EbsOptimized":false}
when adding the Condition statement everything gets denied. Here is the decoded authorization message.
{
"DecodedMessage": " {\"allowed\":false,\"explicitDeny\":true,\"matchedStatements\":{\"items\":[{\"statementId\":\"\",\"effect\":\"DENY\",\"principals\":{\"items\":[]},\"principalGroups\":{\"items\":[{\"value\":\"xxx\"}]},\"actions\":{\"items\":[{\"value\":\"ec2:RunInstances\"}]},\"resources\":{\"items\":[{\"value\":\"*\"}]},\"conditions\":{\"items\":[{\"key\":\"ec2:InstanceType\",\"values\":{\"items\":[{\"value\":\"m4.4xlarge\"}]}}]}}]},\"failures\":{\"items\":[]},\"context\":{\"principal\":{\"id\":\"xxx\",\"name\":\"jellin-test\",\"arn\":\"arn:aws:iam::xxx:user/jellin-test\"},\"action\":\"ec2:RunInstances\",\"resource\":\"arn:aws:ec2:us-east-1:xxx:key-pair/FE-CI\",\"conditions\":{\"items\":[{\"key\":\"ec2:Region\",\"values\":{\"items\":[{\"value\":\"us-east-1\"}]}}]}}}"
}
I am not seeing anything obviously wrong here. My understanding is that the first statement should pass and the second one will only deny if the InstanceType is not m4.4xlarge
The StringNotEquals key needs to be changed to StringNotEqualsIfExists. There is a good explanation of why this happens here.