AWS Private API gateway deployment error when using serverless deploy - aws-api-gateway

I am hitting the below error when I try to create a PRIVATE endpoint type using serverless in AWS.
Below is the serverless.yml file for reference
provider:
name: aws
endpointType: PRIVATE
vpcEndpointIds:
- vpce-xxxx
region: ap-southeast-2
apiKeys:
- ${self:custom.actualStage}-xxxxxx2
resourcePolicy:
- Effect: Allow
Principal: '*'
Action: execute-api:Invoke
Resource:
- execute-api:/*/*/*
Condition:
StringEquals:
aws:SourceVpc:
- "vpc-xxxxx"
plugins:
- serverless-plugin-warmup
iamRoleStatements:
- Effect: 'Allow'
Action:
- 'lambda:InvokeFunction'
Resource: "*"
Error from logs:
CREATE_FAILED: ApiGatewayDeployment1655171823778 (AWS::ApiGateway::Deployment)
Resource handler returned message: "Private REST API doesn't have a resource policy attached to it (Service: ApiGateway, Status Code: 400, Request ID: e321f00e-42b6-4ef6-b984-46500ca40492)" (RequestToken: 475924b8-998d-58fc-89bd-51fc0b80f2d4, HandlerErrorCode: InvalidRequest)

Not sure if AWS released new changes in the serverless configuration for API GW. Your policy version should have worked. However, I have tested this on my end. We now have to mention the resourcePolicy under the apiGateway attribute. Please use the following this will resolve your issue:
apiGateway:
resourcePolicy:
- Effect: Allow
Principal: '*'
Action: execute-api:Invoke
Resource:
- execute-api:/*
- Effect: Deny
Principal: '*'
Action: execute-api:Invoke
Resource:
- execute-api:/*
Condition:
StringNotEquals:
aws:SourceVpc:
- 'vpc-*******'

Related

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

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

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.

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.

Unable to transform request to binary

To implement binary support in api-gateway for file upload, i have used serverless-apigw-binary plugin and added necessary content types which should be converted by api-gateway.
This is my serverless.ymlfile
service: aws-java-gradle
provider:
name: aws
runtime: java8
stage: dev
region: us-east-1
custom:
apigwBinary:
types:
- 'application/pdf'
plugins:
- serverless-apigw-binary
package:
artifact: build/distributions/hello.zip
functions:
uploadLoadFiles:
handler: com.serverless.UploadFileHandler
role: UploadFileRole
timeout: 180
events:
- http:
integration: lambda
path: upload
method: put
cors:
origin: '*'
headers:
- Content-Type
- X-Amz-Date
- Authorization
- X-Api-Key
- X-Amz-Security-Token
- X-Amz-User-Agent
- X-Requested-With
allowCredentials: false
request:
passThrough: WHEN_NO_TEMPLATES
template:
application/pdf: '{ "operation":"dev-aws-java-gradle", "base64Image": "$input.body", "query": "$input.params("fileName")" }'
response:
template: $input.body
statusCodes:
400:
pattern: '.*"httpStatus":400,.*'
template: ${file(response-template.txt)}
401:
pattern: '.*"httpStatus":401,.*'
template: ${file(response-template.txt)}
403:
pattern: '.*"httpStatus":403,.*'
template: ${file(response-template.txt)}
500:
pattern: '.*"httpStatus":500,.*'
template: ${file(response-template.txt)}
501:
pattern: '.*[a-zA-Z].*'
template: ${file(unknown-error-response-template.txt)}
environment:
S3BUCKET: ${env:S3_BUCKET}
APS_ENV: ${env:APS_ENV}
# you can add CloudFormation resource templates here
resources:
Resources:
UploadFileRole:
Type: AWS::IAM::Role
Properties:
RoleName: "UploadFileRole"
AssumeRolePolicyDocument:
Version: '2012-10-17'
Statement:
- Effect: Allow
Principal:
Service:
- lambda.amazonaws.com
Action: sts:AssumeRole
Policies:
- PolicyName: loggingPolicy
PolicyDocument:
Version: '2012-10-17'
Statement:
- Effect: Allow
Action:
- logs:CreateLogGroup
- logs:CreateLogStream
- logs:PutLogEvents
Resource:
- 'Fn::Join':
- ':'
-
- 'arn:aws:logs'
- Ref: 'AWS::Region'
- Ref: 'AWS::AccountId'
- 'log-group:/aws/lambda/*:*:*'
all the necessary settings got implemented in api-gateway after doing sls deploy
(checked based on this article https://aws.amazon.com/blogs/compute/binary-support-for-api-integrations-with-amazon-api-gateway/)
but when i hit my end point api gateway is giving out an error like this
Verifying Usage Plan for request: 45bac722-f039-11e7-bcc6-f9a1aa509052. API Key: API Stage: fd4ue8lpia/int
API Key authorized because method 'PUT /upload' does not require API Key. Request will not contribute to throttle or quota limits
Usage Plan check succeeded for API Key and API Stage fd4ue8lpia/int
Starting execution for request: 45bac722-f039-11e7-bcc6-f9a1aa509052
HTTP Method: PUT, Resource Path: /upload
Method request path:
{}
Method request query string:
{}
Method request headers: {Accept=*/*, CloudFront-Viewer-Country=IN, postman-token=6f1a23ba-36c2-104d-2e12-dc2c76a985ee, CloudFront-Forwarded-Proto=https, CloudFront-Is-Tablet-Viewer=false, origin=chrome-extension://aicmkgpgakddgnaphhhpliifpcfhicfo, CloudFront-Is-Mobile-Viewer=false, User-Agent=Mozilla/5.0 (Macintosh; Intel Mac OS X 10_11_6) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/63.0.3239.84 Safari/537.36, X-Forwarded-Proto=https, CloudFront-Is-SmartTV-Viewer=false, Host=fd4ue8lpia.execute-api.us-east-1.amazonaws.com, Accept-Encoding=gzip, deflate, br, X-Forwarded-Port=443, X-Amzn-Trace-Id=Root=1-5a4c530e-2c1927f85440b71b66cf0c15, Via=2.0 fc18daf68173838631b562fe2efaf8f8.cloudfront.net (CloudFront), x-postman-interceptor-id=8fa8440f-0541-fdac-c60c-6019c2269a66, X-Amz-Cf-Id=P4PYoi5Wwb-NCYRSdTQ_5TdtpbQLBaEATXoyJGC7cS8g6LsoCRPbkg==, X-Forwarded-For=157.50.20.12, 52.46.37.156, content-type=application/pdf, Accept-Language=en-US,en;q=0.9, cache-control=no-cache, CloudFront-Is-Desktop-Viewer=true}
Method request body before transformations: [Binary Data]
Execution failed due to configuration error: Unable to transform request
Method completed with status: 500
and the request is not crossing api-gateway to lambda function.
But i followed a solution mentioned here
to edit lambda function name in integration request section of resource in api-gateway to the same name and click ok. Then error's were gone and working fine.
I checked for changes in roles after doing that but none were found.
Can any one suggest what could have happened there, and any better solutions for the above mentioned problem.
Thanks in advance.
But i followed a solution mentioned here to edit lambda function name
in integration request section of resource in api-gateway to the same
name and click ok. Then error's were gone and working fine.
When you edit lambda function on the console, it sets up the permissions to call the lambda function automatically. If you want to do that manually, you can do that using the CLI