How to get an AWS KMS Key Arn and pass it in IAM role inline policy by CloudFormation? - aws-cloudformation

I am trying to create IAM role and KMS key through CloudFormation template. My requirement is first I need to create KMS Key, get the ARN of it and then while creating IAM role, beed to pass that KMS ARN. This is what my policy looks like:
Resources:
myKey:
Type: AWS::KMS::Key
Properties:
Description: Key for encrypting S3 Buckets
Enabled: TRUE
KeyPolicy:
Version: '2012-10-17'
Statement:
- Sid: Enable IAM User Permissions
Effect: Allow
Principal:
AWS: arn:aws:iam::11111111:root
Action: kms:*
Resource: '*'
KeyUsage: ENCRYPT_DECRYPT
myAlias:
Type: AWS::KMS::Alias
Properties:
AliasName: alias/key_for_s3_encrytpion
TargetKeyId:
Ref: myKey
RootRole:
Type: 'AWS::IAM::Role'
Properties:
RoleName: 'Lambda-S3-SNS-VPC-Role-cft'
AssumeRolePolicyDocument:
Version: '2012-10-17'
Statement:
- Effect: Allow
Principal:
Service:
- lambda.amazonaws.com
Action:
- 'sts:AssumeRole'
Path: /
ManagedPolicyArns:
- !Ref AmazonVPCFullAccessARN
- !Ref AmazonS3FullAccessARN
- !Ref AWSLambdaBasicExecutionRoleARN
- !Ref AmazonSNSFullAccessARN
- !Ref AmazonSSMFullAccessARN
Policies:
- PolicyName: kms_cross_account
PolicyDocument:
Version: 2012-10-17
Statement:
- Effect: Allow
Action:
- "kms:Decrypt"
- "kms:Encrypt"
- "kms:GenerateDataKey"
- "kms:DescribeKey"
- "kms:ReEncrypt*"
Resource:
- <Here I need to pass KMS Key ARN created above>
I tried placing !Sub in Resource:
- !Sub 'arn:aws:kms:${AWS::Region}:${AWS::AccountId}:alias/key_for_s3_encrytpion'
but its directly placing this whole as a string

Solved. I used !GetAtt myKey.Arn to get the KMS ARN in iAM role

Related

CloudFormation template to update the IAM Role's policy

Is it possible to create a CloudFormation template that takes the IAM role's ARN as the input and updates its policy assigned to it to add more privileges?I tried to work with the CloudFormation designer but it is very confusing and not straightforward,
Yes, you can do this with a template such as this:
Description: Add policy to existing role
Parameters:
MyExistingRoleName:
Type: String
Description: Name of the Role you want to add a policy to
Resources:
MyNewPolicy:
Type: AWS::IAM::Policy
Properties:
PolicyName: "my-new-policy"
PolicyDocument:
Version: "2012-10-17"
Statement:
- Effect: Allow
Action:
- "s3:ListAllMyBuckets"
Resource:
- "*"
Roles:
- !Ref MyExistingRoleName

Why does this SQSQueuePolicy fail to create in AWS CloudFormation?

