Bootstrap FreeKB - Amazon Web Services (AWS) - Create API Gateway PRIVATE REST API
Amazon Web Services (AWS) - Create API Gateway PRIVATE REST API


This assumes you have already configured the aws command line tool. If not, check out my article on Getting Started with the AWS CLI.

There are different type of routes that can be created with Amazon Web Services (AWS) API Gateway.

  • HTTP route
  • REST API route (this article)

At a high level, you will

  • Create a backend service that the API Gateway will route requests onto (a Lambda Function in this example)
  • Create the API Gateway REST API
  • Update the API Gateway REST API with methods (e.g. GET, POST)
  • Create a Security Group that allows HTTPS port 443
  • Attach a Resource Policy to the REST API to only allow requests in the same Virtual Private Cloud (VPC) as the REST API
  • Create a Virtual Private Cloud (VPC) execute-api Endpoint that uses a Security Group that allows incoming requests on HTTPS port 443
  • Create or Update and IAM Role with a Trust Policy and Permission Policy that will allow the API Gateway to assume the Role
  • Integrate the Lambda Function with the API Gateway
  • Update the API Gateway Response to return 200 OK
  • Deploy the REST API

 

For this walkthrough, let's say you have a Lambda Function that returns "Hello from Lambda!".

 


Create API Gateway REST API

The aws apigateway create-rest-api command can be used to create the API Gateway REST API. By default, the endpoint will be EDGE. The --endpoint-configuration option can be used to set the REST API endpoint type to private.

~]$ aws apigateway create-rest-api --name my-rest-api --endpoint-configuration='{"types":["PRIVATE"]}'
{
    "apiKeySource": "HEADER",
    "name": "my-rest-api",
    "createdDate": 1704766329,
    "endpointConfiguration": {
        "types": [
            "PRIVATE"
        ]
    },
    "id": "o03n2c8eha"
}

 

At this point, if you were to look at the API Gateway in the AWS console, you would see the API Gateway has no methods, such as GET or POST.

 


Update the API Gateway REST API with methods (e.g. GET, POST)

The aws apigateway get-resources command can be used to see that the API Gateway has no methods.

~]$ aws apigateway get-resources --rest-api-id o03n2c8eha
{
    "items": [
        {
            "id": "6gv3n2wtze",
            "path": "/",
            "resourceMethods": {}
        }
    ]
}

 

The aws apigateway put-method command can be used to update the API Gateway REST API with the methods it will allow, such as GET.

aws apigateway put-method \
--rest-api-id o03n2c8eha \
--resource-id 6gv3n2wtze \
--http-method GET \
--authorization-type "NONE" \
--no-api-key-required

 

And POST.

aws apigateway put-method \
--rest-api-id o03n2c8eha \
--resource-id 6gv3n2wtze \
--http-method POST \
--authorization-type "NONE" \
--no-api-key-required

 

Now the aws apigateway get-resources command should show that the API Gateway has methods.

~]$ aws apigateway get-resources --rest-api-id 2885zecrwj
{
    "items": [
        {
            "id": "sf6n2hrix7",
            "path": "/",
            "resourceMethods": {
                "GET": {},
                "POST": {}
            }
        }
    ]
}

 

Likewise, in the AWS console, the API Gateway should have the methods.

 


Create a Security Group that allows HTTPS port 443

The aws ec2 describe-vpcs command can be used to list your Virtual Private Clouds (VPCs).

~]$ aws ec2 describe-vpcs
{
    "Vpcs": [
        {
            "CidrBlock": "10.0.0.0/24",
            "DhcpOptionsId": "dopt-017f0a715e4ce2fc9",
            "State": "available",
            "VpcId": "vpc-0a9d4cb29e2748444",
            "OwnerId": "123456789012",
            "InstanceTenancy": "default",
            "CidrBlockAssociationSet": [
                {
                    "AssociationId": "vpc-cidr-assoc-07bcabb27322c8281",
                    "CidrBlock": "10.0.0.0/24",
                    "CidrBlockState": {
                        "State": "associated"
                    }
                },
                {
                    "AssociationId": "vpc-cidr-assoc-0113cedd8171ec855",
                    "CidrBlock": "10.31.0.0/16",
                    "CidrBlockState": {
                        "State": "associated"
                    }
                }
            ],
            "IsDefault": false,
            "Tags": [
                {
                    "Key": "Name",
                    "Value": "my-vpc"
                }
            ]
        }
    ]
]

 

Almost always, requests will be submitted to the REST API over HTTPS port 443. The aws ec2 create-security-group command can be used to create a Security Group in your VPC.

~]$ aws ec2 create-security-group --vpc-id vpc-0a9d4cb29e2748444 --group-name apiGatewayRestApi --description apiGatewayRestApi --tag-specifications 'ResourceType=security-group,Tags=[{Key=Name,Value=apiGatewayRestApi}]'           {
    "GroupId": "sg-083870552fd33fe48",
    "Tags": [
        {
            "Key": "Name",
            "Value": "apiGatewayRestApi"
        }
    ]
}

 

