8
votes

First of all I am very new to AWS. Here is what i'm trying to achieve:

  • 1 VPC
    • 2 Subnet
      • 1 public that contain some EC2 instance
      • 1 private that contain an API Gateway only accessible by the EC2 instance

The public subnet is working perfectly well, I can access SSH and HTTP. The private subnet cause me a little trouble. For debug purpose i launched off an EC2 instance in it. From one of the "public instance" I am able to ping the "private instance" private IP (Well there is no public IP obviously)

Following the documentation, I created a VPC Endpoint in my private subnet which created a Network interface where i attached a security group that allow HTTP(S) (80 and 443) from the whole VPC CIDR. The endpoint type is Interface

So, now i have a private subnet with an Endpoint that allow HTTP(S) traffic. That endpoint have some (private) DNS NAME and (probably) also a private IP (Could not find it)

Now I want to add an API Gateway to front some AWS lambda. I create said API and as an Endpoint Type -> Private

Following this : Official Documentation The "only" way to "link" the API Gateway to the VPC Endpoint is to add a resource policy. So I input the following

{
"Version": "2012-10-17",
"Statement": [
    {
        "Effect": "Deny",
        "Principal": "*",
        "Action": "execute-api:Invoke",
        "Resource": "arn:aws:execute-api:<REGION>:<MY ID>:<API GATEWAY ID>/*/*/<MY RESOURCE>",
        "Condition": {
            "StringNotEquals": {
                "aws:sourceVpce": "<VPC ENDPOINT ID>"
            }
        }
    },
    {
        "Effect": "Allow",
        "Principal": "*",
        "Action": "execute-api:Invoke",
        "Resource": "arn:aws:execute-api:<REGION>:<MY ID>:<API GATEWAY ID>/*/*/<MY RESOURCE>"
    }
]

}

And for the sake of completeness here is my lambda (python3.6):

from __future__ import division
def lambda_handler(event, context):
  return {
      "statusCode":200,
      "headers": {"Content-Type": "application/json" },
      "body" : "It work!"
  }

Finally the problem:

What would be the URL to invoke this REST Api! API Gateway (In the lamdba Console) Tell me this:

https://<API GATEWAY ID>.<REGION>.amazonaws.com/<MY STAGE>/<MY RESOURCE>

Ok! Lets call that url: APIURL I ssh to the EC2 instance in the public subnet and run the following:

curl https://$APIURL

And it work: It output: "It work!" but that APIURL does not seem to come from the VPC endpoint so I try the following (still from the public subnet EC2):

curl https://vpce-XXXXXXX-XXXX.execute-api.REGION.vpce.amazonaws.com/<MY STAGE>/<MY RESOURCE>

And i get: {"message":"Forbidden"}

That does not seem right. As i test i change de API Gateway resource policy for the following:

{
"Version": "2012-10-17",
"Statement": [
    {
        "Effect": "Deny",
        "Principal": "*",
        "Action": "execute-api:Invoke",
        "Resource": "arn:aws:execute-api:<REGION>:<MY ID>:<API ID>/*/*/<MY RESOURCE>"
    }
]

}

And NOTHING changed. The APIURL is still working and the VPCE Url still give me forbidden.

What am I doing wrong? My apologies for the long post.

2
if you update the resource policy, you need to deploy your api again. Otherwise, the changes will have no effect.matthewatabet
None of the answer provided despite giving useful information for people running in a similar issue really answer it. I think the problem was to "redeploy" it so it take the new configuration. Could you provide an answer base on your comment so i can accept it?drgn
absolutely -- added an answer.matthewatabet

2 Answers

6
votes

A policy role update does not take effect until the api has been deployed to a stage.

https://docs.aws.amazon.com/apigateway/latest/developerguide/apigateway-resource-policies-create-attach.html

If you update the resource policy after the API is created, you'll need to deploy the API to propagate the changes after you've attached the updated policy.

0
votes

As your API url is working fine,there seems to be a problem with the policy.
In IAM policy Deny permission will override the Allow permission. Try changing your policy to the following:

{
    "Version": "2012-10-17",
    "Statement": [
        {
            "Effect": "Allow",
            "Principal": "*",
            "Action": "execute-api:Invoke",
            "Resource": [
                "arn:aws:execute-api:region:account-id:api-id/*",
            "Condition": {
              "StringEquals":{
                             "aws:SourceVpce": "<VPC Endpoint ID>"
                         }
                       }
                    ]
        },
        {
            "Effect": "Deny",
            "Principal": "*",
            "Action": "execute-api:Invoke",
            "Resource": [
                "arn:aws:execute-api:region:account-id:api-id/*"
            ],
            "Condition" : {
                "StringNotEquals": {
                    "aws:SourceVpce": "<VPC Endpoint ID>"
                }
            }
        }
    ]
}

For further reference, follow this link:
https://aws.amazon.com/blogs/compute/introducing-amazon-api-gateway-private-endpoints/