Creating a secure API with AWS

I'm currently experimenting with hosting a Go application on AWS that will serve clients via a RESTful API. Because I don't want just anyone being able to access these endpoints I have to lock them down in some way. I can use JWT tokens to ensure I know who I'm talking to, but that doesn't really protect my server. What I'd really like to do is prevent the whole thing from being accessed unless it is from, or to, a specific endpoint and only that endpoint. I don't want to lay awake at night hoping I didn't leave port "x" open to the world.

Luckily AWS gives me a route to achieve my goals. It's not the most straightforward thing to do, and God knows the AWS documentation is a chore to read, but I think I've figured it out and I'll lay it out here.

High-level steps:

  1. Create a VPC
  2. Create an internal Network Load Balancer
  3. Get your application running on an EC2 within the private subnet
  4. Create a VPC Link in API Gateway (crucial step!)
  5. Create an API method within API Gateway

I'm no seasoned dev-ops vet so I was stabbing blindly at this setup for a little bit. The fundamental thing I didn't immediately wrap my head around was the VPC Link. When you create a private subnet the outside world is completely ignorant to anything within the subnet, so it's effectively useless for serving applications out of. Unless you could magically peek into it. This is where the VPC Links come in.

Setup an Elastic IP Address

You'll assign this to your Load Balancer

  • From the main AWS dashboard, go to the VPC Dashboard and select "Elastic IPs" on the left
  • Allocate an IP

Setup a private VPC

  • From the main dashboard, go (again) to the VPC Dashboard and select "Start VPC Wizard"
  • For my project I chose the public/private VPC option
  • Give your VPC a name
  • Choose an availability zone

    • This is important! You want everything you're doing in these steps to exist in the same zone.
  • Create VPC

Create your EC2s in the subnet

  • Create one "bridge" EC2 instance in the public portion of my subnet

    There may be a better way to do this

    • Set this public EC2 with the ability to be SSH'd into

      • This allows you to get your application into the private EC2
  • Create the EC2 instance which will serve your application

    • This will be in the private portion of your VPC
  • By using our "bridge" EC2 we can scp our application into it (the bridge) and then, from there, scp the application into the private EC2 instance

Create your Network Load Balancer

  • From the main AWS dashboard select the EC2 Dashboard
  • Select Load Balancers (lower left-ish)
  • Create a Network Load Balancer

    1. Name it
    2. Choose "internal" in the Scheme section
    3. Leave the listener at TCP port 80
    4. Select your newly created VPC from the dropdown
    5. Select your availability zone (the one where you created your VPC)
    6. Select the private subnet
    7. Click "Configure Routing"
  • On the Configure Routing page, leave everything as it is, but give a name to the "Name" section under the Target Group section (it was the second line for me)

    You're naming a Target Group which we'll define later

  • Click "Next: Register Targets"
  • This is where we tell the load balancer where to push the requests it will receive from API Gateway

    1. At the bottom of the page find your application server, and click the radio button attributed to it
    2. Click "Add to registered"
    3. Click "Next: Review"
    4. On the next page click "Create"

Create a VPC Link policy

As per the AWS docs you can either create a policy for a specific user (inline policy) or create it as a global. I chose the former

  • From the main AWS Dashboard click into the IAM section
  • Go to "Users" (This will be different if you're creating a global, assignable, policy. It's roughly the same idea though.)
  • Click on your user
  • In the lower-right click "Add inline policy"
  • Select the JSON tab
  • Remove what's there and (as per the docs), place this in its place:

    {
       "Version":"2012-10-17",
       "Statement":[
          {
             "Effect":"Allow",
             "Action":[
                "ec2:CreateVpcEndpointServiceConfiguration",
                "ec2:DeleteVpcEndpointServiceConfigurations",
                "ec2:DescribeVpcEndpointServiceConfigurations",
                "ec2:ModifyVpcEndpointServicePermissions"
             ],
             "Resource":"*"
          },
          {
             "Effect":"Allow",
             "Action":[
                "elasticloadbalancing:DescribeLoadBalancers"
             ],
             "Resource":"*"
          }
       ]
    }
  • Click "Review Policy" and finish it up

Configure Target Groups

  • From the main AWS Dashboard go to the EC2 Dashboard
  • In the lower left, right under "Load Balancers", select "Target Groups"
  • You should see the Target Group we created previously, select it
  • Select the "Targets" tab and click edit
  • Select your application server at the bottom and click "Add to registered"
  • Click "Save"
  • At some point, if everything went smoothly, the status of your registered target (i.e. your app server) will turn to "healthy"

Confirm your Network Load Balancer is listening to the right Target Group

  • From the Load Balancers page, select your load balancer
  • Click the Listeners tab

    1. If you see your target group under the "Default Action" column, continue to the next step (API Gateway)
    2. If you dont see your target group, click "Add Listener" and select the correct group, save it and move to the next step

Configure API Gateway

  • From the main AWS Dashboard go into the API Gateway page
  • Create an API

    1. Select "New API"
    2. Give it a name
    3. Give it a description (optional)
    4. Click "Create API"
  • Create a VPC Link

    1. Select "VPC Links" from the menu on the left
    2. Click "Create"
    3. Name it, give it a (optional) description
    4. Select your load balancer for the "Target NLB"
    5. Click "Create"

      Note: It will take about 4-5 minutes for the VPC Link creation to succeed

  • (Once the VPC Link has finished spinning up) Select your previously-created API

    These next few steps assume you're creating a GET endpoint, adjust as necessary

    1. Click the "Actions" dropdown and select "Create Method", select GET, click the little check mark
    2. Select VPC Link as the Integration Type
    3. Check Use Proxy Integration
    4. Select GET for Method
    5. For the endpoint URL:

      • Go back to the load balancer menu (Main Dashboard -> EC2 Dashboard -> Load Balancers)
      • Select your load balancer
      • Copy the DNS Name under the Basic Configuration section. It should look like: whateveryournamewas.23425asdasdf.elb..amazonaws.com
      • Go back to API Gateway and fill in the Endpoint Url Section with that and append your specific endpoint, e.g.

        • whateveryournamewas.23425asdasdf.elb..amazonaws.com:80/get/kittens

And that should be it! Some of the steps I took may be unnecessary or slighly wrong (I wrote this from memory). Feel free to reach out with questions. Enjoy!