AWS VPC NAT Gateway Kurulumu ve Yapılandırması

Bir production ortamında private subnet’teki EC2 instance’larının internete çıkması gerektiğinde, ama dışarıdan erişilemez kalması gerektiğinde ne yaparsınız? İşte tam bu noktada NAT Gateway devreye giriyor. AWS VPC mimarisinin belki de en kritik bileşenlerinden biri olan NAT Gateway’i doğru kurmak, hem güvenlik hem de maliyet açısından son derece önemli. Bu yazıda NAT Gateway’i sıfırdan kuracağız, yaygın hataları ele alacağız ve gerçek dünya senaryolarıyla konuyu pekiştireceğiz.

NAT Gateway Nedir ve Neden Gerekli?

Klasik bir VPC mimarisinde iki tür subnet bulunur: public subnet ve private subnet. Public subnet’teki kaynaklar Internet Gateway üzerinden doğrudan internete çıkabilir. Ancak private subnet’teki EC2 instance’ları, RDS veritabanları veya uygulama sunucularınız internet erişimi olmadan çalışır. Bu aslında güvenlik açısından istediğiniz şeydir; dışarıdan kimse bu kaynaklara doğrudan erişemez.

Peki ya bu private instance’ların yazılım güncellemesi yapması, bir S3 bucket’ına erişmesi veya harici bir API’ye istek atması gerekirse? İşte NAT Gateway tam bu ihtiyacı karşılar. Network Address Translation prensibiyle çalışır: private subnet’ten gelen trafiği kendi IP adresiyle maskeleyerek internete iletir, dönen yanıtları da ilgili instance’a geri gönderir. Dışarıdan hiç kimse private instance’ın gerçek IP adresini göremez.

NAT Gateway ile NAT Instance arasındaki farka da değinelim. NAT Instance, EC2 üzerinde çalışan eski yöntemdir ve yönetim yükü getirir. NAT Gateway ise AWS’nin yönettiği, otomatik ölçeklenen, yüksek erişilebilirlik sunan bir managed servistir. Production ortamları için NAT Gateway’i tercih etmek doğru karardır.

Ön Gereksinimler

Başlamadan önce aşağıdakilerin hazır olduğundan emin olun:

  • AWS CLI kurulu ve yapılandırılmış (credentials ayarlı)
  • En az bir VPC mevcut
  • Public subnet ve private subnet tanımlı
  • Internet Gateway VPC’ye attach edilmiş
  • Yeterli IAM izinleri (EC2, VPC tam yetki)

AWS CLI’yi yapılandırmak için:

aws configure
# AWS Access Key ID: [access-key-buraya]
# AWS Secret Access Key: [secret-key-buraya]
# Default region name: eu-west-1
# Default output format: json

Adım 1: VPC ve Subnet Yapısını Oluşturma

Sıfırdan başlayacağız. Önce VPC’yi oluşturalım:

# VPC oluştur
VPC_ID=$(aws ec2 create-vpc 
  --cidr-block 10.0.0.0/16 
  --tag-specifications 'ResourceType=vpc,Tags=[{Key=Name,Value=production-vpc}]' 
  --query 'Vpc.VpcId' 
  --output text)

echo "VPC ID: $VPC_ID"

# DNS hostname'leri etkinleştir
aws ec2 modify-vpc-attribute 
  --vpc-id $VPC_ID 
  --enable-dns-hostnames '{"Value": true}'

aws ec2 modify-vpc-attribute 
  --vpc-id $VPC_ID 
  --enable-dns-support '{"Value": true}'

Şimdi public ve private subnet’leri oluşturalım. Gerçek bir production ortamında her zaman birden fazla Availability Zone kullanmalısınız:

# Public subnet - AZ 1a
PUBLIC_SUBNET_1=$(aws ec2 create-subnet 
  --vpc-id $VPC_ID 
  --cidr-block 10.0.1.0/24 
  --availability-zone eu-west-1a 
  --tag-specifications 'ResourceType=subnet,Tags=[{Key=Name,Value=public-subnet-1a}]' 
  --query 'Subnet.SubnetId' 
  --output text)

