Bulut Ortamında Ağ Güvenliği: VPC, Güvenlik Grupları ve NACL ile Trafiği Kontrol Altına Alma

Bulut ortamına geçiş yapan çoğu ekibin ilk ciddi sorunuyla karşılaştığı yer ağ güvenliğidir. “On-premise’de firewall vardı, zaten güvendik” mantığıyla buluta taşınan altyapılar, yanlış yapılandırılmış güvenlik grupları ve açık kalmış portlar yüzünden ciddi güvenlik açıklarına maruz kalıyor. Bu yazıda AWS üzerinden VPC, Security Group ve NACL kavramlarını hem teorik hem de pratik senaryolarla ele alacağız. Amacım sizi dokümantasyona gönderip “şunu oku” demek değil, gerçekten çalışan bir ağ güvenliği mimarisi kurmanıza yardımcı olmak.

VPC Nedir ve Neden Bu Kadar Önemli

Virtual Private Cloud (VPC), AWS altyapısında sizin için ayrılmış izole bir ağ segmentidir. Veri merkezinizdeki fiziksel ağın bulut karşılığı olarak düşünebilirsiniz. Ama dikkat edin, bu sadece bir isim benzerliği değil; VPC içinde subnet’ler tanımlıyorsunuz, routing table’lar oluşturuyorsunuz, internet gateway veya NAT gateway ile dış dünyayla bağlantı kuruyorsunuz.

Bir VPC oluştururken ilk yapmanız gereken şey CIDR bloğunu doğru belirlemek. Çünkü sonradan değiştirmek çok acı verir. Yaygın bir hata, herkesin /16 alıp durması ve sonra subnet planlamasını hiç düşünmemesi. Şöyle bir senaryo düşünelim: Üretim, test ve geliştirme ortamlarınız aynı VPC içinde farklı subnet’lerde mi çalışacak, yoksa her ortam kendi VPC’sinde mi izole olacak? Bu kararı baştan vermek, ilerideki güvenlik ve maliyet sorunlarını büyük ölçüde azaltır.

# AWS CLI ile temel VPC oluşturma
aws ec2 create-vpc 
  --cidr-block 10.0.0.0/16 
  --tag-specifications 'ResourceType=vpc,Tags=[{Key=Name,Value=production-vpc},{Key=Environment,Value=prod}]'

VPC içinde subnet tasarımı yapılırken public ve private subnet ayrımına dikkat etmek gerekiyor. Public subnet’te internet gateway üzerinden dış dünyaya doğrudan erişim sağlanırken, private subnet’te bu erişim NAT gateway üzerinden gerçekleşiyor. Kritik veritabanlarınızı, uygulama sunucularınızı asla public subnet’e koymayın. Bunu bir kez daha söyleyeyim: Asla koymayın.

# Public subnet oluşturma
aws ec2 create-subnet 
  --vpc-id vpc-0abc12345 
  --cidr-block 10.0.1.0/24 
  --availability-zone us-east-1a 
  --tag-specifications 'ResourceType=subnet,Tags=[{Key=Name,Value=public-subnet-1a}]'

# Private subnet oluşturma
aws ec2 create-subnet 
  --vpc-id vpc-0abc12345 
  --cidr-block 10.0.10.0/24 
  --availability-zone us-east-1a 
  --tag-specifications 'ResourceType=subnet,Tags=[{Key=Name,Value=private-subnet-1a}]'

Güvenlik Grupları: Stateful Güvenlik Katmanı

Güvenlik grupları (Security Groups), EC2 instance’larınıza veya diğer AWS kaynaklarına bağlanan stateful güvenlik duvarlarıdır. Stateful olması şu anlama geliyor: Bir bağlantıya izin verdikten sonra, o bağlantıya ait dönüş trafiğini ayrıca tanımlamanıza gerek yok. Sistem bunu otomatik olarak yönetiyor.

