AWS Api Gateway custom authorizer polices with Path Params - amazon-web-services

Is there a way to create a custom authorizer that returns policies allowing resources paths and its path params?
Example:
Allow: GET /stores, GET /stores/{storeId}
Deny: GET /stores/{storeId}/products
I'm having problems with Path Parameters, because when I return a policy like arn:...:.../stage/GET/stores/{storeId}, API gateway blocks calls to GET /stores/123 or GET /stores/555123

Such a policy is possible. You can return the following structure as custom Authorizer policy to achieve this:
{
"principalId": "user",
"policyDocument": {
"Version": "2012-10-17",
"Statement": [{
"Action": "execute-api:Invoke",
"Effect": "Allow",
"Resource": "arn:aws:execute-api:eu-central-1:1234567890:9f4xsv4jbl/prod/GET/stores"
},
{
"Action": "execute-api:Invoke",
"Effect": "Deny",
"Resource": "arn:aws:execute-api:eu-central-1:1234567890:9f4xsv4jbl/*/GET/stores/{id}"
},
{
"Action": "execute-api:Invoke",
"Effect": "Allow",
"Resource": "arn:aws:execute-api:eu-central-1:1234567890:9f4xsv4jbl/prod/GET/stores/*/products"
}
]
}
}

Related

Amazon S3 static Website accessible (403 Error) when secure transport policy added