I've created the following CloudFormation template:
AWSTemplateFormatVersion: 2010-09-09
Description: Creates all resources necessary to send SES emails & track bounces/complaints through AWS
Resources:
IAMUser:
Type: 'AWS::IAM::User'
Properties:
UserName: iam-ses-sqs
SQSQueue:
Type: 'AWS::SQS::Queue'
Properties:
QueueName: ses-queue
SNSTopic:
Type: 'AWS::SNS::Topic'
Properties:
TopicName: sns-notifications
IAMUserPolicy:
Type: 'AWS::IAM::Policy'
Properties:
PolicyName: IAM_Send_SES_Email
PolicyDocument:
Statement:
- Effect: Allow
Action:
- 'SES:SendEmail'
- 'SES:SendRawEmail'
Resource: 'arn:aws:ses:*:*:identity/*'
Users:
- !Ref IAMUser
SQSQueuePolicy:
Type: 'AWS::SQS::QueuePolicy'
Properties:
Queues:
- !Ref SQSQueue
PolicyDocument:
Statement:
- Action:
- 'SQS:ReceiveMessage'
- 'SQS:DeleteMessage'
- 'SQS:GetQueueAttributes'
Effect: Allow
Resource: !Ref SQSQueue
Principal:
AWS:
- !Ref IAMUser
SNSTopicSubscription:
Type: 'AWS::SNS::Subscription'
Properties:
Protocol: SQS
Endpoint: !GetAtt
- SQSQueue
- Arn
TopicArn: !Ref SNSTopic
I'd like to allow IAMUser to perform the SQS ReceiveMessage, DeleteMessage, and GetQueueAttributes actions on the SQSQueue resource. SQSQueue should also be subscribed to the SNSTopic.
When creating a stack using this template in CloudFormation, the SQSQueue, SNSTopic, SNSTopicSubscription, IAMUser, and IAMUserPolicy all create with no problem, in that order. However, the SQSQueuePolicy fails to create and generates the error message:
Invalid value for the parameter Policy. (Service: AmazonSQS; Status Code: 400; Error Code: InvalidAttributeValue; Request ID: {request id})
Why is this failing, and how should I modify the template to ensure that all resources and their associated policies/subscriptions are created successfully?
I found two problems in your CloudFormation template.
The first one, like Marcin said, the resource reference must be the Queue ARN and not the Queue URL.
Resource: !GetAtt SQSQueue.Arn
The second one is that your AWS reference is with your IAM user but it must be the Account ID.
Principal:
AWS:
- !Ref 'AWS::AccountId'
That said, I was able to create successfully the CloudFormation Stack in my account with this CloudFormation Template:
AWSTemplateFormatVersion: 2010-09-09
Description: Creates all resources necessary to send SES emails & track bounces/complaints through AWS
Resources:
IAMUser:
Type: 'AWS::IAM::User'
Properties:
UserName: iam-ses-sqs
SQSQueue:
Type: 'AWS::SQS::Queue'
Properties:
QueueName: ses-queue
SQSQueuePolicy:
Type: 'AWS::SQS::QueuePolicy'
Properties:
Queues:
- !Ref SQSQueue
PolicyDocument:
Statement:
- Action:
- 'SQS:ReceiveMessage'
- 'SQS:DeleteMessage'
- 'SQS:GetQueueAttributes'
Effect: Allow
Resource: !GetAtt SQSQueue.Arn
Principal:
AWS:
- !Ref 'AWS::AccountId'
The following will return queue URL, not ARN:
Resource: !Ref SQSQueue
But you need to use queue ARN in the policy:
Resource: !GetAtt SQSQueue.Arn

ARN of the role that is automatically created with an Lambda function

In a SAM template, is there a way to reference the ARN of the role that is automatically created with an Lambda function?
I would need to use that ARN somewhere else in the template.
# this is the role
Role:
Type: AWS::IAM::Role
Properties:
RoleName: client-role
AssumeRolePolicyDocument:
Version: "2012-10-17"
Statement:
- Effect: Allow
Principal:
Service: lambda.amazonaws.com
Action: sts:AssumeRole
- Effect: Allow
Principal:
AWS: "arn:aws:iam::xxxx:role/xxxxxxx-ApiHandlerRole-12UWXALxxxxx"
Action: sts:AssumeRole
ManagedPolicyArns:
- arn:aws:iam::aws:policy/AmazonS3FullAccess
# this is the lambda
ApiHandler:
Type: AWS::Serverless::Function
Properties:
FunctionName: api-handler
......
Policies:
- DynamoDBCrudPolicy:
TableName: !Ref Table
- S3ReadPolicy:
BucketName: !Ref Bucket
- S3WritePolicy:
BucketName: !Ref Bucket
- Version: "2012-10-17"
Statement:
- Effect: Allow
Action: sts:AssumeRole
Resource: !GetAtt Role.Arn
I think what you do is separate the Resource build of the Role.
Then you can use the !Ref Role anywhere you need it, including in your lambda Role.
You can construct the ARN of the role yourself. It has fixed format. From docs:
If a role isn't specified, one is created for you with a logical ID of function-logical-idRole.
For example using Sub:
!Sub "arn:${AWS::Partition}:iam::${AWS::AccountId}:role/function-logical-idRole"
where function-logical-id is your lambda function logical id.
Something like...
# this is the lambda
ApiHandler:
Type: AWS::Serverless::Function
Properties:
FunctionName: api-handler
Policies:
......
# this is the role
Role:
Type: AWS::IAM::Role
Properties:
RoleName: client-role
AssumeRolePolicyDocument:
Version: "2012-10-17"
Statement:
- Effect: Allow
Principal:
Service: lambda.amazonaws.com
Action: sts:AssumeRole
- Effect: Allow
Principal:
AWS: !GetAtt ApiHandlerRole.Arn
Action: sts:AssumeRole
ManagedPolicyArns:
- arn:aws:iam::aws:policy/AmazonS3FullAccess
Assuming that you have not specified the "AssumeRolePolicyDocument" for your function.
(code above based on the pastebin), the SAM cli will generate a role called "ApiHandlerRole" for you.
from the docs:
If this property isn't specified, AWS SAM adds a default assume role
for this function.
Which from the looks of it you may want to just explore that property some more. I'm new to AWS SAM but there has got to be way to plug "arn:aws:iam::aws:policy/AmazonS3FullAccess" at it. :)
Hope this helps all
docs link : https://docs.aws.amazon.com/serverless-application-model/latest/developerguide/sam-resource-function.html#sam-function-assumerolepolicydocument
SOLUTION:
So, I bumped into this situation today.
Suppose your Resource Lambda is named MyLambda, then use
!Ref MyLambdaRole.Arn
Tried and tested, works like a charm.
Reason why it works: If you expand the processed template, the IAM Role resource is named using the following nomenclature
<lambda-logical-id>Role
Don't forget to upvote! :D
What worked for me is refer the ARN Attribute of the autogenerated role like
SomeLambdaFunction:
Type: AWS::Serverless::Function
Properties:
...other properties...
Policies:
... Some sam policies...
.... different resource reference Lambda autogenerate role...
- Action: //some actions here
Effect: Allow
Principal:
AWS: !GetAtt SomeLambdaFunctionRole.Arn
Resource: "*"
.... More template code...