Güvenlik gruplarında bazı temel kurallar vardır:

  • Varsayılan olarak tüm inbound trafik reddedilir, siz açıkça izin vermediğiniz sürece hiçbir şey içeri giremez
  • Varsayılan olarak tüm outbound trafik izinlidir, bunu çoğu kişi değiştirmez ama değiştirmek gerekebilir
  • Birden fazla güvenlik grubunu aynı kaynağa atayabilirsiniz
  • Güvenlik grubu kuralları sadece “izin ver” mantığıyla çalışır, “reddet” kuralı yazamazsınız

Şimdi gerçek dünya senaryosuna geçelim. Diyelim ki bir web uygulaması çalıştırıyorsunuz. Önünde bir load balancer var, arkasında uygulama sunucuları, en geride de bir RDS veritabanı. Bu katmanlı mimaride güvenlik gruplarını nasıl yapılandırmalısınız?

# Load Balancer için güvenlik grubu
aws ec2 create-security-group 
  --group-name alb-sg 
  --description "Application Load Balancer Security Group" 
  --vpc-id vpc-0abc12345

# ALB'ye sadece 80 ve 443 portlarından trafik izni
aws ec2 authorize-security-group-ingress 
  --group-id sg-alb123 
  --protocol tcp 
  --port 80 
  --cidr 0.0.0.0/0

aws ec2 authorize-security-group-ingress 
  --group-id sg-alb123 
  --protocol tcp 
  --port 443 
  --cidr 0.0.0.0/0
# Uygulama sunucuları için güvenlik grubu
# Sadece ALB'den gelen trafik kabul edilecek
aws ec2 create-security-group 
  --group-name app-server-sg 
  --description "Application Server Security Group" 
  --vpc-id vpc-0abc12345

# ALB güvenlik grubundan uygulama portuna izin
aws ec2 authorize-security-group-ingress 
  --group-id sg-app123 
  --protocol tcp 
  --port 8080 
  --source-group sg-alb123

Burada önemli bir detaya dikkat edin: CIDR bloğu yerine başka bir güvenlik grubunu kaynak olarak belirtebiliyorsunuz. Bu sayede IP adresi takip etmek yerine “ALB güvenlik grubundaki her şeyden gelen trafiğe izin ver” diyebiliyorsunuz. Bu yaklaşım hem daha güvenli hem de yönetimi çok daha kolay.

# RDS veritabanı için güvenlik grubu
# Sadece uygulama sunucularından 5432 portuna izin
aws ec2 create-security-group 
  --group-name rds-sg 
  --description "RDS PostgreSQL Security Group" 
  --vpc-id vpc-0abc12345

aws ec2 authorize-security-group-ingress 
  --group-id sg-rds123 
  --protocol tcp 
  --port 5432 
  --source-group sg-app123

Bu yapıyla artık veritabanınıza sadece uygulama sunucuları erişebiliyor. İnternetten, başka bir sunucudan, hatta VPC içindeki başka bir kaynaktan bile doğrudan bağlantı kurulamıyor. Bu en az ayrıcalık prensibinin güvenlik grupları düzeyindeki uygulamasıdır.

Outbound Kuralları ve Güvenliği

Çoğu ekip outbound kurallarını “hepsine izin ver” şeklinde bırakır. Ama saldırganların sisteminize girmeyi başardığı senaryolarda, dışarıya veri sızdırmak veya C2 sunucularıyla iletişim kurmak için bu açık outbound kapıyı kullanırlar. Kritik sistemlerde outbound trafiği de kısıtlamak gerekiyor.

# Mevcut outbound kuralını kaldır
aws ec2 revoke-security-group-egress 
  --group-id sg-rds123 
  --protocol -1 
  --port -1 
  --cidr 0.0.0.0/0

# Sadece belirli portlara outbound izni ver
# Veritabanının sadece uygulama sunucularına cevap vermesine izin ver
aws ec2 authorize-security-group-egress 
  --group-id sg-rds123 
  --protocol tcp 
  --port 5432 
  --source-group sg-app123

NACL: Network Access Control List ile Subnet Düzeyinde Kontrol

NACL’lar güvenlik gruplarından temel olarak şu noktada ayrılır: Stateless çalışırlar. Yani bir pakete izin verdikten sonra, dönüş paketini de ayrıca tanımlamanız gerekir. Bu ekstra iş yükü getirse de NACL’ların sunduğu avantajlar vardır. Özellikle belirli IP adreslerini veya IP bloklarını subnet düzeyinde engellemek istediğinizde NACL çok daha etkili çalışır.

