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
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
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)
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 AWSRetain: 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 VPCattached: IGW is attached and ready for usedetaching: IGW is being detacheddetached: 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:
- VPC does not exist or is not ready
- Another IGW is already attached to the VPC
- 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:
- Use the existing IGW
- 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:
- Check if the route table has a route to 0.0.0.0/0 pointing to the IGW
- Check if the subnet is associated with the correct route table
- Check security groups and NACLs
Command:
# Check route tables
aws ec2 describe-route-tables \
--filters "Name=vpc-id,Values=vpc-xxx"
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