Skip to main content

Internet Gateway - Internet Connectivity

Provide internet access for resources in VPC public subnets.

Prerequisite: AWSProvider Configuration​

Before creating any AWS resource, you need to configure an AWSProvider that manages credentials and authentication with AWS.

IRSA:

apiVersion: aws-infra-operator.runner.codes/v1alpha1
kind: AWSProvider
metadata:
name: production-aws
namespace: default
spec:
region: us-east-1
roleARN: arn:aws:iam::123456789012:role/infra-operator-role
defaultTags:
managed-by: infra-operator
environment: production

Static Credentials:

apiVersion: v1
kind: Secret
metadata:
name: aws-credentials
namespace: default
type: Opaque
stringData:
access-key-id: test
secret-access-key: test
---
apiVersion: aws-infra-operator.runner.codes/v1alpha1
kind: AWSProvider
metadata:
name: localstack
namespace: default
spec:
region: us-east-1
accessKeyIDRef:
name: aws-credentials
key: access-key-id
secretAccessKeyRef:
name: aws-credentials
key: secret-access-key
defaultTags:
managed-by: infra-operator
environment: test

Check Status:

kubectl get awsprovider
kubectl describe awsprovider production-aws
warning

For production, always use IRSA (IAM Roles for Service Accounts) instead of static credentials.

Create IAM Role for IRSA​

To use IRSA in production, you need to create an IAM Role with the necessary permissions:

Trust Policy (trust-policy.json):

{
"Version": "2012-10-17",
"Statement": [
{
"Effect": "Allow",
"Principal": {
"Federated": "arn:aws:iam::123456789012:oidc-provider/oidc.eks.us-east-1.amazonaws.com/id/EXAMPLED539D4633E53DE1B71EXAMPLE"
},
"Action": "sts:AssumeRoleWithWebIdentity",
"Condition": {
"StringEquals": {
"oidc.eks.us-east-1.amazonaws.com/id/EXAMPLED539D4633E53DE1B71EXAMPLE:sub": "system:serviceaccount:infra-operator-system:infra-operator-controller-manager",
"oidc.eks.us-east-1.amazonaws.com/id/EXAMPLED539D4633E53DE1B71EXAMPLE:aud": "sts.amazonaws.com"
}
}
}
]
}

IAM Policy - Internet Gateway (igw-policy.json):

{
"Version": "2012-10-17",
"Statement": [
{
"Effect": "Allow",
"Action": [
"ec2:CreateInternetGateway",
"ec2:DeleteInternetGateway",
"ec2:DescribeInternetGateways",
"ec2:AttachInternetGateway",
"ec2:DetachInternetGateway",
"ec2:CreateTags",
"ec2:DeleteTags",
"ec2:DescribeTags"
],
"Resource": "*"
}
]
}

Create Role with AWS CLI:

# 1. Get OIDC Provider from EKS cluster
export CLUSTER_NAME=my-cluster
export AWS_REGION=us-east-1
export AWS_ACCOUNT_ID=$(aws sts get-caller-identity --query Account --output text)

OIDC_PROVIDER=$(aws eks describe-cluster \
--name $CLUSTER_NAME \
--region $AWS_REGION \
--query "cluster.identity.oidc.issuer" \
--output text | sed -e "s/^https:\/\///")

# 2. Update trust-policy.json with correct values
cat > trust-policy.json <<EOF
{
"Version": "2012-10-17",
"Statement": [
{
"Effect": "Allow",
"Principal": {
"Federated": "arn:aws:iam::${AWS_ACCOUNT_ID}:oidc-provider/${OIDC_PROVIDER}"
},
"Action": "sts:AssumeRoleWithWebIdentity",
"Condition": {
"StringEquals": {
"${OIDC_PROVIDER}:sub": "system:serviceaccount:infra-operator-system:infra-operator-controller-manager",
"${OIDC_PROVIDER}:aud": "sts.amazonaws.com"
}
}
}
]
}
EOF

# 3. Create IAM Role
aws iam create-role \
--role-name infra-operator-igw-role \
--assume-role-policy-document file://trust-policy.json \
--description "Role for Infra Operator Internet Gateway management"

# 4. Create and attach policy
aws iam put-role-policy \
--role-name infra-operator-igw-role \
--policy-name InternetGatewayManagement \
--policy-document file://igw-policy.json

