API Gateway Resource policy returning 403 - amazon-web-services

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

Related

Unable to hit AWS api gateway endpoint from EC2 instance in the same VPC using a resource policy

I have an ec2 instance inside a VPC, and I'd like to limit access to my api gateway to just that VPC. It seems like this should be really simple based on the examples they give, but for some reason I can't access it from my ec2 instance with this policy:
{
"Version": "2012-10-17",
"Statement":
[
{
"Effect": "Deny",
"Principal": "*",
"Action": "execute-api:Invoke",
"Resource": "execute-api:*",
"Condition":
{
"StringNotEquals":
{
"aws:sourceVpc": "vpc-******"
}
}
},
{
"Effect": "Allow",
"Principal": "*",
"Action": "execute-api:Invoke",
"Resource": "execute-api:*"
}
]
}
It seems very straight-forward, but attempting to hit an endpoint gives me this error: User: anonymous is not authorized to perform: execute-api:Invoke on resource: arn:aws:execute-api:...
Other things I've tried:
Changing the "Resource" value to "execute-api/*"
Using the arn value as the Resource instead of "execute-api..."
Switching the order of the Deny and Allow statements
Just using an allow statement like so:
"Effect": "Allow",
"Principal": "*",
"Action": "execute-api:Invoke",
"Resource": "arn:***",
"Condition": {
"StringEquals": {
"aws:SourceVpc": "vpc-*****"
}
}
}

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

How can I deny public access to an AWS API gateway while allowing access by only a specific role?

I would like to deny public access to an AWS API Gateway and only allow access when the API is invoked with a specific role. In my test there are two gateways, and one calls the other:
Public Gateway -> Private Gateway
I want to be able to visit Public Gateway endpoints in a browser and receive a 2XX response, and when visiting the Private Gateway directly I should receive a 4XX response. The only way to access the Private Gateway should be via the Public Gateway (which proxies to the Private Gateway with each endpoint).
I've tried several policies. All of these always result in the Public Gateway error logs showing the following:
User: anonymous is not authorized to perform: execute-api:Invoke on resource: arn:aws:execute-api:us-east-1:********9012:abcd123456/dev/GET/products
That error message is received by the Public Gateway as a response from the Private Gateway.
Here are policies I've tried (separately):
{
"Version": "2012-10-17",
"Statement": [
{
"Effect": "Deny",
"Principal": "*",
"Action": "execute-api:Invoke",
"Resource": "arn:aws:execute-api:us-east-1:123456789012:abcd123456/*",
"Condition": {
"StringNotEquals": {
"aws:PrincipalArn": "arn:aws:iam::123456789012:role/test-apigateway-role"
}
}
}
]
}
{
"Version": "2012-10-17",
"Statement": [
{
"Effect": "Deny",
"NotPrincipal": {
"AWS": [
"arn:aws:iam::123456789012:role/test-apigateway-role",
"arn:aws:iam::123456789012:root"
]
},
"Action": "execute-api:Invoke",
"Resource": "arn:aws:execute-api:us-east-1:123456789012:abcd123456/*"
}
]
}
{
"Version": "2012-10-17",
"Statement": [
{
"Effect": "Deny",
"Principal": "*",
"Action": "execute-api:Invoke",
"Resource": "arn:aws:execute-api:us-east-1:123456789012:abcd123456/*/*/*",
"Condition": {
"ArnNotEquals": {
"aws:PrincipalArn": "arn:aws:iam::123456789012:role/test-apigateway-role"
}
}
},
{
"Effect": "Allow",
"Principal": "*",
"Action": "execute-api:Invoke",
"Resource": "arn:aws:execute-api:us-east-1:123456789012:abcd123456/*/*/*"
}
]
}
{
"Version": "2012-10-17",
"Statement": [
{
"Effect": "Deny",
"Principal": "*",
"Action": "execute-api:Invoke",
"Resource": "arn:aws:execute-api:us-east-1:123456789012:abcd123456/*",
"Condition": {
"StringNotEquals": {
"aws:PrincipalArn": "arn:aws:iam::123456789012:role/test-apigateway-role"
}
}
},
{
"Effect": "Allow",
"Principal": "*",
"Action": "execute-api:Invoke",
"Resource": "arn:aws:execute-api:us-east-1:123456789012:abcd123456/*/*/*"
}
]
}
{
"Version": "2012-10-17",
"Statement": [
{
"Effect": "Deny",
"Principal": "*",
"Action": "execute-api:Invoke",
"Resource": "arn:aws:execute-api:us-east-1:123456789012:abcd123456/*",
"Condition": {
"StringNotEquals": {
"aws:PrincipalArn": "arn:aws:iam::123456789012:role/test-apigateway-role"
}
}
},
{
"Effect": "Allow",
"Principal": "*",
"Action": "execute-api:Invoke",
"Resource": "arn:aws:execute-api:us-east-1:123456789012:abcd123456/*/*/*",
"Condition": {
"StringEquals": {
"aws:PrincipalArn": "arn:aws:iam::123456789012:role/test-apigateway-role"
}
}
}
]
}
I've redeployed with each Resource Policy change and waited one minute before testing.
The role is assigned in the Public Gateway's serverless.yml settings:
service: test-gateway
provider:
name: aws
runtime: nodejs12.x
apiGateway:
shouldStartNameWithService: true
role: arn:aws:iam::123456789012:role/test-apigateway-role
How about trying this?
According to the docs, if you don't specify an explicit Deny, and then provide a specific Allow, it should work. If it doesn't, keep sharing your outputs, I'm intrigued.
Update: I removed the Deny * part, this means we'll get an implicit deny for requests that are not specifically declared in an Allow statement. This is according to Sessions policies (see docs link)
Update 2: Check this answer's comments, the author also mentioned - added authorizer: aws_iam to serverless.yml
{
"Version": "2012-10-17",
"Statement": [
{
"Effect": "Allow",
"Principal": {
"AWS": [
"arn:aws:iam::123456789012:role/test-apigateway-role"
]
},
"Action": "execute-api:Invoke",
"Resource": [
"arn:aws:execute-api:us-east-1:123456789012:abcd123456/*"
]
}
]
}

