Private API Gateway - Part 2: Secure Cross-VPC Access with PrivateLink and IAM Authentication

2024-12-06

🔍 Overview

In Part 1, we deployed a private Employee Directory API using Lambda, API Gateway and Interface Endpoints. Now, we’ll:

  • Enable secure cross-VPC access using VPC Peering and PrivateLink
  • Add IAM-based SigV4 authentication to protect the API

🌐 Cross-VPC Access with PrivateLink

If you want consumers in a different VPC/account to call your API:

1. Enable Private DNS (already done)

Ensure private_dns_enabled = true on your aws_vpc_endpoint.

2. VPC Peering or Transit Gateway

For same-account cross-VPC:

resource "aws_vpc_peering_connection" "peer" {
  vpc_id        = aws_vpc.main.id
  peer_vpc_id   = aws_vpc.other.id
  auto_accept   = true
}

resource "aws_route" "to_peer" {
  route_table_id         = aws_route_table.main.id
  destination_cidr_block = aws_vpc.other.cidr_block
  vpc_peering_connection_id = aws_vpc_peering_connection.peer.id
}

For different-account, use PrivateLink with NLB + Endpoint Service (optional advanced setup).

🔐 Add IAM-Based Authentication

We now want IAM-authenticated access to our API.

1. Update API Gateway Method

resource "aws_api_gateway_method" "get" {
  rest_api_id   = aws_api_gateway_rest_api.private_api.id
  resource_id   = aws_api_gateway_resource.employee.id
  http_method   = "GET"
  authorization = "AWS_IAM"
}

2. Create IAM Role for Client

resource "aws_iam_user" "api_client" {
  name = "internal-api-client"
}

resource "aws_iam_policy" "invoke_api" {
  name   = "InvokePrivateAPI"
  policy = jsonencode({
    Version: "2012-10-17",
    Statement: [{
      Effect: "Allow",
      Action: "execute-api:Invoke",
      Resource: "arn:aws:execute-api:${var.region}:${data.aws_caller_identity.current.account_id}:${aws_api_gateway_rest_api.private_api.id}/*"
    }]
  })
}

resource "aws_iam_user_policy_attachment" "attach" {
  user       = aws_iam_user.api_client.name
  policy_arn = aws_iam_policy.invoke_api.arn
}

3. Test with SigV4

Install AWS CLI or use awscurl:

awscurl --service execute-api \
  --region us-east-1 \
  --access_key <AKIA...> \
  --secret_key <SECRET> \
  https://<rest-api-id>.execute-api.us-east-1.amazonaws.com/prod/employee/1002

You can now control access by IAM policies and optionally federate via Cognito/SAML if needed.


✅ Summary

We’ve now:

  • Enabled secure cross-VPC access using PrivateLink/VPC peering
  • Enforced IAM-based authentication using AWS_IAM
  • Set up a realistic, secure, internal API stack

Next article: Add observability (CloudWatch Logs + X-Ray), throttling and versioned deployments with stages.


Related Posts