AWS IAM’de En Az Yetki Prensibi Nasıl Uygulanır?
AWS’de yanlış yapılandırılmış bir IAM politikası, birkaç dakika içinde tüm altyapınızı tehlikeye atabilir. Geçen yıl bir müşterinin ortamında tam olarak bunu yaşadık: Bir developer, test amaçlı oluşturduğu servise AdministratorAccess politikası atamıştı. O servis ele geçirilince saldırgan tüm S3 bucket’larını sildi, EC2 instance’larını kapattı ve yeni IAM kullanıcıları oluşturdu. Hasarı onarmak üç gün sürdü. Bu yazıda, En Az Yetki Prensibi (Principle of Least Privilege) uygulamasını AWS IAM üzerinde nasıl hayata geçireceğinizi, gerçek dünya senaryolarıyla anlatacağım.
En Az Yetki Prensibi Nedir ve Neden Önemlidir
En az yetki prensibi basitçe şu demektir: Her kullanıcı, servis veya sistem, görevini yerine getirmek için gereken minimum yetkiye sahip olmalıdır. Ne fazla, ne eksik. AWS ortamında bu prensip, IAM politikaları aracılığıyla uygulanır.
Peki neden bu kadar kritik?
- Blast radius küçülür: Bir hesap veya servis ele geçirildiğinde, saldırganın yapabileceği hasar sınırlı kalır
- İç tehditler azalır: Yanlışlıkla veya kasıtlı yapılan hasarın önüne geçilir
- Compliance kolaylaşır: SOC 2, PCI DSS, ISO 27001 gibi sertifikalar için temel gereksinimdir
- Audit trail temizlenir: Geniş yetkili hesaplar, anomali tespitini zorlaştırır
AWS’nin kendi güvenlik raporlarına göre, güvenlik olaylarının büyük çoğunluğu aşırı geniş IAM yetkilerinden kaynaklanmaktadır. * (wildcard) action ve resource kombinasyonu, güvenlik ekiplerinin kabusudur.
IAM Temellerini Anlamak
Uygulamaya geçmeden önce IAM’ın yapı taşlarını netleştirelim.
Policy Tipleri
- Identity-based policies: Kullanıcı, grup veya role’e atanan politikalar
- Resource-based policies: S3 bucket, SQS queue gibi kaynaklara doğrudan atanan politikalar
- Permission boundaries: Bir identity’nin alabileceği maksimum yetki sınırı
- Service Control Policies (SCP): AWS Organizations seviyesinde tüm hesaplara uygulanan kısıtlamalar
- Session policies: AssumeRole sırasında geçici olarak daraltılan yetkiler
Policy Değerlendirme Mantığı
AWS, bir isteği değerlendirirken şu sırayı izler: Önce explicit deny var mı diye bakar, varsa reddeder. Explicit deny yoksa, explicit allow var mı diye bakar. İkisi de yoksa, implicit deny ile reddeder. Bu sırayı anlamak, politika yazarken yapacağınız hataları minimize eder.
Adım Adım Uygulama: Gerçek Dünya Senaryoları
Senaryo 1: EC2 Instance’ın S3’e Erişimi
Diyelim ki bir EC2 instance’ınız var ve bu instance, sadece belirli bir S3 bucket’tan dosya okuyup yazması gerekiyor. Klasik yanlış yapılan şey şudur:
# YANLIS: Bu policy EC2'ye tüm S3 yetkisi verir
aws iam attach-role-policy
--role-name MyEC2Role
--policy-arn arn:aws:iam::aws:policy/AmazonS3FullAccess
Bunun yerine, sadece ihtiyaç duyulan bucket ve işlemler için özel bir policy oluşturalım:
# Önce policy dosyasını oluştur
cat > ec2-s3-limited-policy.json << 'EOF'
{
"Version": "2012-10-17",
"Statement": [
{
"Sid": "AllowSpecificBucketReadWrite",
"Effect": "Allow",
"Action": [
"s3:GetObject",
"s3:PutObject",
"s3:DeleteObject",
"s3:GetObjectVersion"
],
"Resource": "arn:aws:s3:::my-app-bucket-prod/*"
},
{
"Sid": "AllowBucketListing",
"Effect": "Allow",
"Action": [
"s3:ListBucket",
"s3:GetBucketLocation"
],
"Resource": "arn:aws:s3:::my-app-bucket-prod"
}
]
}
EOF
# Policy'yi oluştur
aws iam create-policy
--policy-name EC2AppS3LimitedAccess
--policy-document file://ec2-s3-limited-policy.json
--description "EC2 app instance için sadece my-app-bucket-prod erişimi"
# Policy'yi role'e ekle
aws iam attach-role-policy
--role-name MyEC2Role
--policy-arn arn:aws:iam::123456789012:policy/EC2AppS3LimitedAccess
Bu yaklaşımla EC2 instance’ınız sadece my-app-bucket-prod bucket’ına erişebilir. Diğer tüm bucket’lar, delete işlemi dahil, tamamen kapalıdır.
Senaryo 2: Lambda Fonksiyonu için Minimal Yetki
Lambda’lar genellikle en çok abuse edilen servislerden biridir. Çünkü geliştiriciler “şimdilik” diyerek geniş yetkiler atar ve bu “şimdilik” kalıcı olur.
Bir Lambda fonksiyonunun yapması gereken işler şunlar olsun: DynamoDB’den okuma, CloudWatch’a log yazma ve belirli bir SQS queue’dan mesaj alma.
cat > lambda-minimal-policy.json << 'EOF'
{
"Version": "2012-10-17",
"Statement": [
{
"Sid": "DynamoDBReadOnly",
"Effect": "Allow",
"Action": [
"dynamodb:GetItem",
"dynamodb:Query",
"dynamodb:Scan",
"dynamodb:BatchGetItem"
],
"Resource": [
"arn:aws:dynamodb:eu-west-1:123456789012:table/UserTable",
"arn:aws:dynamodb:eu-west-1:123456789012:table/UserTable/index/*"
]
},
{
"Sid": "SQSConsumeMessages",
"Effect": "Allow",
"Action": [
"sqs:ReceiveMessage",
"sqs:DeleteMessage",
"sqs:GetQueueAttributes"
],
"Resource": "arn:aws:sqs:eu-west-1:123456789012:OrderProcessingQueue"
},
{
"Sid": "CloudWatchLogs",
"Effect": "Allow",
"Action": [
"logs:CreateLogGroup",
"logs:CreateLogStream",
"logs:PutLogEvents"
],
"Resource": "arn:aws:logs:eu-west-1:123456789012:log-group:/aws/lambda/OrderProcessor:*"
}
]
}
EOF
aws iam create-policy
--policy-name LambdaOrderProcessorPolicy
--policy-document file://lambda-minimal-policy.json
Dikkat edin, DynamoDB için sadece read action’lar verildi. SQS için sadece consume işlemleri. CloudWatch Logs için de sadece ilgili log group’a yazma hakkı verildi.
Senaryo 3: Developer Ekibi için Permission Boundary
Büyük organizasyonlarda geliştiricilerin kendi IAM role’lerini oluşturmasına izin vermek gerekebilir, ancak bu durum kontrol dışına çıkabilir. Permission Boundary tam burada devreye girer.
cat > developer-permission-boundary.json << 'EOF'
{
"Version": "2012-10-17",
"Statement": [
{
"Sid": "AllowedServices",
"Effect": "Allow",
"Action": [
"s3:*",
"lambda:*",
"dynamodb:*",
"sqs:*",
"sns:*",
"logs:*",
"cloudwatch:*",
"ec2:Describe*",
"iam:Get*",
"iam:List*"
],
"Resource": "*"
},
{
"Sid": "DenyPrivilegedIAMActions",
"Effect": "Deny",
"Action": [
"iam:CreateUser",
"iam:DeleteUser",
"iam:AttachUserPolicy",
"iam:CreateAccessKey",
"iam:UpdateAccountPasswordPolicy",
"organizations:*",
"account:*"
],
"Resource": "*"
},
{
"Sid": "DenyProductionEnvironment",
"Effect": "Deny",
"Action": "*",
"Resource": "*",
"Condition": {
"StringEquals": {
"aws:ResourceTag/Environment": "production"
}
}
}
]
}
EOF
# Permission boundary policy oluştur
aws iam create-policy
--policy-name DeveloperPermissionBoundary
--policy-document file://developer-permission-boundary.json
# Yeni bir developer role oluştururken boundary'yi uygula
aws iam create-role
--role-name DeveloperRole
--assume-role-policy-document file://trust-policy.json
--permissions-boundary arn:aws:iam::123456789012:policy/DeveloperPermissionBoundary
Bu yaklaşımla developer’lar production tag’i taşıyan kaynaklara hiçbir şekilde erişemez ve kritik IAM aksiyonları gerçekleştiremez.
Senaryo 4: Mevcut Yetkileri Analiz Etmek
En az yetki prensibini uygulamanın ilk adımı, şu an ne durumda olduğunuzu anlamaktır. AWS IAM Access Analyzer ve aws iam generate-service-last-accessed-details komutu bu konuda çok değerlidir.
# Bir role'ün son kullandığı servisleri listele
ROLE_ARN="arn:aws:iam::123456789012:role/MyEC2Role"
# Job başlat
JOB_ID=$(aws iam generate-service-last-accessed-details
--arn $ROLE_ARN
--query 'JobId'
--output text)
echo "Job ID: $JOB_ID"
# Birkaç saniye bekle
sleep 5
# Sonuçları çek ve hiç kullanılmamış servisleri filtrele
aws iam get-service-last-accessed-details
--job-id $JOB_ID
--query 'ServicesLastAccessed[?LastAuthenticated==`null`].{Service:ServiceName,Prefix:ServiceNamespace}'
--output table
Bu çıktı size şunu söyler: Bu role’e atanmış politikalar hangi servislere erişim veriyor, ama bu servisler hiç kullanılmamış. Kullanılmayan tüm servis yetkilerini kaldırabilirsiniz.
Senaryo 5: Condition Keys ile Granüler Kontrol
IAM politikalarının gerçek gücü, Condition bloklarında yatmaktadır. Sadece “ne yapabilir” değil, “ne zaman, nereden, nasıl yapabilir” sorularını da cevaplayabilirsiniz.
cat > conditional-access-policy.json << 'EOF'
{
"Version": "2012-10-17",
"Statement": [
{
"Sid": "S3AccessOnlyFromOfficeIP",
"Effect": "Allow",
"Action": [
"s3:GetObject",
"s3:ListBucket"
],
"Resource": [
"arn:aws:s3:::sensitive-data-bucket",
"arn:aws:s3:::sensitive-data-bucket/*"
],
"Condition": {
"IpAddress": {
"aws:SourceIp": [
"203.0.113.0/24",
"198.51.100.0/24"
]
}
}
},
{
"Sid": "RequireMFAForDeleteOperations",
"Effect": "Deny",
"Action": [
"s3:DeleteObject",
"s3:DeleteBucket",
"dynamodb:DeleteTable",
"ec2:TerminateInstances"
],
"Resource": "*",
"Condition": {
"BoolIfExists": {
"aws:MultiFactorAuthPresent": "false"
}
}
},
{
"Sid": "EnforceEncryptionOnS3Put",
"Effect": "Deny",
"Action": "s3:PutObject",
"Resource": "arn:aws:s3:::sensitive-data-bucket/*",
"Condition": {
"StringNotEquals": {
"s3:x-amz-server-side-encryption": "aws:kms"
}
}
}
]
}
EOF
Bu policy üç şey yapıyor:
- S3AccessOnlyFromOfficeIP: Bucket erişimini sadece belirli IP aralıklarından sağlar
- RequireMFAForDeleteOperations: Silme işlemleri için MFA zorunlu kılar
- EnforceEncryptionOnS3Put: KMS şifreleme olmadan dosya yüklemeyi engeller
Senaryo 6: AWS Organizations ile SCP Uygulama
Çok hesaplı (multi-account) bir AWS yapınız varsa, Service Control Policies ile tüm organizasyona uygulanan güvenlik politikaları yazabilirsiniz. Bu, bireysel hesap yöneticilerinin bile aşamayacağı sınırlar oluşturur.
cat > organization-scp-security.json << 'EOF'
{
"Version": "2012-10-17",
"Statement": [
{
"Sid": "DenyRootAccountUsage",
"Effect": "Deny",
"Action": "*",
"Resource": "*",
"Condition": {
"StringLike": {
"aws:PrincipalArn": "arn:aws:iam::*:root"
}
}
},
{
"Sid": "DenyRegionsOutsideEU",
"Effect": "Deny",
"NotAction": [
"iam:*",
"organizations:*",
"route53:*",
"budgets:*",
"waf:*",
"cloudfront:*",
"sts:*",
"support:*",
"trustedadvisor:*"
],
"Resource": "*",
"Condition": {
"StringNotLike": {
"aws:RequestedRegion": [
"eu-west-1",
"eu-central-1",
"eu-west-3"
]
}
}
},
{
"Sid": "RequireIMDSv2",
"Effect": "Deny",
"Action": "ec2:RunInstances",
"Resource": "arn:aws:ec2:*:*:instance/*",
"Condition": {
"StringNotEquals": {
"ec2:MetadataHttpTokens": "required"
}
}
}
]
}
EOF
# SCP oluştur (Organizations yönetim hesabından çalıştırılmalı)
aws organizations create-policy
--name "SecurityBaselineSCP"
--type SERVICE_CONTROL_POLICY
--description "Tum organizasyon icin temel guvenlik kisitlamalari"
--content file://organization-scp-security.json
RequireIMDSv2 condition’ı özellikle önemli: IMDSv1’de saldırganlar, SSRF açıkları aracılığıyla instance metadata’ya erişerek IAM credential’larını çalabilir. Bu SCP ile tüm organizasyonda IMDSv2 zorunlu hale gelir.
Senaryo 7: IAM Access Analyzer ile Sürekli İzleme
Manuel review yapmak yeterli değil, süreci otomatize etmek gerekiyor. IAM Access Analyzer, dış erişime açık kaynakları sürekli izler.
# Access Analyzer oluştur
aws accessanalyzer create-analyzer
--analyzer-name "ProductionAccessAnalyzer"
--type ACCOUNT
--tags Environment=production
# Mevcut bulgular var mı kontrol et
aws accessanalyzer list-findings
--analyzer-arn "arn:aws:access-analyzer:eu-west-1:123456789012:analyzer/ProductionAccessAnalyzer"
--filter '{"status": {"eq": ["ACTIVE"]}}'
--query 'findings[*].{ResourceType:resourceType,Resource:resource,Principal:principal}'
--output table
# Tüm kullanıcıların aktif access key'lerini listele (90 günden eski olanları bul)
aws iam generate-credential-report
sleep 10
aws iam get-credential-report
--query 'Content'
--output text | base64 --decode |
awk -F',' 'NR>1 && $9=="true" {
cmd = "date -d " $10 " +%s 2>/dev/null || date -j -f %Y-%m-%dT%H:%M:%S+00:00 " $10 " +%s"
cmd | getline key_date
close(cmd)
current = systime()
age_days = (current - key_date) / 86400
if (age_days > 90) {
print $1, "Access Key 1 age:", int(age_days), "days - ROTATE NEEDED"
}
}'
Pratik Tavsiyeler ve Sık Yapılan Hatalar
Wildcard Kullanımını Minimize Edin
En sık görülen hata, action veya resource için kullanmaktır. Her kullandığınızda, kendinize şunu sorun: “Bu gerçekten gerekli mi?” Çoğu zaman değildir.
s3:*yerine sadece ihtiyaç duyulan action’ları listeleyinResource: "*"yerine ARN bazlı kısıtlama yapın- Mecburen wildcard kullanmanız gerekiyorsa, Condition bloklarıyla daraltın
Managed Policy’lere Körce Güvenmeyin
AWS’nin sağladığı managed policy’ler (AmazonS3FullAccess, AdministratorAccess gibi) kullanım kolaylığı sunar, ancak genellikle ihtiyaçtan çok daha fazla yetki içerir. Bu policy’leri başlangıç noktası olarak kullanın, sonra custom policy yazın.
Tag-Based Access Control Kullanın
Kaynakları tag’lendirmek ve tag’lere göre erişim kontrolü yapmak, ölçeklenebilir bir IAM stratejisinin temelidir.
- Her kaynağa
Environment(dev/staging/prod) tag’i ekleyin - Her kaynağa
Teamtag’i ekleyin - IAM policy’lerde
aws:ResourceTagcondition’ını kullanın
Role’leri Düzenli Audit Edin
Her üç ayda bir şunları yapın:
- Kullanılmayan role’leri devre dışı bırakın veya silin
GetServiceLastAccessedDetailsile kullanılmayan yetkileri kaldırın- 90 günden eski access key’leri rotate edin
- MFA aktif olmayan hesapları tespit edin ve uyarı gönderin
Least Privilege Uygularken Dikkat Edilecekler
- Önce izinleri geniş tutup sonra daraltmak, baştan dar tutmaktan daha kolaydır; ama pratikte daraltma genellikle ertelenir, bu yüzden baştan minimal başlayın
- Servis hesapları için asla console erişimi vermeyin
- Cross-account access için role chaining kullanın, credential paylaşımından kaçının
- CI/CD pipeline’ları için özel role’ler oluşturun ve bu role’lere sadece deployment için gereken yetkileri verin
AWS Config ile Compliance Kontrolü
Policy’lerin doğru uygulandığını sürekli kontrol etmek için AWS Config’i kullanabilirsiniz.
# Root account MFA kontrolü için Config rule aktive et
aws configservice put-config-rule
--config-rule '{
"ConfigRuleName": "root-account-mfa-enabled",
"Source": {
"Owner": "AWS",
"SourceIdentifier": "ROOT_ACCOUNT_MFA_ENABLED"
}
}'
# IAM policy wildcard kontrolü
aws configservice put-config-rule
--config-rule '{
"ConfigRuleName": "iam-no-inline-policy-check",
"Source": {
"Owner": "AWS",
"SourceIdentifier": "IAM_NO_INLINE_POLICY_CHECK"
}
}'
# Uyumsuz kaynakları listele
aws configservice get-compliance-details-by-config-rule
--config-rule-name "root-account-mfa-enabled"
--compliance-types NON_COMPLIANT
--query 'EvaluationResults[*].EvaluationResultIdentifier.EvaluationResultQualifier.ResourceId'
Sonuç
En az yetki prensibi, AWS güvenliğinin temel taşıdır. Başlangıçta fazladan iş gibi görünse de uzun vadede hem güvenlik açıklarını minimize eder hem de audit ve compliance süreçlerini kolaylaştırır. Bu yazıda ele aldığımız yaklaşımları özetlersek:
Hemen uygulamanız gerekenler:
- Mevcut policy’leri
GetServiceLastAccessedDetailsile audit edin AdministratorAccessve*wildcard kullanımlarını tespit edin- Root account için MFA zorunlu kılın ve access key’lerini silin
- IAM Access Analyzer’ı aktive edin
Orta vadeli hedefler:
- Tüm managed policy’lerin yerini custom policy’ler alsın
- Tag-based access control altyapısını kurun
- Permission boundary’leri developer ekipleri için zorunlu kılın
- Çeyreklik IAM review sürecini otomatize edin
Uzun vadeli strateji:
- AWS Organizations ve SCP’yi multi-account stratejinizin merkezine koyun
- Her deployment pipeline’ında IAM policy review adımı ekleyin
- Güvenlik ekibini geliştirici süreçlerin içine dahil edin (shift-left security)
IAM güvenliği bir kere yapıp biten bir iş değil, sürekli bakım gerektiren bir süreçtir. Her yeni servis, her yeni team member, her yeni deployment bu sürece dahil edilmeli. Şimdi konsolunuzu açın ve AdministratorAccess olan kaç role var, bir bakın. Sürprizlerle karşılaşabilirsiniz.