AWS Elasticsearch Access Policy ridiculously fickle

I want to create an AWS Elasticsearch with this policy, to enable specific access from IAM roles, set admin IPs, and public read only. ES Console keeps returning an error "Error setting policy". I can't work out why this would not be allowed?
{
"Version": "2012-10-17",
"Statement": [
{
"Effect": "Allow",
"Principal": {
"AWS": "arn:aws:iam::<id>:role/<lambda role 1 name>"
},
"Action": "es:ESHttpPost",
"Resource": "arn:aws:es:eu-west-1:<id>:domain/*/*"
},
{
"Effect": "Allow",
"Principal": {
"AWS": "arn:aws:iam::<id>:role/<lambda role 2 name>"
},
"Action": "es:ESHttpDelete",
"Resource": "arn:aws:es:eu-west-1:<id>:domain/*/*"
},
{
"Effect": "Allow",
"Principal": {
"AWS": "*"
},
"Action": "es:*",
"Resource": "arn:aws:es:eu-west-1:<id>:domain/*/*",
"Condition": {
"IpAddress": {
"aws:SourceIp": [
"<ip1>",
"<ip2>",
"<ip3>"
]
}
}
},
{
"Effect": "Allow",
"Principal": {
"AWS": "*"
},
"Action": "es:ESHttpGet",
"Resource": "arn:aws:es:eu-west-1:<id>:domain/*/*"
}
]
}
It's in eu-west-1 and version 7.1. I've tried variations like es:* and putting principals in an array (like in the provided templates) but these are all rejected?! I can seemingly only have 2 statements, with 1 principal in each (* and 1 of these IAMs).
Is there a better recommended way? Like putting it behind API Gateway or something. I saw reverse proxy in the docs but this seems like a ridiculous overkill and $$$.

How to allow only an IP/range access to AWS API Gateway resources

How best can I restrict access to certain routes in AWS API gateway by IP?
I want to allow only my ECS cluster to access certain routes in API gateway. I tried putting the ECS NAT gateway, the VPC CIDR range in aws:SourceIp but always get denied. I even tried my personal computer public IP address ... same results ... Is this the correct way? Or should I try IAM authorizers? The downside with IAM authorizer is I need to sign my API calls? Perhaps using the API Gateway SDK? Which means code change I prefer to avoid.
{
"Id": "MY_API_POLICY",
"Version": "2012-10-17",
"Statement": [
{
"Effect": "Deny",
"Principal": "*",
"Action": "execute-api:Invoke",
"Condition": {
"NotIpAddress": {
"aws:SourceIp": ["XX.XX.XX.XX/32"]
}
},
"Resource": [
"arn:aws:execute-*:*:apiid/stagename/*/private/route"
]
},
{
"Effect": "Allow",
"Principal": "*",
"Action": "execute-api:Invoke",
"Resource": [
"arn:aws:execute-*:*:apiid/stagename/*/public/route"
]
}
]
}
As #Visal already mentioned is restricting the ip/range is the correct way. Here is the example: https://aws.amazon.com/de/blogs/compute/control-access-to-your-apis-using-amazon-api-gateway-resource-policies/
There is an example for a policy that allows the access for a certain ip range:
{
"Version": "2012-10-17",
"Statement": [
{
"Effect": "Allow",
"Principal": {
"AWS": [
"arn:aws:iam::<account_idA>:user/<user>",
"arn:aws:iam::<account_idA>:root"
]
},
"Action": "execute-api:Invoke",
"Resource": "arn:aws:execute-api:us-east-1:<account_idB>:qxz8y9c8a4/*/*/*"
},
{
"Effect": "Allow",
"Principal": "*",
"Action": "execute-api:Invoke",
"Resource": "arn:aws:execute-api:us-east-1:<account_idB>:qxz8y9c8a4/*",
"Condition": {
"IpAddress": {
"aws:SourceIp": " 203.0.113.0/24"
}
}
}
]
}
Or if you want to deny the access then you will find this policy:
{
"Effect": "Deny",
"Principal": "*",
"Action": "execute-api:Invoke",
"Resource": "arn:aws:execute-api:us-east-1:<account_idB>:qxz8y9c8a4/*",
"Condition": {
"IpAddress": {
"aws:SourceIp": "203.0.113.0/24"
}
}
}