# Public subnet - AZ 1b
PUBLIC_SUBNET_2=$(aws ec2 create-subnet 
  --vpc-id $VPC_ID 
  --cidr-block 10.0.2.0/24 
  --availability-zone eu-west-1b 
  --tag-specifications 'ResourceType=subnet,Tags=[{Key=Name,Value=public-subnet-1b}]' 
  --query 'Subnet.SubnetId' 
  --output text)

# Private subnet - AZ 1a
PRIVATE_SUBNET_1=$(aws ec2 create-subnet 
  --vpc-id $VPC_ID 
  --cidr-block 10.0.10.0/24 
  --availability-zone eu-west-1a 
  --tag-specifications 'ResourceType=subnet,Tags=[{Key=Name,Value=private-subnet-1a}]' 
  --query 'Subnet.SubnetId' 
  --output text)

# Private subnet - AZ 1b
PRIVATE_SUBNET_2=$(aws ec2 create-subnet 
  --vpc-id $VPC_ID 
  --cidr-block 10.0.11.0/24 
  --availability-zone eu-west-1b 
  --tag-specifications 'ResourceType=subnet,Tags=[{Key=Name,Value=private-subnet-1b}]' 
  --query 'Subnet.SubnetId' 
  --output text)

echo "Public Subnet 1: $PUBLIC_SUBNET_1"
echo "Public Subnet 2: $PUBLIC_SUBNET_2"
echo "Private Subnet 1: $PRIVATE_SUBNET_1"
echo "Private Subnet 2: $PRIVATE_SUBNET_2"

Adım 2: Internet Gateway Kurulumu

NAT Gateway’in çalışabilmesi için VPC’nin önce bir Internet Gateway’e ihtiyacı var:

# Internet Gateway oluştur
IGW_ID=$(aws ec2 create-internet-gateway 
  --tag-specifications 'ResourceType=internet-gateway,Tags=[{Key=Name,Value=production-igw}]' 
  --query 'InternetGateway.InternetGatewayId' 
  --output text)

# VPC'ye attach et
aws ec2 attach-internet-gateway 
  --internet-gateway-id $IGW_ID 
  --vpc-id $VPC_ID

echo "Internet Gateway ID: $IGW_ID"

Public subnet’ler için route table oluşturalım ve Internet Gateway’e yönlendirme ekleyelim:

# Public route table oluştur
PUBLIC_RT=$(aws ec2 create-route-table 
  --vpc-id $VPC_ID 
  --tag-specifications 'ResourceType=route-table,Tags=[{Key=Name,Value=public-rt}]' 
  --query 'RouteTable.RouteTableId' 
  --output text)

# Internet Gateway'e default route ekle
aws ec2 create-route 
  --route-table-id $PUBLIC_RT 
  --destination-cidr-block 0.0.0.0/0 
  --gateway-id $IGW_ID

# Public subnet'leri bu route table'a associate et
aws ec2 associate-route-table 
  --route-table-id $PUBLIC_RT 
  --subnet-id $PUBLIC_SUBNET_1

aws ec2 associate-route-table 
  --route-table-id $PUBLIC_RT 
  --subnet-id $PUBLIC_SUBNET_2

# Public subnet'lerde otomatik public IP atamasını etkinleştir
aws ec2 modify-subnet-attribute 
  --subnet-id $PUBLIC_SUBNET_1 
  --map-public-ip-on-launch

aws ec2 modify-subnet-attribute 
  --subnet-id $PUBLIC_SUBNET_2 
  --map-public-ip-on-launch

Adım 3: Elastic IP ve NAT Gateway Oluşturma

NAT Gateway’in static bir public IP’ye ihtiyacı vardır. Bunun için Elastic IP allocate etmemiz gerekiyor:

# Elastic IP allocate et - AZ 1a için
EIP_1=$(aws ec2 allocate-address 
  --domain vpc 
  --tag-specifications 'ResourceType=elastic-ip,Tags=[{Key=Name,Value=nat-eip-1a}]' 
  --query 'AllocationId' 
  --output text)

# Elastic IP allocate et - AZ 1b için
EIP_2=$(aws ec2 allocate-address 
  --domain vpc 
  --tag-specifications 'ResourceType=elastic-ip,Tags=[{Key=Name,Value=nat-eip-1b}]' 
  --query 'AllocationId' 
  --output text)

echo "EIP 1 (1a): $EIP_1"
echo "EIP 2 (1b): $EIP_2"

# NAT Gateway oluştur - AZ 1a (public subnet'te olmalı!)
NAT_GW_1=$(aws ec2 create-nat-gateway 
  --subnet-id $PUBLIC_SUBNET_1 
  --allocation-id $EIP_1 
  --tag-specifications 'ResourceType=natgateway,Tags=[{Key=Name,Value=nat-gw-1a}]' 
  --query 'NatGateway.NatGatewayId' 
  --output text)

# NAT Gateway oluştur - AZ 1b
NAT_GW_2=$(aws ec2 create-nat-gateway 
  --subnet-id $PUBLIC_SUBNET_2 
  --allocation-id $EIP_2 
  --tag-specifications 'ResourceType=natgateway,Tags=[{Key=Name,Value=nat-gw-1b}]' 
  --query 'NatGateway.NatGatewayId' 
  --output text)

echo "NAT Gateway 1 (1a): $NAT_GW_1"
echo "NAT Gateway 2 (1b): $NAT_GW_2"

Çok önemli bir nokta: NAT Gateway her zaman public subnet‘e kurulur, private subnet’e değil. Bu yanlış anlaşılan en yaygın konulardan biridir. NAT Gateway’i public subnet’e koyuyoruz çünkü internet çıkışı için Internet Gateway’e erişmesi gerekiyor.

NAT Gateway’in hazır hale gelmesi birkaç dakika sürer. Devam etmeden önce bekleyelim:

# NAT Gateway'lerin available durumuna gelmesini bekle
echo "NAT Gateway 1 hazır olana kadar bekleniyor..."
aws ec2 wait nat-gateway-available 
  --nat-gateway-ids $NAT_GW_1

echo "NAT Gateway 2 hazır olana kadar bekleniyor..."
aws ec2 wait nat-gateway-available 
  --nat-gateway-ids $NAT_GW_2

echo "Her iki NAT Gateway de hazır!"

Adım 4: Private Subnet Route Table Yapılandırması

Private subnet’lerin trafiği NAT Gateway üzerinden yönlendirmesi için route table’ları yapılandırmamız gerekiyor:

# Private route table - AZ 1a
PRIVATE_RT_1=$(aws ec2 create-route-table 
  --vpc-id $VPC_ID 
  --tag-specifications 'ResourceType=route-table,Tags=[{Key=Name,Value=private-rt-1a}]' 
  --query 'RouteTable.RouteTableId' 
  --output text)

# Private route table - AZ 1b
PRIVATE_RT_2=$(aws ec2 create-route-table 
  --vpc-id $VPC_ID 
  --tag-specifications 'ResourceType=route-table,Tags=[{Key=Name,Value=private-rt-1b}]' 
  --query 'RouteTable.RouteTableId' 
  --output text)

# 1a private subnet'i 1a NAT Gateway üzerinden çıkar
aws ec2 create-route 
  --route-table-id $PRIVATE_RT_1 
  --destination-cidr-block 0.0.0.0/0 
  --nat-gateway-id $NAT_GW_1

# 1b private subnet'i 1b NAT Gateway üzerinden çıkar
aws ec2 create-route 
  --route-table-id $PRIVATE_RT_2 
  --destination-cidr-block 0.0.0.0/0 
  --nat-gateway-id $NAT_GW_2