NACL kurallarında önemli bir detay var: Kural numarası sıralaması. Kurallar numaralandırılır ve düşükten yükseğe doğru değerlendirilir. İlk eşleşen kuralda işlem durur. Bu yüzden genel “tümüne izin ver” kuralını yüksek bir numaraya, özel engelleme kurallarını ise düşük numaralara yazmanız gerekiyor.

NACL kuralları şu bileşenlerden oluşur:

  • Kural numarası: 1-32766 arası, işleme önceliğini belirler
  • Protokol: TCP, UDP, ICMP veya tümü
  • Port aralığı: Tek port veya aralık
  • Kaynak/Hedef CIDR: Hangi IP bloğuna uygulanacağı
  • İzin/Engelle: Allow veya Deny
# Belirli bir IP bloğunu NACL ile engelleme
# Önce NACL oluşturalım
aws ec2 create-network-acl 
  --vpc-id vpc-0abc12345 
  --tag-specifications 'ResourceType=network-acl,Tags=[{Key=Name,Value=production-nacl}]'

# Kötü niyetli IP bloğunu engelle (kural 100)
aws ec2 create-network-acl-entry 
  --network-acl-id acl-123abc 
  --rule-number 100 
  --protocol -1 
  --rule-action deny 
  --ingress 
  --cidr-block 192.168.100.0/24

# HTTP trafiğine izin ver (kural 200)
aws ec2 create-network-acl-entry 
  --network-acl-id acl-123abc 
  --rule-number 200 
  --protocol tcp 
  --rule-action allow 
  --ingress 
  --port-range From=80,To=80 
  --cidr-block 0.0.0.0/0

# HTTPS trafiğine izin ver (kural 210)
aws ec2 create-network-acl-entry 
  --network-acl-id acl-123abc 
  --rule-number 210 
  --protocol tcp 
  --rule-action allow 
  --ingress 
  --port-range From=443,To=443 
  --cidr-block 0.0.0.0/0

Ephemeral portları unutmayın. Stateless yapıda NACL kullanırken TCP bağlantılarının dönüş trafiği için ephemeral port aralığını (1024-65535) outbound kurallarda açmanız gerekiyor. Bunu atlayan sysadminlerin “neden bağlantı çalışmıyor” diye saatlerce hata ayıkladığına defalarca şahit oldum.

# Outbound ephemeral port izni - dönüş trafiği için zorunlu
aws ec2 create-network-acl-entry 
  --network-acl-id acl-123abc 
  --rule-number 900 
  --protocol tcp 
  --rule-action allow 
  --egress 
  --port-range From=1024,To=65535 
  --cidr-block 0.0.0.0/0

NACL vs Güvenlik Grupları: Hangisini Ne Zaman Kullanmalısınız

İkisi birbirini tamamlayan araçlardır, biri diğerinin alternatifi değildir. Şöyle düşünebilirsiniz:

  • Güvenlik grupları instance düzeyinde, NACL subnet düzeyinde çalışır
  • Güvenlik grupları sadece “izin ver” kuralı yazmanıza izin verirken, NACL hem “izin ver” hem “engelle” destekler
  • Belirli bir IP’yi hızlıca engellemek istiyorsanız NACL daha pratik; çünkü tek noktadan tüm subnet’i korursunuz
  • Uygulama katmanlarına özel erişim kontrolü için güvenlik grupları çok daha esnek

Pratikte her ikisini de birlikte kullanmak en sağlıklı yaklaşımdır. NACL’ı kaba filtre olarak kullanın: bilinen kötü IP bloklarını engelleyin, yalnızca ihtiyacınız olan protokollere izin verin. Güvenlik gruplarını ise ince ayar katmanı olarak kullanın: hangi kaynaktan hangi porta erişim olacağını detaylı tanımlayın.

Gerçek Dünya Senaryosu: Bastion Host ile Güvenli Erişim