And then the aws ec2 authorize-security-group-ingress command can be used to allow incoming requests on HTTPS port 443.

aws ec2 authorize-security-group-ingress --group-id sg-083870552fd33fe48 --protocol tcp --port 443 --cidr 0.0.0.0/0

 


Virtual Private Cloud endpoint

The aws ec2 describe-subnets command can be used to get the subnet IDs in your VPC.

~]$ aws ec2 describe-subnets --filter "Name=vpc-id,Values=vpc-0a9d4cb29e2748444" | grep "SubnetId"
            "SubnetId": "subnet-0f015da3a1e164304",
            "SubnetId": "subnet-0d2d8580c46d6d280",
            "SubnetId": "subnet-02b9845e7366bdf89",
            "SubnetId": "subnet-075d4be5a8a07c818",

 

The aws ec2 create-vpc-endpoint command can be used to create a Virtual Private Cloud endpoint that will allow the execute-api service in the Virtual Private Cloud Subnets, allowing incoming requests listed in the Security Group you just created.

aws ec2 create-vpc-endpoint \
--vpc-id vpc-0a9d4cb29e2748444 \
--vpc-endpoint-type Interface \
--service-name com.amazonaws.us-east-1.execute-api \
--subnet-ids subnet-0f015da3a1e164304 subnet-0d2d8580c46d6d280 subnet-02b9845e7366bdf89 subnet-075d4be5a8a07c818 \
--security-group-id sg-083870552fd33fe48 \
--tag-specifications 'ResourceType=vpc-endpoint,Tags=[{Key=service,Value=execute-api}]'

 


Attach a Resource Policy to the REST API

Create a Resource Policy to only allow requests to be submitted to the REST API that originate in Virtual Private Cloud (VPC) vpc-123456789012.

{
    "Version": "2012-10-17",
    "Statement": [
        {
            "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-0a9d4cb29e2748444"
                }
            }
        }
    ]
}

 


IAM Role with Trust Policy and Permission Policy

Next we will be updating the API Gateway to be integrated with our Lambda Function. But we will first need an IAM Role that will allow the API Gateway service to assume the IAM Role and the Role will need to allow Lambda actions. Let's create a file with the following JSON. It can be named anything, such as my.json. Notice this will allow the apigateway.amazonaws.com service to assume the role. This is a Trust Policy. It's basically a way of saying "I trust you" or "I trust the apigateway.amazonaws.com service.

{
  "Version": "2012-10-17",
  "Statement": [
      {
          "Effect": "Allow",
          "Principal": { "Service": "apigateway.amazonaws.com" },
          "Action": "sts:AssumeRole"
      }
  ]
}

 

And then the aws iam create-role command can be used to create the role.

aws iam create-role --role-name my-role --assume-role-policy-document file://my.json

 

And then the aws iam attach-role-policy can be used to attach the AWSLambda_FullAccess Permission Policy to the role.

aws iam attach-role-policy --policy-arn arn:aws:iam::aws:policy/AWSLambda_FullAccess --role-name my-role

 


Update API Gateway Response

Let's add a response for 200 OK.

aws apigateway update-method-response \
--rest-api-id o03n2c8eha \
--resource-id 6gv3n2wtze \
--http-method POST \
--status-code 200

 

At this point, if you were to try to submit a request to the REST API from an EC2 instance in the same Virtual Private Cloud (VPC) as the API Gateway REST API, you should get something like "Could not resolve host".

~]$ curl --request POST --url https://o03n2c8eha.execute-api.us-east-1.amazonaws.com/
curl: (6) Could not resolve host: o03n2c8eha.execute-api.us-east-1.amazonaws.com

 

Beause the REST API needs to be deployed for it to be available. By default, creating the REST API does not deploy the REST API as can be seen by the fact that this command returns an empty list (no deployments).

~]$ aws apigateway get-deployments --rest-api-id 2885zecrwj
{
    "items": []
}

 

Let's create the first deployment.

aws apigateway create-deployment \
--rest-api-id 2885zecrwj \
--stage-name dev \
--stage-description "Development Stage" \
--description "First Deployment"

 

You should now be able to go to use the Test tab in the AWS API Gateway console and get a response from the Lambda Function.

 

Likewise, you should be able to submit a POST requests to the REST API and your Lambda Function should return output. In this example, the endpoint is /dev since the --stage-name of the deployment was dev.

~]$ curl --request POST --url https://o03n2c8eha.execute-api.us-east-1.amazonaws.com/dev
{"result": "success", "message": "Hello World"}

 




Did you find this article helpful?

If so, consider buying me a coffee over at Buy Me A Coffee



Comments


Add a Comment


Please enter 69f03c in the box below so that we can be sure you are a human.