AWS ApiGateway Proxy to non-Public S3 Bucket

The following cloudformation script sets up an Api Gateway method that proxies to an S3 bucket.
The S3BucketPolicy opens up the bucket to public read access but the AWS UI warns that this should never be done.
I tried setting the S3BucketPolicy Principal to service apigateway.amazonaws.com but this results in Access Denied.
1) What is the right way to limit bucket access to the API gateway function? (Sample YAML would be great)
2) How could I debug this Access Denied failure to get more information on why it failed?
3) Where should I be looking for sample code on what should be a very standard template snippet?
ATTEMPT #1 - Works but only by making the S3 Bucket Public otherwise Access Denied
AWSTemplateFormatVersion: 2010-09-09
Parameters:
S3BucketName:
Type: String
Description: >
Name for the S3 bucket that contains the nested templates.
Resources:
RestAPI:
Type: 'AWS::ApiGateway::RestApi'
Properties:
BinaryMediaTypes:
- '*/*'
Name: !Ref 'AWS::StackName'
RestAPIRootGET:
Type: 'AWS::ApiGateway::Method'
Properties:
AuthorizationType: NONE
HttpMethod: GET
Integration:
IntegrationHttpMethod: GET
PassthroughBehavior: WHEN_NO_MATCH
Type: HTTP_PROXY
Uri: !Sub https://${S3BucketName}.s3.amazonaws.com/static-assets/index.html
ResourceId: !GetAtt RestAPI.RootResourceId
RestApiId: !Ref RestAPI
DependsOn:
- RestAPI
BucketPolicy:
Type: AWS::S3::BucketPolicy
Properties:
Bucket: !Ref S3BucketName
PolicyDocument:
Version: 2012-10-17
Statement:
-
Sid: GetObject
Effect: Allow
Principal: "*"
Action:
- s3:*
Resource:
- !Sub 'arn:aws:s3:::${S3BucketName}/static-assets/*'
I think perhaps the right away is to create a role with access to the bucket and then have the ApiGateway assume this role but I'm having a hard time finding documentation that explains how to do this in a cloudformation template. (see also Michael - sqlbot comment suggesting using the credentials property of the method)
Here is my attempt which still fails with Access Denied
ATTEMPT #2 - Access Denied
AWSTemplateFormatVersion: 2010-09-09
Parameters:
S3BucketName:
Type: String
Description: >
Name for the S3 bucket that contains the nested templates.
Resources:
RestAPI:
Type: 'AWS::ApiGateway::RestApi'
Properties:
BinaryMediaTypes:
- '*/*'
Name: !Ref 'AWS::StackName'
RestAPIRootGET:
Type: 'AWS::ApiGateway::Method'
Properties:
AuthorizationType: NONE
HttpMethod: GET
Integration:
IntegrationHttpMethod: GET
PassthroughBehavior: WHEN_NO_MATCH
Type: HTTP_PROXY
Uri: !Sub https://${S3BucketName}.s3.amazonaws.com/static-assets/index.html
Credentials: !GetAtt AllowStaticAccessRole.Arn
ResourceId: !GetAtt RestAPI.RootResourceId
RestApiId: !Ref RestAPI
DependsOn:
- RestAPI
- AllowStaticAccessRole
AllowStaticAccessRole:
Type: "AWS::IAM::Role"
Properties:
AssumeRolePolicyDocument:
Version: "2012-10-17"
Statement:
-
Effect: "Allow"
Principal:
Service:
- "apigateway.amazonaws.com"
Action:
- "sts:AssumeRole"
Path: "/"
Policies:
-
PolicyName: "AllowStaticAccessPolicy"
PolicyDocument:
Version: "2012-10-17"
Statement:
-
Effect: "Allow"
Action:
- s3:*
Resource:
- !Sub 'arn:aws:s3:::${S3BucketName}/static-assets/*'
As already mentioned in the comments, the Access Denied error could be coming from KMS rather than from the S3 itself.
To solve the issue, you need to add at minimum these permissions to the role that the Api Gateway assumes: "kms:Decrypt", "kms:ReEncryptFrom", preferably also stating which Resource this should apply too for proper least privilege implementation.