Production sunucularınıza SSH ile nasıl bağlanıyorsunuz? “VPN açıyorum, direkt bağlanıyorum” cevabını çok sık duyuyorum. Ama birçok ekipte VPN konfigürasyonu da o kadar iyi değil. Daha sağlam bir yaklaşım bastion host (jump server) kullanmak.

Bastion host, public subnet’e yerleştirilen ve sadece SSH için kullanılan küçük bir EC2 instance’ıdır. Private subnet’teki sunuculara bu bastion üzerinden atlama yapılır. Bu şekilde private sunucularınızın SSH portu internete açık olmak zorunda kalmaz.

# Bastion host güvenlik grubu
# Sadece şirket IP'sinden SSH erişimi
aws ec2 create-security-group 
  --group-name bastion-sg 
  --description "Bastion Host Security Group" 
  --vpc-id vpc-0abc12345

aws ec2 authorize-security-group-ingress 
  --group-id sg-bastion123 
  --protocol tcp 
  --port 22 
  --cidr 203.0.113.0/24  # Şirketinizin statik IP bloğu

# Private sunucuların SSH grubunu güncelle
# Sadece bastion'dan SSH erişimine izin ver
aws ec2 authorize-security-group-ingress 
  --group-id sg-app123 
  --protocol tcp 
  --port 22 
  --source-group sg-bastion123

Bastion’a bağlandıktan sonra private sunuculara atlama yapmak için SSH ProxyJump kullanabilirsiniz:

# ~/.ssh/config dosyasına ekleyin
# Host bastion
#   HostName 203.0.113.50
#   User ec2-user
#   IdentityFile ~/.ssh/prod-key.pem

# SSH ProxyJump ile private sunucuya bağlanma
ssh -J ec2-user@bastion-ip [email protected]

# Ya da config dosyasıyla
ssh -J bastion [email protected]

Bu yapıda private sunucuların internet erişimi olmadığı için güncelleme ve paket indirme işlemleri için NAT Gateway gerekiyor. NAT Gateway maliyeti göz ardı etmeyin; özellikle büyük veri transferleri yapıyorsanız aylık fatura sürpriz yapabilir.

VPC Flow Logs ile Trafik İzleme

Güvenlik gruplarınızı ve NACL’larınızı yapılandırdınız, ama bunların doğru çalışıp çalışmadığını nasıl anlayacaksınız? VPC Flow Logs burada devreye giriyor. VPC Flow Logs, VPC’nizden geçen tüm ağ trafiğini kaydeden bir özelliktir. Bu logları CloudWatch Logs veya S3’e yazabilirsiniz.

# VPC Flow Logs'u CloudWatch'a yönlendirme
aws ec2 create-flow-logs 
  --resource-type VPC 
  --resource-ids vpc-0abc12345 
  --traffic-type ALL 
  --log-destination-type cloud-watch-logs 
  --log-group-name /aws/vpc/flowlogs 
  --deliver-logs-permission-arn arn:aws:iam::123456789:role/FlowLogsRole

Flow log formatında şu bilgiler yer alır:

  • srcaddr: Kaynak IP adresi
  • dstaddr: Hedef IP adresi
  • srcport: Kaynak port
  • dstport: Hedef port
  • protocol: Protokol numarası
  • packets: Paket sayısı
  • bytes: Transfer edilen byte miktarı
  • action: ACCEPT veya REJECT

Özellikle REJECT kayıtlarına dikkat edin. Sürekli REJECT olan bağlantılar ya bir saldırı girişimini ya da yanlış yapılandırılmış bir kuralı işaret ediyor olabilir. CloudWatch Logs Insights ile bu logları sorgulamak oldukça pratik:

# CloudWatch Logs Insights ile reddedilen trafiği sorgulama
# Bu sorguyu AWS Console üzerinden Logs Insights'ta çalıştırabilirsiniz
fields @timestamp, srcaddr, dstaddr, dstport, action
| filter action = "REJECT"
| stats count(*) as requestCount by srcaddr, dstport
| sort requestCount desc
| limit 20

Güvenlik Gruplarını Terraform ile Yönetmek