We have an Amazon S3 static website and it was working fine until we introduced a policy where we allow only secure data transfer by enforcing aws:SecureTransport. A policy with simply denies access to the site when the aws:SecureTransport fails. But when we access the site now, it says 403 Forbidden error.
The set up is that we have CloudFront fronted to this site, so the traffic routes through the CloudFront, not sure if this has to do something with the issue we are facing, where the traffic route between CloudFront and Amazon S3 is http only. Having said that, strangely when we tweek the policy to have aws:SecureTransport:true and allow such requests to the site, it works fine, but when we have deny policy aws:SecureTransport:false, then we end up getting 403 error. Sharing both the policies here.
When we have this the static website works fine:
{
"Version": "2012-10-17",
"Statement": [
{
"Sid": "AllowOriginAccessIdentity",
"Effect": "Allow",
"Principal": {
"AWS": "arn:aws:iam::cloudfront:user/CloudFront Origin Access Identity XXXXXXXXXXX"
},
"Action": "s3:GetObject",
"Resource": "arn:aws:s3:::example.domain.com/*"
},
{
"Sid": "ForceSSLRequest",
"Effect": "Allow",
"Principal": {
"AWS": "*"
},
"Action": "s3:*",
"Resource": "arn:aws:s3:::example.domain.com/*",
"Condition": {
"Bool": {
"aws:SecureTransport": true
}
}
}
]
}
Where as when we have as below, it fails, and we want this to be implemented to be absolutely sure:
{
"Version": "2012-10-17",
"Statement": [
{
"Sid": "AllowOriginAccessIdentity",
"Effect": "Allow",
"Principal": {
"AWS": "arn:aws:iam::cloudfront:user/CloudFront Origin Access Identity XXXXXXXXXXX"
},
"Action": "s3:GetObject",
"Resource": "arn:aws:s3:::example.domain.com/*"
},
{
"Sid": "ForceSSLRequest",
"Effect": "Deny",
"Principal": {
"AWS": "*"
},
"Action": "s3:*",
"Resource": "arn:aws:s3:::example.domain.com/*",
"Condition": {
"Bool": {
"aws:SecureTransport": false
}
}
}
]
}
Update: I have a policy as below allowing an OAI accessing the S3. This does not work, but when we read/understand the policy it makes sense to allow access the webiste, but it fails :(.
{
"Version": "2012-10-17",
"Statement": [
{
"Sid": "AllowOriginAccessIdentity",
"Effect": "Deny",
"Principal": {
"AWS": "arn:aws:iam::cloudfront:user/CloudFront Origin Access Identity XXXXXXXXXXX"
},
"Action": "s3:*",
"Resource": "arn:aws:s3:::example-domain.com/*",
"Condition": {
"Bool": {
"aws:SecureTransport": "false"
}
}
}
]
}
But the below works, even though logical readability is same according to my understanding.
{
"Version": "2012-10-17",
"Statement": [
{
"Sid": "AllowOriginAccessIdentity",
"Effect": "Allow",
"Principal": {
"AWS": "arn:aws:iam::cloudfront:user/CloudFront Origin Access Identity XXXXXXXXXXX"
},
"Action": "s3:*",
"Resource": "arn:aws:s3:::example-domain.com/*",
"Condition": {
"Bool": {
"aws:SecureTransport": "true"
}
}
}
]
}
Any help in understanding this behavior is much appreciated.
The policy logic is:
Explicit Deny by default
Use Allow to grant desired access
Use Deny to override access given by Allow
Therefore, the better policy is to Allow access if aws:SecureTransport is true, since it is less permissive and doesn't need any Deny statements (which are always confusing!).
See: Policy evaluation logic - AWS Identity and Access Management

Allow S3 bucket operations based on EC2 role

Our EC2s are secured using IAM roles. When trying to run an AWS console command such as aws s3 cp I am seeing:
fatal error: An error occurred (403) when calling the HeadObject operation: Forbidden
If allowed based on specific users that are given keys, there are no issues. This just isn't working with roles.
Here is the bucket ACL:
{
"Version": "2012-10-17",
"Statement": [
{
"Sid": "Public",
"Effect": "Allow",
"Principal": "*",
"Action": "s3:GetObject",
"Resource": "arn:aws:s3:::my-bucket/*"
},
{
"Sid": "Devs",
"Effect": "Deny",
"NotPrincipal": {
"AWS": "arn:aws:iam::1234567890:user/DevUser"
},
"Action": "s3:*",
"Resource": "arn:aws:s3:::my-bucket/something-privileged/*"
},
{
"Sid": "EC2s",
"Effect": "Allow",
"Principal": {
"AWS": "arn:aws:iam::1234567890:role/EC2Role"
},
"Action": "s3:*",
"Resource": "arn:aws:s3:::my-bucket/something-privileged/*"
},
]
}
As you can see, we want the public to generally be able to fetch objects that we link to. This works.
We want devs to be able to access a specific hidden folder in the bucket using their AWS keys. This works.
We want EC2s to be able to run aws-cli commands on that same hidden folder using only the assigned security role. This does not work.
I also tried "Effect": "Deny", "NotPrincipal": { ... } on the EC2 statement but that didn't work either.
What's wrong with this ACL?
You have a Deny statement in this where the principal is not that specific IAM user. In any AWS privilege a deny will always override an allow which is the scenario happening here.
To allow this here you will need to include the IAM role arn in the NotPrincipal statement as well. This would look like the below statement.
{
"Version": "2012-10-17",
"Statement": [
{
"Sid": "Public",
"Effect": "Allow",
"Principal": "*",
"Action": "s3:GetObject",
"Resource": "arn:aws:s3:::my-bucket/*"
},
{
"Sid": "Devs",
"Effect": "Deny",
"NotPrincipal": {
"AWS": ["arn:aws:iam::1234567890:user/DevUser", "arn:aws:iam::1234567890:role/EC2Role"]
},
"Action": "s3:*",
"Resource": "arn:aws:s3:::my-bucket/something-privileged/*"
}
]
}

Invoking SNS from cross account using API Gateway

I am having an API gateway end point in my AWS account which will invoke a SNS in another AWS account in same region.
The access policy in API gateway in my account is like follows
{
"Version": "2012-10-17",
"Statement": [
{
"Sid": "VisualEditor0",
"Effect": "Allow",
"Action": "sns:Publish",
"Resource": "arn:aws:sns:ap-southeast-1:604970532282:PublishSourceMsgTopic"
}
]
}
The sns arn : arn:aws:sns:ap-southeast-1:604970532282:PublishSourceMsgTopic belongs to another AWS account in same region.
The json of the access policy configured in the above SNS is :
{
"Version": "2008-10-17",
"Id": "__default_policy_ID",
"Statement": [
{
"Sid": "__default_statement_ID",
"Effect": "Allow",
"Principal": {
"AWS": "*"
},
"Action": [
"SNS:Publish",
"SNS:RemovePermission",
"SNS:SetTopicAttributes",
"SNS:DeleteTopic",
"SNS:ListSubscriptionsByTopic",
"SNS:GetTopicAttributes",
"SNS:Receive",
"SNS:AddPermission",
"SNS:Subscribe"
],
"Resource": "arn:aws:sns:ap-southeast-1:604970532282:PublishSourceMsgTopic",
"Condition": {
"StringEquals": {
"AWS:SourceOwner": "604970532282"
}
}
},
{
"Sid": "__console_pub_0",
"Effect": "Allow",
"Principal": {
"AWS": "arn:aws:iam::148445556582:root"
},
"Action": "SNS:Publish",
"Resource": "arn:aws:sns:ap-southeast-1:604970532282:PublishSourceMsgTopic"
}
]
}
When I am invoking the API Gateway its showing the following error :
User: arn:aws:sts::148445556582:assumed-role/api_gateway_sns_role/BackplaneAssumeRoleSession is not
authorized to perform: SNS:Publish on resource: arn:aws:sns:ap-southeast-
1:604970532282:PublishSourceMsgTopic
I am able to invoke the SNS successfully if i am giving SNS topic which is configured in my AWS account.
What am I missing here?
You are giving permission for the root owner of the external account to publish on the topic, but the actual publish request is using the role of the API gateway.
So in your access policy, you'll need to give the publish permission to the role the API Gateway is using, not the role of root.
Typically what you would do is set "Principal": "*" and then add conditions under resource in the policy to match the account and arn of the resource accessing SNS from another account.
{
"Version": "2012-10-17",
"Statement": [{
"Effect": "Allow",
"Principal": "*",
"Action": "SNS:Publish",
"Resource": "arn:aws:sns:us-east-2:444455556666:MyTopic",
"Condition": {
"ArnLike": {
"aws:SourceArn": "arn:aws:cloudwatch:us-east-2:111122223333:alarm:MyAlarm"
}
}
}]
}
There are several example access policies here, that should help you.

API Gateway Resource policy returning 403

So I'm trying to restrict access on API Gateway for one API endpoint for Auth0 to call when a user has signed Up.
I've tried a few permutations on this, the example below in my mind should work that doesn't.
I allow everything.
As a test, I specifically allowed one endpoint also.
Then I deny everyone the securedEnpoint
Then I allow auth0 IP addresses access to the securedEnd endpoint - my IP was also on that list I've removed it for security.
The securedEndpoint doesn't have an authorizer attached, with this policy applied ALL endpoints return 403 from APIG - I'm using serverless to deploy this, what you see below is the resulting JSON from the resource policy section in the APIG console.
{
"Version": "2012-10-17",
"Statement": [
{
"Effect": "Allow",
"Principal": "*",
"Action": "execute-api:Invoke",
"Resource": "eu-west-2:ACCOUNT_ID:API_ID/*/*/*"
},
{
"Effect": "Allow",
"Principal": "*",
"Action": "execute-api:Invoke",
"Resource": "eu-west-2:ACCOUNT_ID:API_ID/*/*/allowedEndPoint"
},
{
"Effect": "Deny",
"Principal": "*",
"Action": "execute-api:Invoke",
"Resource": "eu-west-2:ACCOUNT_ID:API_ID/*/POST/securedEndpoint"
},
{
"Effect": "Allow",
"Principal": "*",
"Action": "execute-api:Invoke",
"Resource": "eu-west-2:ACCOUNT_ID:API_ID/*/POST/securedEndpoint",
"Condition": {
"IpAddress": {
"aws:SourceIp": [
"138.91.154.99",
"54.183.64.135",
"54.67.77.38",
"54.67.15.170",
"54.183.204.205",
"54.173.21.107",
"54.85.173.28",
"35.167.74.121",
"35.160.3.103",
"35.166.202.113",
"52.14.40.253",
"52.14.38.78",
"52.14.17.114",
"52.71.209.77",
"34.195.142.251",
"52.200.94.42"
]
}
}
}
]
}

AWS Lambda Access Denied on Pre-Signed CloudFront URL

I was following the guide from https://docs.aws.amazon.com/solutions/latest/serverless-image-handler/deployment.html to create a new Lambda Function over my CloudFront distribution. However, I have an extra requirement to only use the pre-signed URLs. The idea is that my service generates the CloudFront pre-signed URL and gives that URL to the client to access it. However, client should be able to invoke the Lambda Function on that URL.
For example the following should be possible:
Service returns the URL https://dfg565mo4z0svb.cloudfront.net/portrait.jpeg?Expires=1540724061&Signature=VLfwYdHrLM91wzFyOg0S3C6PKkKWghfOiZzt1-ew~gt0HPK~Sap0~5PHVHCEDHgHIQfwb0~oAZQ1igOOiRigzMTQ-ew~uSIR7-dsd~QJlAuceO5f2cDB2hopC5~trEgRTMnQSozPlbrFSwthveVBlZPVI3s2YapZgC7pqZB08IKIYtcXKjRfMPkxgumV5P-~Dj7rK5fdfvLyvTUTxIwrt3WLndOydBjxxUsL-6D-Hkdz8uWi6u59-sg__&Key-Pair-Id=BPKDVBLKFPWSDLIAXN8I
The client should be able to invoke Lambda like this: https://dfg565mo4z0svb.cloudfront.net/fit-in/100x100/portrait.jpeg?Expires=1540724061&Signature=VLfwYdHrLM91wzFyOg0S3C6PKkKWghfOiZzt1-ew~gt0HPK~Sap0~5PHVHCEDHgHIQfwb0~oAZQ1igOOiRigzMTQ-ew~uSIR7-dsd~QJlAuceO5f2cDB2hopC5~trEgRTMnQSozPlbrFSwthveVBlZPVI3s2YapZgC7pqZB08IKIYtcXKjRfMPkxgumV5P-~Dj7rK5fdfvLyvTUTxIwrt3WLndOydBjxxUsL-6D-Hkdz8uWi6u59-sg__&Key-Pair-Id=BPKDVBLKFPWSDLIAXN8I
where /fit-in/100x100/ is the Lambda Function.
All of that works by the default, but if I set the Restrict Viewer Access
(Use Signed URLs or Signed Cookies) option under Origin Behaviour to Yes, then suddenly any call to my Lambda Function returns the Access Denied response.
IAM Policy of the Role that my Lambda Function is using
{
"Version": "2012-10-17",
"Statement": [
{
"Effect": "Allow",
"Action": [
"logs:CreateLogGroup",
"logs:CreateLogStream",
"logs:PutLogEvents"
],
"Resource": "arn:aws:logs:*:*:*"
},
{
"Effect": "Allow",
"Action": [
"s3:PutObject",
"s3:GetObject"
],
"Resource": "arn:aws:s3:::myBucket/*"
}
]
}
Bucket Policy
{
"Version": "2008-10-17",
"Id": "PolicyForCloudFrontPrivateContent",
"Statement": [
{
"Sid": "1",
"Effect": "Allow",
"Principal": {
"AWS": "arn:aws:iam::cloudfront:user/CloudFront Origin Access Identity EN2PJ6YY7V8EE"
},
"Action": "s3:GetObject",
"Resource": "arn:aws:s3:::myBucket/*"
},
{
"Sid": "2",
"Effect": "Allow",
"Principal": {
"AWS": "arn:aws:iam::cloudfront:user/CloudFront Origin Access Identity E2EM2OLBKAK85T"
},
"Action": "s3:GetObject",
"Resource": "arn:aws:s3:::myBucket/*"
}
]
}
How can I use the presigned URLs with Lambda?