# Private subnet'leri route table'lara bağla
aws ec2 associate-route-table 
  --route-table-id $PRIVATE_RT_1 
  --subnet-id $PRIVATE_SUBNET_1

aws ec2 associate-route-table 
  --route-table-id $PRIVATE_RT_2 
  --subnet-id $PRIVATE_SUBNET_2

echo "Route table yapılandırması tamamlandı."

Her AZ’daki private subnet’in aynı AZ’daki NAT Gateway’i kullanması kritiktir. Bu yaklaşım hem latency’yi minimize eder hem de cross-AZ veri transfer maliyetlerini önler.

Adım 5: Kurulumu Doğrulama

Kurulumu test etmek için private subnet’e bir test EC2 instance’ı başlatalım ve bağlantıyı kontrol edelim:

# Önce bir security group oluştur
SG_ID=$(aws ec2 create-security-group 
  --group-name private-test-sg 
  --description "Private instance test SG" 
  --vpc-id $VPC_ID 
  --query 'GroupId' 
  --output text)

# Sadece VPC içinden SSH erişimine izin ver
aws ec2 authorize-security-group-ingress 
  --group-id $SG_ID 
  --protocol tcp 
  --port 22 
  --cidr 10.0.0.0/16

# Outbound tüm trafiğe izin ver (zaten default)
echo "Security Group ID: $SG_ID"

# Test instance başlat
INSTANCE_ID=$(aws ec2 run-instances 
  --image-id ami-0c55b159cbfafe1f0 
  --instance-type t3.micro 
  --subnet-id $PRIVATE_SUBNET_1 
  --security-group-ids $SG_ID 
  --tag-specifications 'ResourceType=instance,Tags=[{Key=Name,Value=nat-test-instance}]' 
  --query 'Instances[0].InstanceId' 
  --output text)

echo "Test Instance ID: $INSTANCE_ID"

Instance çalıştıktan sonra bir bastion host (ya da AWS SSM Session Manager) üzerinden bağlanıp internet erişimini test edebilirsiniz:

# SSM Session Manager ile bağlan (bastion gerekmez)
aws ssm start-session --target $INSTANCE_ID

# Instance içinde test et:
# curl -s https://checkip.amazonaws.com
# ping -c 4 8.8.8.8
# curl -s https://api.ipify.org

Dönen IP adresi NAT Gateway’in Elastic IP’si olmalıdır. Eğer öyleyse her şey doğru çalışıyor demektir.

Gerçek Dünya Senaryosu: Maliyet Optimizasyonu

NAT Gateway’in en büyük dezavantajı maliyetidir. Saatlik çalışma ücreti ve işlenen veri miktarı üzerinden ücretlendirilirsiniz. Orta büyüklükte bir sistemde aylık 50-200 dolar arasında NAT Gateway maliyeti görmek mümkündür.

Maliyeti düşürmek için uygulayabileceğiniz stratejiler:

  • VPC Endpoint kullanımı: S3, DynamoDB ve diğer AWS servisleri için VPC Endpoint kurarak bu trafiği NAT Gateway üzerinden geçirmekten kaçının. VPC Endpoint çok daha ucuzdur.
  • Dev/Test ortamlarında tek NAT Gateway: Production’da multi-AZ NAT Gateway zorunlu olsa da dev ortamında tek bir NAT Gateway yeterlidir.
  • Gereksiz veri transferini azaltmak: Private instance’lardan büyük dosya indirmeleri varsa bunları S3 üzerinden yönlendirmek daha ekonomiktir.
  • NAT Instance alternatifi: Çok düşük trafikli dev ortamları için t3.nano NAT Instance ayda birkaç dolara denk gelebilir.

S3 için VPC Gateway Endpoint kurulumu:

# S3 VPC Gateway Endpoint oluştur
aws ec2 create-vpc-endpoint 
  --vpc-id $VPC_ID 
  --service-name com.amazonaws.eu-west-1.s3 
  --route-table-ids $PRIVATE_RT_1 $PRIVATE_RT_2 
  --tag-specifications 'ResourceType=vpc-endpoint,Tags=[{Key=Name,Value=s3-endpoint}]'

