The state machine IAM Role is not authorized to access the Log Destination - aws-cloudformation

I am trying to deploy a CF stack which is failing because of an IAM permission issue. The concerning resources in the stack for this issue are:
state machine (step function)
Cloudwatch log group
A subscription filter for the log group
This subscription filter forwards the logs to Kenesis where the logs are streamed into splunk. Coming back to my issue, when I try to deploy the above CF stack, I get the following error: The state machine IAM Role is not authorized to access the Log Destination
I have given the following permissions to the role attached to the state machine
StateMachineRole:
Type: AWS::IAM::Role
DeletionPolicy: Retain
Properties:
RoleName: StateMachineRole-${self:custom.env.stage}
AssumeRolePolicyDocument:
Version: '2012-10-17'
Statement:
- Effect: Allow
Principal:
Service: states.amazonaws.com
Action: sts:AssumeRole
LambdaPolicy:
Type: AWS::IAM::Policy
DeletionPolicy: Retain
DependsOn: CustomLogGroup
Properties:
PolicyName: LambdaPolicy-${self:custom.env.stage}
PolicyDocument:
Version: '2012-10-17'
Statement:
- Effect: Allow
Action:
- 'lambda:InvokeFunction'
Resource: lambdaArn
- Effect: Allow
Action:
- 'logs:CreateLogDelivery'
- 'logs:GetLogDelivery'
- 'logs:UpdateLogDelivery'
- 'logs:DeleteLogDelivery'
- 'logs:ListLogDeliveries'
- 'logs:PutLogEvents'
- 'logs:PutResourcePolicy'
- 'logs:DescribeResourcePolicies'
- 'logs:DescribeLogGroups'
- 'logs:PutDestination'
- 'logs:PutSubscriptionFilter'
- 'logs:PutDestinationPolicy'
Resource: !GetAtt CustomLogGroup.Arn
/*CustomLogGroup*/
CustomLogGroup:
Type: AWS::Logs::LogGroup
Properties:
KmsKeyId: !ImportValue XXXXXXX
LogGroupName: CustomLogGroupName
RetentionInDays: ${file(./.env.${self:custom.env.stage}.yaml):cloudwatchLogs.retentionDays
Referred to the following SO question: Aws step function deployment log access issue

Related

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

Problem when deploying a SageMaker Multi-Model Endpoints with AWS CDK/CloudFormation

I am trying to automate the deployment of a SageMaker multi-model endpoints with AWS CDK using Python language (I guess it would be the same by directly writing a CloudFormation template in json/yaml format), but when trying to deploy it, error occurs at the creation of the SageMaker model.
Here is part of the CloudFormation template made with the cdk synth command:
Resources:
smmodelexecutionrole:
Type: AWS::IAM::Role
Properties:
AssumeRolePolicyDocument:
Statement:
- Action: sts:AssumeRole
Effect: Allow
Principal:
Service: sagemaker.amazonaws.com
Version: "2012-10-17"
Policies:
- PolicyDocument:
Statement:
- Action: s3:GetObject
Effect: Allow
Resource:
Fn::Join:
- ""
- - "arn:"
- Ref: AWS::Partition
- :s3:::<bucket_name>/deploy_multi_model_artifact/*
Version: "2012-10-17"
PolicyName: policy_s3
- PolicyDocument:
Statement:
- Action: ecr:*
Effect: Allow
Resource:
Fn::Join:
- ""
- - "arn:"
- Ref: AWS::Partition
- ":ecr:"
- Ref: AWS::Region
- ":"
- Ref: AWS::AccountId
- :repository/<my_ecr_repository>
Version: "2012-10-17"
PolicyName: policy_ecr
Metadata:
aws:cdk:path: <omitted>
smmodel:
Type: AWS::SageMaker::Model
Properties:
ExecutionRoleArn:
Fn::GetAtt:
- smmodelexecutionrole
- Arn
Containers:
- Image: xxxxxxxxxxxx.dkr.ecr.<my_aws_region>.amazonaws.com/<my_ecr_repository>/multi-model:latest
Mode: MultiModel
ModelDataUrl: s3://<bucket_name>/deploy_multi_model_artifact/
ModelName: MyModel
Metadata:
aws:cdk:path: <omitted>
When running cdk deploy on the Terminal, the following error occur:
3/6 | 7:56:58 PM | CREATE_FAILED | AWS::SageMaker::Model | sm_model (smmodel)
Could not access model data at s3://<bucket_name>/deploy_multi_model_artifact/.
Please ensure that the role "arn:aws:iam::xxxxxxxxxxxx:role/<my_role>" exists
and that its trust relationship policy allows the action "sts:AssumeRole" for the service principal "sagemaker.amazonaws.com".
Also ensure that the role has "s3:GetObject" permissions and that the object is located in <my_aws_region>.
(Service: AmazonSageMaker; Status Code: 400; Error Code: ValidationException; Request ID: xxxxx)
What I have:
An ECR repository containing the docker image
A S3 bucket containing the model artifacts (.tar.gz files) inside the "folder" "deploy_multi_model_artifact"
To test if it is a IAM role issue, I tried to replace MultiModel by SingleModel and replace s3://<bucket_name>/deploy_multi_model_artifact/ with s3://<bucket_name>/deploy_multi_model_artifact/one_of_my_artifacts.tar.gz, and I could create successfully the model. I am then guessing that it is not a problem related with the IAM contrary to what the error message tells me (but I may make a mistake!) as it seems .
So I am wondering where the problem comes from. This is even more confusing as I have already deployed this multi-model endpoints using boto3 without problem.
Any help would be greatly appreciated !!
(About Multi-Model Endpoints deployment: https://github.com/awslabs/amazon-sagemaker-examples/blob/master/advanced_functionality/multi_model_xgboost_home_value/xgboost_multi_model_endpoint_home_value.ipynb)
Problem was that I forgot to add SageMaker access permissions to the IAM role.
I can deploy the multi-model endpoints by adding the SageMaker FullAccess managed policy to the IAM role.

How to get an AWS KMS Key Arn and pass it in IAM role inline policy by 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

Cloudformation for a kube2iam role

I'm having trouble creating a role for kube2iam, everything seems to work fine I deploy the stack with the role and the pods spin up but whenever a pod tries to perform an authorized action (put an item into dynamo in this case) I get an error that the assumed role is not authorized. Here's the snippet that creates the role:
ServiceRole:
Type: "AWS::IAM::Role"
Properties:
RoleName:
Ref: StackName
AssumeRolePolicyDocument:
Version: "2012-10-17"
Statement:
- Effect: "Allow"
Principal:
Service:
- "ec2.amazonaws.com"
Action:
- "sts:AssumeRole"
Path: "/"
Policies:
- PolicyName:
Ref: StackName
PolicyDocument:
Version: "2012-10-17"
Statement:
- Effect: "Allow"
Action:
- dynamodb:PutItem
Resource:
Fn::GetAtt: [Table, Arn]
The table is elsewhere in the same stack and deploys just fine. I deployed kube2iam via a helm chart
The error I get is:
User: arn:aws:sts::<BLAHBLAH>:assumed-role/nodes.k8s.logint.cimpress.io/<BLAHBLAH> is not authorized to perform: dynamodb:PutItem on resource <BLAHBLAH>
I also tried this for the assume role:
- Effect: "Allow"
Principal:
AWS: "arn:aws:iam::<BLAHBLAH>:role/nodes.<BLAHBLAH>"
Action:
- "sts:AssumeRole"
I still get the same error

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.