cross-referencing cloudformation not working

I have created a policy template and outputted the ARN:
Resources:
# Codebuild Policies
CodeBuildServiceRolePolicy1:
Type: AWS::IAM::ManagedPolicy
Properties:
Description: 'This service role enables AWS CodePipeline to interact with other AWS services, including AWS CodeBuild, on your behalf'
Path: "/"
PolicyDocument:
Version: "2012-10-17"
Statement:
- Resource: "*"
Effect: "Allow"
Action:
...
Outputs:
StackName:
Value: !Ref AWS::StackName
CodeBuildServiceRolePolicy:
Description: The ARN of the ManagedPolicy1
Value: !Ref CodeBuildServiceRolePolicy1
Export:
Name: !Sub '${EnvironmentName}-CodeBuildServiceRolePolicy1'
Now I want o import these Policy into a template with Roles and
# Codebuilding service role
CodeBuildRole:
Type: AWS::IAM::Role
Properties:
RoleName: !Sub ${EnvironmentName}-CodeBuildRole
AssumeRolePolicyDocument:
Statement:
- Action: ["sts:AssumeRole"]
Effect: Allow
Principal:
Service: [codebuild.amazonaws.com]
Version: "2012-10-17"
Path: /
Policies:
- PolicyDocument:
Fn::ImportValue:
!Sub ${EnvironmentName}-CodeBuildServiceRolePolicy1'
But this fails. I'm getting an error, what is wrong?
merci in advance
A
Have you tried to reference the Managed Policy you created with your first stack, using the !Ref function?
The CF for the policy:
AWSTemplateFormatVersion: "2010-09-09"
Resources:
CodeBuildServiceRolePolicy1:
Type: AWS::IAM::ManagedPolicy
Properties:
Path: "/"
PolicyDocument:
...
Outputs:
CodeBuildServiceRolePolicy:
Value: !Ref CodeBuildServiceRolePolicy1.Arn
The CF for the role:
AWSTemplateFormatVersion: "2010-09-09"
Parameters:
PolicyName:
Type: String
Resources:
CodeBuildRole:
Type: "AWS::IAM::Role"
Properties:
Path: "/"
Policies: !Ref PolicyName
Also checkout the docs for Cloudformation IAM an CloudFormation Functions
The solution is to use the AWS resource Type: AWS::IAM::ManagedPolicy instead of AWS::IAM::Policy .
If you use AWS::IAM::ManagedPolicy you can export the policy ARN like this
CodeBuildServiceRolePolicy:
Description: ARN of the managed policy
Value: !Ref CodeBuildServiceRolePolicy
and import it into another template with fn::ImportValue or fn::GetAtt
Using AWS::IAM::Policy only allows to create inline policies which cannot be referenced.