# DynamoDB için de benzer şekilde:
aws ec2 create-vpc-endpoint 
  --vpc-id $VPC_ID 
  --service-name com.amazonaws.eu-west-1.dynamodb 
  --route-table-ids $PRIVATE_RT_1 $PRIVATE_RT_2 
  --tag-specifications 'ResourceType=vpc-endpoint,Tags=[{Key=Name,Value=dynamodb-endpoint}]'

Bu endpoint’leri ekledikten sonra private instance’larınızın S3 ve DynamoDB trafiği NAT Gateway’den geçmez, AWS’nin iç ağı üzerinden gider.

Monitoring ve CloudWatch Alarmları

NAT Gateway’i kurduktan sonra izlemeyi unutmayın. CloudWatch üzerinden NAT Gateway metriklerini takip edebilirsiniz:

# NAT Gateway için CloudWatch alarm oluştur - hata sayısı için
aws cloudwatch put-metric-alarm 
  --alarm-name "NAT-Gateway-Error-Count" 
  --alarm-description "NAT Gateway connection error count too high" 
  --metric-name ErrorPortAllocation 
  --namespace AWS/NATGateway 
  --statistic Sum 
  --period 300 
  --threshold 100 
  --comparison-operator GreaterThanThreshold 
  --dimensions Name=NatGatewayId,Value=$NAT_GW_1 
  --evaluation-periods 2 
  --alarm-actions arn:aws:sns:eu-west-1:123456789012:ops-alerts

# Paket drop alarmı
aws cloudwatch put-metric-alarm 
  --alarm-name "NAT-Gateway-Packet-Drop" 
  --alarm-description "NAT Gateway dropping packets" 
  --metric-name PacketsDropCount 
  --namespace AWS/NATGateway 
  --statistic Sum 
  --period 300 
  --threshold 1000 
  --comparison-operator GreaterThanThreshold 
  --dimensions Name=NatGatewayId,Value=$NAT_GW_1 
  --evaluation-periods 1 
  --alarm-actions arn:aws:sns:eu-west-1:123456789012:ops-alerts

Takip etmeniz gereken önemli NAT Gateway metrikleri:

  • BytesInFromDestination: İnternetten gelen veri miktarı
  • BytesOutToInternet: İnternete gönderilen veri miktarı
  • ConnectionAttemptCount: Bağlantı girişimleri
  • ConnectionEstablishedCount: Başarılı bağlantılar
  • ErrorPortAllocation: Port tahsis hataları (yoğun bağlantı durumunda artabilir)
  • PacketsDropCount: Düşürülen paketler
  • IdleTimeoutCount: Zaman aşımına uğrayan bağlantılar

Yaygın Hatalar ve Çözümleri

Problem 1: Private instance’dan internete çıkamıyor

Kontrol listesi:

  • NAT Gateway public subnet’te mi? Private subnet’te NAT Gateway çalışmaz.
  • Private subnet route table’ında 0.0.0.0/0 -> NAT Gateway kaydı var mı?
  • Internet Gateway VPC’ye attach edilmiş mi?
  • Public subnet route table’ında 0.0.0.0/0 -> Internet Gateway kaydı var mı?
  • Security Group outbound kuralları engelliyor mu?
  • NACL kuralları trafiği kesiyor mu?

Problem 2: NAT Gateway “failed” durumunda

NAT Gateway başarısız olabilir. Durumunu kontrol edin:

aws ec2 describe-nat-gateways 
  --nat-gateway-ids $NAT_GW_1 
  --query 'NatGateways[0].{State:State,FailureCode:FailureCode,FailureMessage:FailureMessage}'

Problem 3: Cross-AZ yönlendirme ve yüksek maliyet