# 5. Get Role ARN
aws iam get-role \
--role-name infra-operator-igw-role \
--query 'Role.Arn' \
--output text

Annotate Operator ServiceAccount:

# Add annotation to operator ServiceAccount
kubectl annotate serviceaccount infra-operator-controller-manager \
-n infra-operator-system \
eks.amazonaws.com/role-arn=arn:aws:iam::123456789012:role/infra-operator-igw-role
note

Replace 123456789012 with your AWS Account ID and EXAMPLED539D4633E53DE1B71EXAMPLE with your OIDC provider ID.

Overview​

An Internet Gateway (IGW) is a VPC component that enables communication between resources in the VPC and the internet. It is horizontally scalable, redundant, and highly available by design.

Features:

  • Allows egress traffic to the internet
  • Allows ingress traffic from the internet
  • Supports IPv4 and IPv6
  • No additional cost (only data traffic)
  • One IGW per VPC

Quick Start​

Basic Internet Gateway:

apiVersion: aws-infra-operator.runner.codes/v1alpha1
kind: InternetGateway
metadata:
name: e2e-igw
namespace: default
spec:
providerRef:
name: localstack
vpcID: REPLACE_WITH_VPC_ID
tags:
Name: e2e-internet-gateway
ManagedBy: infra-operator
deletionPolicy: Delete

Production Internet Gateway:

apiVersion: aws-infra-operator.runner.codes/v1alpha1
kind: InternetGateway
metadata:
name: production-igw
namespace: default
spec:
providerRef:
name: production-aws
vpcID: vpc-0a1b2c3d4e5f6g7h8
tags:
Name: production-internet-gateway
Environment: production
ManagedBy: infra-operator
CostCenter: networking
deletionPolicy: Retain

Apply:

kubectl apply -f internet-gateway.yaml

Check Status:

kubectl get internetgateway
kubectl describe internetgateway e2e-igw

Configuration Reference​

Required Fields​

Reference to the AWSProvider resource

Name of the AWSProvider resource

AWS VPC ID where the Internet Gateway will be attached (e.g., vpc-0a1b2c3d4e5f6g7h8)

note

Use REPLACE_WITH_VPC_ID during deployment and replace with the actual VPC ID after its creation, or use the status.vpcID field from an existing VPC resource.

Optional Fields​

Key-value pairs to tag the Internet Gateway

Example:

tags:
Name: production-igw
Environment: production
Team: platform

What happens to the IGW when the CR is deleted

Options:

  • Delete: IGW is deleted from AWS
  • Retain: IGW remains in AWS but unmanaged

Status Fields​

After the Internet Gateway is created, the following status fields are populated:

AWS Internet Gateway identifier (e.g., igw-0a1b2c3d4e5f6g7h8)

ID of the VPC to which the IGW is attached

IGW attachment state

  • attaching: IGW is being attached to the VPC
  • attached: IGW is attached and ready for use
  • detaching: IGW is being detached
  • detached: IGW has been detached

true when the IGW is attached and ready for use

Timestamp of the last synchronization with AWS

Examples​

Internet Gateway for Production​

Example:

apiVersion: aws-infra-operator.runner.codes/v1alpha1
kind: InternetGateway
metadata:
name: production-igw
namespace: default
spec:
providerRef:
name: production-aws

vpcID: vpc-0a1b2c3d4e5f6g7h8

tags:
Name: production-internet-gateway
Environment: production
ManagedBy: infra-operator
CostCenter: networking

# Keep IGW if CR is deleted
deletionPolicy: Retain

Internet Gateway for Development​

Example:

apiVersion: aws-infra-operator.runner.codes/v1alpha1
kind: InternetGateway
metadata:
name: dev-igw
namespace: default
spec:
providerRef:
name: localstack

vpcID: vpc-f3ea9b1b36fce09cd

tags:
Name: development-internet-gateway
Environment: development
AutoShutdown: "true"

# Delete IGW on cleanup
deletionPolicy: Delete

Complete Configuration with VPC​

VPC:

apiVersion: aws-infra-operator.runner.codes/v1alpha1
kind: VPC
metadata:
name: app-vpc
namespace: default
spec:
providerRef:
name: production-aws
cidrBlock: "10.0.0.0/16"
enableDnsSupport: true
enableDnsHostnames: true
tags:
Name: application-vpc
deletionPolicy: Delete

Internet Gateway:

apiVersion: aws-infra-operator.runner.codes/v1alpha1
kind: InternetGateway
metadata:
name: app-igw
namespace: default
spec:
providerRef:
name: production-aws
vpcID: REPLACE_WITH_VPC_ID
tags:
Name: application-igw
deletionPolicy: Delete

Public Subnet:

apiVersion: aws-infra-operator.runner.codes/v1alpha1
kind: Subnet
metadata:
name: app-public-subnet
namespace: default
spec:
providerRef:
name: production-aws
vpcID: REPLACE_WITH_VPC_ID
cidrBlock: "10.0.1.0/24"
availabilityZone: us-east-1a
mapPublicIpOnLaunch: true
tags:
Name: public-subnet-1a
Type: public
deletionPolicy: Delete

Verification​

Check IGW Status​

Command:

# List all Internet Gateways
kubectl get internetgateways

# Get detailed information
kubectl get internetgateway production-igw -o yaml

# Watch creation progress
kubectl get internetgateway production-igw -w

Check on AWS​

AWS CLI:

# List Internet Gateways
aws ec2 describe-internet-gateways --internet-gateway-ids igw-xxx

# Get IGW details
aws ec2 describe-internet-gateways \
--internet-gateway-ids igw-xxx \
--query 'InternetGateways[0]' \
--output json

LocalStack:

# For testing with LocalStack
export AWS_ENDPOINT_URL=http://localhost:4566

aws ec2 describe-internet-gateways \
--internet-gateway-ids igw-xxx

Expected Output​

Example:

status:
internetGatewayID: igw-0a1b2c3d4e5f6g7h8
vpcID: vpc-f3ea9b1b36fce09cd
state: attached
ready: true
lastSyncTime: "2025-11-22T20:30:15Z"

Troubleshooting​

IGW does not attach to VPC​

Symptoms: IGW remains in attaching state

Common causes:

  1. VPC does not exist or is not ready
  2. Another IGW is already attached to the VPC
  3. Insufficient IAM permissions

Solutions:

# Check if VPC exists and is ready
kubectl get vpc my-vpc

# Check if an IGW already exists in the VPC
aws ec2 describe-internet-gateways \
--filters "Name=attachment.vpc-id,Values=vpc-xxx"

# Check controller logs
kubectl logs -n infra-operator-system \
deploy/infra-operator-controller-manager \
--tail=100

VPC already has IGW attached​

Error: "Resource has a dependency violation"

Cause: A VPC can only have one Internet Gateway attached

Solutions:

  1. Use the existing IGW
  2. Or detach the old IGW before attaching a new one

Command:

# List IGWs in the VPC
aws ec2 describe-internet-gateways \
--filters "Name=attachment.vpc-id,Values=vpc-xxx"

Deletion stuck​

Symptoms: IGW deletion takes too long or gets stuck

Cause: IGW still has dependencies (route tables pointing to it)

Solutions:

# Check route tables using the IGW
aws ec2 describe-route-tables \
--filters "Name=route.gateway-id,Values=igw-xxx"

# Remove routes before deleting IGW
# (normally managed automatically by the operator)

# Force deletion if necessary
kubectl delete internetgateway my-igw --force --grace-period=0

Internet does not work after creating IGW​

Symptoms: Resources in public subnet cannot access the internet

Cause: Missing route table configuration

Solutions:

  1. Check if the route table has a route to 0.0.0.0/0 pointing to the IGW
  2. Check if the subnet is associated with the correct route table
  3. Check security groups and NACLs

Command:

# Check route tables
aws ec2 describe-route-tables \
--filters "Name=vpc-id,Values=vpc-xxx"

Best Practices​

Best Practices
  • One IGW per VPC — AWS allows only one IGW attached to a VPC
  • Reuse IGW for all public subnets — No need for multiple IGWs in same VPC
  • Attach before routing — IGW must be attached to VPC before adding routes
  • Tag consistently — Include VPC name and environment in IGW tags
  • Never delete IGW with active routes — Remove route table entries first

Public Network Architecture​

Internet Gateway Architecture