Elle AWS CLI komutları yazmak başlangıç için iyi, ama production ortamında güvenlik gruplarını kod olarak yönetmek (Infrastructure as Code) çok daha sağlıklı. Terraform kullanarak güvenlik grubu konfigürasyonlarını versiyon kontrolüne alabilir, değişiklikleri gözden geçirebilir ve tekrar üretilebilir bir altyapı kurabilirsiniz.

# security_groups.tf
resource "aws_security_group" "app_server" {
  name        = "app-server-sg"
  description = "Application Server Security Group"
  vpc_id      = aws_vpc.main.id

  ingress {
    from_port       = 8080
    to_port         = 8080
    protocol        = "tcp"
    security_groups = [aws_security_group.alb.id]
    description     = "Allow traffic from ALB only"
  }

  ingress {
    from_port       = 22
    to_port         = 22
    protocol        = "tcp"
    security_groups = [aws_security_group.bastion.id]
    description     = "Allow SSH from bastion host"
  }

  egress {
    from_port       = 5432
    to_port         = 5432
    protocol        = "tcp"
    security_groups = [aws_security_group.rds.id]
    description     = "Allow PostgreSQL to RDS"
  }

  tags = {
    Name        = "app-server-sg"
    Environment = "production"
    ManagedBy   = "terraform"
  }
}

Bu yaklaşımla güvenlik grubu değişiklikleri git diff ile incelenebilir hale geliyor ve yanlış bir değişikliği geri almak dakikalar içinde mümkün oluyor. Güvenlik açısından bu çok kritik; “kim bu kuralı ekledi, ne zaman ekledi” sorularına kolayca cevap bulabiliyorsunuz.

Sık Yapılan Hatalar ve Nasıl Önlenir

Yıllar içinde en çok karşılaştığım güvenlik grubu hatalarını özetleyeyim:

  • 0.0.0.0/0 üzerinden SSH açmak: Bastion host veya VPN olmadan SSH portunu internete açmak ciddi bir risktir. Bot’lar sürekli bu portu tarıyor ve brute force deniyor.
  • Güvenlik gruplarını çok geniş tanımlamak: Bir güvenlik grubunu 20 farklı uygulama için kullanmak, bir değişikliğin beklenmedik sonuçlar doğurmasına yol açar.
  • Kullanılmayan güvenlik gruplarını temizlememek: Zamanla onlarca kullanılmayan güvenlik grubu birikir. Bunları periyodik olarak temizleyin.
  • NACL kurallarında ephemeral portları unutmak: Yukarıda bahsettim ama tekrar vurgulayayım; stateless yapıda dönüş trafiği için ephemeral portları açmayı unutmayın.
  • Güvenlik grubunu kaynak olarak kullanmak yerine CIDR yazmak: IP adresleri değişebilir; mümkün olduğunda güvenlik grubu referansı kullanın.

Sonuç

Bulut ortamında ağ güvenliği, bir kez yapıp bırakılan bir iş değil. Altyapınız büyüdükçe, yeni servisler eklendikçe güvenlik kurallarını güncel tutmak gerekiyor. VPC tasarımını doğru yapmak, güvenlik gruplarını en az ayrıcalık prensibiyle yapılandırmak ve NACL’ları subnet düzeyinde ek bir katman olarak kullanmak; bu üçlü doğru uygulandığında ciddi bir güvenlik seviyesi sağlıyor.

Önerilen pratik adımlar şöyle özetlenebilir: Önce VPC tasarımınızı belirleyin ve public/private subnet ayrımını netleştirin. Ardından her uygulama katmanı için ayrı güvenlik grupları oluşturun ve aralarındaki ilişkileri güvenlik grubu referanslarıyla tanımlayın. NACL’ları bilinen kötü kaynaklara karşı ek bir engelleme katmanı olarak kullanın. VPC Flow Logs’u açın ve düzenli olarak inceleyin. Son olarak tüm bu konfigürasyonları Terraform gibi bir araçla kod olarak yönetin.

Güvenlik her zaman sürtünme yaratır; ama bu sürtünmeyi minimize edecek iş akışları kurarsanız, hem güvenli hem de yönetilebilir bir bulut altyapısı oluşturmuş olursunuz. Sormak istedikleriniz olursa yorumlarda buluşuruz.

Bir yanıt yazın

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