AZ-1a’daki private instance’ların AZ-1b’deki NAT Gateway’i kullanması durumunda cross-AZ transfer ücreti ödüyorsunuzdur. Her AZ’ın kendi NAT Gateway’ini kullandığından emin olun.

Problem 4: Port tükenmesi

NAT Gateway instance başına maksimum 55.000 eşzamanlı bağlantıyı destekler. Yüksek bağlantı ihtiyacı olan uygulamalarda (örneğin binlerce aynı hedefe giden connection) sorun yaşanabilir. Çözüm olarak uygulamanızın connection pooling kullandığından emin olun.

Temizlik: Kaynakları Silme

Test ortamını temizlemek için kaynakları oluşturma sırasının tersinden silin:

# Instance'ı sonlandır
aws ec2 terminate-instances --instance-ids $INSTANCE_ID

# Route table association'ları sil ve route table'ları sil
aws ec2 delete-route-table --route-table-id $PRIVATE_RT_1
aws ec2 delete-route-table --route-table-id $PRIVATE_RT_2
aws ec2 delete-route-table --route-table-id $PUBLIC_RT

# NAT Gateway'leri sil (bu birkaç dakika sürer)
aws ec2 delete-nat-gateway --nat-gateway-id $NAT_GW_1
aws ec2 delete-nat-gateway --nat-gateway-id $NAT_GW_2

# NAT Gateway'lerin silinmesini bekle
aws ec2 wait nat-gateway-deleted --nat-gateway-ids $NAT_GW_1 $NAT_GW_2

# Elastic IP'leri serbest bırak
aws ec2 release-address --allocation-id $EIP_1
aws ec2 release-address --allocation-id $EIP_2

# Internet Gateway'i detach et ve sil
aws ec2 detach-internet-gateway 
  --internet-gateway-id $IGW_ID 
  --vpc-id $VPC_ID
aws ec2 delete-internet-gateway --internet-gateway-id $IGW_ID

# Subnet'leri sil
aws ec2 delete-subnet --subnet-id $PUBLIC_SUBNET_1
aws ec2 delete-subnet --subnet-id $PUBLIC_SUBNET_2
aws ec2 delete-subnet --subnet-id $PRIVATE_SUBNET_1
aws ec2 delete-subnet --subnet-id $PRIVATE_SUBNET_2

# VPC'yi sil
aws ec2 delete-vpc --vpc-id $VPC_ID

echo "Tüm kaynaklar temizlendi."

Dikkat: Elastic IP’leri release etmeyi unutmayın. Kullanılmayan Elastic IP’ler için de ücret ödersiniz.

Sonuç

NAT Gateway, AWS VPC mimarisinin temel taşlarından biridir ve doğru kurulumu production ortamlarında hem güvenliği hem de uygulama sağlığını doğrudan etkiler. Bu yazıda öğrendiklerimizi özetleyelim:

NAT Gateway her zaman public subnet’e kurulur ve private subnet’lerin internet çıkışını sağlar. Production ortamlarında her Availability Zone için ayrı NAT Gateway kullanmak hem yüksek erişilebilirlik hem de maliyet optimizasyonu açısından doğru yaklaşımdır. S3 ve DynamoDB gibi AWS servisleri için VPC Endpoint kullanmak NAT Gateway maliyetini önemli ölçüde düşürür. CloudWatch alarmları kurarak NAT Gateway sağlığını proaktif olarak izlemelisiniz. Temizlik yaparken kaynak silme sırasına dikkat edin; yoksa dependency hataları alırsınız.

NAT Gateway’in Terraform veya AWS CloudFormation ile Infrastructure as Code olarak yönetilmesi büyük ortamlarda çok daha sürdürülebilir bir yaklaşım sunar. Manuel CLI adımları öğrenmek için harika, ama production’da mutlaka IaC kullanın. Bir sonraki yazıda bu kurulumun tamamını Terraform ile nasıl yapılandıracağımıza bakacağız.

Bir yanıt yazın

E-posta adresiniz yayınlanmayacak. Gerekli alanlar * ile işaretlenmişlerdir