AWS IAM Rol ve Politika Oluşturma Rehberi

AWS’de bir şeyler kurarken “bu servise şu servisten erişim vermem lazım ama nasıl?” diye kendinizi buldunuz mu hiç? Ya da üretim ortamında bir Lambda fonksiyonunun S3 bucket’ına erişememesi yüzünden saatlerce hata ayıkladınız mı? IAM (Identity and Access Management), AWS’nin bel kemiğidir ve doğru anlaşılmadığında hem güvenlik açıkları hem de sinir bozucu erişim sorunları kaçınılmaz olur. Bu yazıda IAM rol ve politika kavramlarını gerçek dünya senaryolarıyla birlikte, sıfırdan ileri seviyeye kadar ele alacağız.

IAM Temelleri: Kim Kimdir?

IAM’ı anlamak için önce temel aktörleri tanımak gerekiyor.

IAM User (Kullanıcı): Bir kişiyi veya uygulamayı temsil eder. Uzun vadeli erişim anahtarları (access key) kullanır. Genellikle insanlar için kullanılır, servisler için değil.

IAM Group (Grup): Kullanıcıları mantıksal olarak gruplar. Gruba atanan politika, gruptaki tüm kullanıcılara uygulanır.

IAM Role (Rol): Bir kimlik tanımlar ama kalıcı kimlik bilgisi yoktur. Geçici credential üretir. EC2, Lambda gibi AWS servisleri veya başka AWS hesapları bu rolleri üstlenir (assume role).

IAM Policy (Politika): Neye izin verilip neyin yasaklandığını tanımlayan JSON dokümanıdır. User, Group veya Role’e attach edilir.

İşte en önemli nokta: Servisler için her zaman rol kullanın, kullanıcı değil. Lambda’ya S3 erişimi verecekseniz, Lambda’ya bir rol atarsınız. Bu rol geçici token üretir ve çok daha güvenlidir.

IAM Policy Anatomisi

Bir politikanın yapısını anlamadan rol oluşturmak, temelsiz bina yapmak gibidir. Temel bir policy JSON’ına bakalım:

cat << 'EOF' > my-policy.json
{
  "Version": "2012-10-17",
  "Statement": [
    {
      "Sid": "AllowS3ReadAccess",
      "Effect": "Allow",
      "Action": [
        "s3:GetObject",
        "s3:ListBucket"
      ],
      "Resource": [
        "arn:aws:s3:::my-production-bucket",
        "arn:aws:s3:::my-production-bucket/*"
      ],
      "Condition": {
        "StringEquals": {
          "aws:RequestedRegion": "eu-west-1"
        }
      }
    }
  ]
}
EOF

Policy’nin anatomisini madde madde açıklayalım:

  • Version: Her zaman 2012-10-17 kullanın. Bu tarihin önemi yok, AWS’nin policy dil versiyonunu ifade ediyor
  • Statement: Bir veya birden fazla izin bloğu içeren dizi
  • Sid: Statement ID, isteğe bağlı ama takip için önemli bir tanımlayıcı
  • Effect: Allow veya Deny, başka seçenek yok
  • Action: Hangi API çağrısına izin verildiği, servis:İşlem formatında
  • Resource: Bu aksiyonun hangi kaynağa uygulanacağı, ARN formatında
  • Condition: Opsiyonel, ekstra koşullar ekler

Önemli bir not: AWS’de varsayılan olarak her şey reddedilir. Siz izin vermediğiniz sürece hiçbir şeye erişilemez. Explicit Deny ise Allow’u geçersiz kılar, bunu aklınızdan çıkarmayın.

İlk Rolünüzü AWS CLI ile Oluşturmak

AWS Console’dan rol oluşturmak görsel olarak kolay olsa da, gerçek sysadmin’ler işleri CLI’dan yapar. Hem tekrar edilebilir hem de otomasyona uygun olur.

Önce bir Trust Policy tanımlamamız gerekiyor. Bu, rolü kimin üstlenebileceğini belirtir:

# EC2 instanceları için trust policy
cat << 'EOF' > ec2-trust-policy.json
{
  "Version": "2012-10-17",
  "Statement": [
    {
      "Effect": "Allow",
      "Principal": {
        "Service": "ec2.amazonaws.com"
      },
      "Action": "sts:AssumeRole"
    }
  ]
}
EOF

# Rolü oluştur
aws iam create-role 
  --role-name MyEC2Role 
  --assume-role-policy-document file://ec2-trust-policy.json 
  --description "EC2 instancelari icin ornek rol" 
  --tags Key=Environment,Value=production Key=Team,Value=sysadmin

Şimdi bu role bir politika ekleyelim. Managed policy kullanmak ve custom policy kullanmak arasında seçim yapabilirsiniz:

# AWS managed policy ekle (hazır, AWS tarafından yönetilen)
aws iam attach-role-policy 
  --role-name MyEC2Role 
  --policy-arn arn:aws:iam::aws:policy/AmazonSSMManagedInstanceCore

# Kendi custom policy'nizi oluşturun
aws iam create-policy 
  --policy-name MyCustomS3Policy 
  --policy-document file://my-policy.json 
  --description "Production S3 bucket okuma politikasi"

# Oluşturulan custom policy'yi role ekle
# ACCOUNT_ID'yi kendi hesap numaranızla değiştirin
aws iam attach-role-policy 
  --role-name MyEC2Role 
  --policy-arn arn:aws:iam::123456789012:policy/MyCustomS3Policy

Gerçek Dünya Senaryosu 1: Lambda’dan DynamoDB ve S3 Erişimi

Diyelim ki bir e-ticaret sitesi için sipariş işleme Lambda fonksiyonu yazıyorsunuz. Bu fonksiyon DynamoDB’den sipariş okuyacak, işleyecek ve sonucu S3’e yazacak. İşte bu senaryo için minimal privilege prensibini uygulayarak rol oluşturalım:

# Lambda trust policy
cat << 'EOF' > lambda-trust-policy.json
{
  "Version": "2012-10-17",
  "Statement": [
    {
      "Effect": "Allow",
      "Principal": {
        "Service": "lambda.amazonaws.com"
      },
      "Action": "sts:AssumeRole"
    }
  ]
}
EOF

# Sipariş işleme için custom policy
cat << 'EOF' > order-processing-policy.json
{
  "Version": "2012-10-17",
  "Statement": [
    {
      "Sid": "DynamoDBReadOrders",
      "Effect": "Allow",
      "Action": [
        "dynamodb:GetItem",
        "dynamodb:Query",
        "dynamodb:Scan"
      ],
      "Resource": "arn:aws:dynamodb:eu-west-1:123456789012:table/Orders"
    },
    {
      "Sid": "S3WriteProcessedOrders",
      "Effect": "Allow",
      "Action": [
        "s3:PutObject"
      ],
      "Resource": "arn:aws:s3:::processed-orders-bucket/*"
    },
    {
      "Sid": "CloudWatchLogs",
      "Effect": "Allow",
      "Action": [
        "logs:CreateLogGroup",
        "logs:CreateLogStream",
        "logs:PutLogEvents"
      ],
      "Resource": "arn:aws:logs:eu-west-1:123456789012:*"
    }
  ]
}
EOF

# Rolü oluştur
aws iam create-role 
  --role-name OrderProcessingLambdaRole 
  --assume-role-policy-document file://lambda-trust-policy.json

# Policy'yi oluştur ve attach et
aws iam create-policy 
  --policy-name OrderProcessingPolicy 
  --policy-document file://order-processing-policy.json

aws iam attach-role-policy 
  --role-name OrderProcessingLambdaRole 
  --policy-arn arn:aws:iam::123456789012:policy/OrderProcessingPolicy

echo "Rol ARN'ini kontrol et:"
aws iam get-role --role-name OrderProcessingLambdaRole 
  --query 'Role.Arn' --output text

Bu yaklaşımda dikkat edin: Lambda sadece DynamoDB’den okuyabilir, yazamaz. S3’e sadece yazabilir, okuyamaz. CloudWatch Logs için ise sadece log yazma izni var. Bu least privilege (minimum ayrıcalık) prensibinin ta kendisi.

Gerçek Dünya Senaryosu 2: Cross-Account Erişim

Bu biraz daha ileri seviye ama gerçek ortamlarda sık karşılaşılan bir durum. Örneğin dev hesabınızdaki bir EC2’nun prod hesabındaki S3’e erişmesi gerekiyor. Cross-account role assumption tam bu iş için var.

Prod hesabında (123456789012) yapılacaklar:

# Prod hesabında, dev hesabına güvenen bir rol oluştur
cat << 'EOF' > cross-account-trust.json
{
  "Version": "2012-10-17",
  "Statement": [
    {
      "Effect": "Allow",
      "Principal": {
        "AWS": "arn:aws:iam::987654321098:role/DevEC2Role"
      },
      "Action": "sts:AssumeRole",
      "Condition": {
        "StringEquals": {
          "sts:ExternalId": "unique-external-id-buraya"
        }
      }
    }
  ]
}
EOF

aws iam create-role 
  --role-name ProdS3AccessRole 
  --assume-role-policy-document file://cross-account-trust.json 
  --profile prod-account

aws iam attach-role-policy 
  --role-name ProdS3AccessRole 
  --policy-arn arn:aws:iam::aws:policy/AmazonS3ReadOnlyAccess 
  --profile prod-account

Dev hesabında (987654321098) rol üstlenmek:

# Dev EC2'sundan prod rolünü üstlen
CREDS=$(aws sts assume-role 
  --role-arn "arn:aws:iam::123456789012:role/ProdS3AccessRole" 
  --role-session-name "dev-access-session" 
  --external-id "unique-external-id-buraya" 
  --output json)

# Geçici credential'ları export et
export AWS_ACCESS_KEY_ID=$(echo $CREDS | jq -r '.Credentials.AccessKeyId')
export AWS_SECRET_ACCESS_KEY=$(echo $CREDS | jq -r '.Credentials.SecretAccessKey')
export AWS_SESSION_TOKEN=$(echo $CREDS | jq -r '.Credentials.SessionToken')

# Artık prod hesabının S3'üne erişebilirsiniz
aws s3 ls s3://prod-data-bucket/

ExternalId kullanımı önemlidir. “Confused Deputy” saldırısını önler. Üçüncü parti bir servise rol erişimi verirken mutlaka kullanın.

Policy Tipleri ve Farkları

AWS’de birkaç farklı policy tipi var ve bunları karıştırmak can sıkıcı hatalara yol açabilir:

  • Identity-based Policy: User, Group veya Role’e attach edilir. “Ben ne yapabilirim?” sorusunu yanıtlar
  • Resource-based Policy: S3, SQS gibi kaynakların kendisine yazılır. “Bana kim erişebilir?” sorusunu yanıtlar
  • Permission Boundary: Bir kullanıcı veya rolün maksimum alabilebileceği izinleri sınırlar. Devops ekibi bunu kullanarak developer’ların kendilerine aşırı izin vermesini engeller
  • Service Control Policy (SCP): AWS Organizations seviyesinde çalışır. Tüm hesap için üst sınır koyar
  • Session Policy: AssumeRole sırasında geçici olarak izinleri kısıtlar

Permission Boundary örneği özellikle önemli. Diyelim ki developer’larınızın kendi IAM rollerini oluşturmasına izin vermek istiyorsunuz ama AdminAccess verememezsiniz:

cat << 'EOF' > developer-boundary.json
{
  "Version": "2012-10-17",
  "Statement": [
    {
      "Effect": "Allow",
      "Action": [
        "s3:*",
        "dynamodb:*",
        "lambda:*",
        "logs:*"
      ],
      "Resource": "*"
    },
    {
      "Effect": "Deny",
      "Action": [
        "iam:*",
        "organizations:*",
        "account:*"
      ],
      "Resource": "*"
    }
  ]
}
EOF

# Boundary'yi politika olarak oluştur
aws iam create-policy 
  --policy-name DeveloperPermissionBoundary 
  --policy-document file://developer-boundary.json

# Developer rolüne boundary ekleyerek oluştur
aws iam create-role 
  --role-name DeveloperRole 
  --assume-role-policy-document file://lambda-trust-policy.json 
  --permissions-boundary arn:aws:iam::123456789012:policy/DeveloperPermissionBoundary

IAM Policy Simülatörü ile Test Etmek

Rol ve policy oluşturdunuz, peki gerçekten istediğiniz gibi çalışıyor mu? Production’da test etmek yerine IAM Policy Simulator’ü kullanın:

# Belirli bir rolün S3 GetObject yapıp yapamayacağını test et
aws iam simulate-principal-policy 
  --policy-source-arn "arn:aws:iam::123456789012:role/OrderProcessingLambdaRole" 
  --action-names "s3:GetObject" 
  --resource-arns "arn:aws:s3:::processed-orders-bucket/test.json"

# Birden fazla aksiyonu aynı anda test et
aws iam simulate-principal-policy 
  --policy-source-arn "arn:aws:iam::123456789012:role/OrderProcessingLambdaRole" 
  --action-names "s3:PutObject" "s3:DeleteObject" "dynamodb:DeleteItem" 
  --resource-arns "arn:aws:s3:::processed-orders-bucket/*" 
  --query 'EvaluationResults[*].{Action:EvalActionName,Decision:EvalDecision}'

Bu komut size her aksiyon için allowed veya implicitDeny / explicitDeny döner. Deployment öncesi bu testi CI/CD pipeline’ınıza ekleyin.

Inline vs Managed Policy: Hangisini Ne Zaman?

Sık sorulan bir soru: Custom policy’yi inline mı yazayım yoksa managed policy mi oluşturayım?

Managed Policy kullanın:

  • Aynı politikayı birden fazla rol/kullanıcıda kullanıyorsanız
  • Politikayı bağımsız olarak versiyonlamak istiyorsanız
  • Politika değişikliklerini merkezi yönetmek istiyorsanız

Inline Policy kullanın:

  • Politika sadece tek bir rol için geçerliyse ve asla paylaşılmayacaksa
  • Rolü silerken politikanın da otomatik silinmesini istiyorsanız
  • Güçlü bir “bu politika bu role özel” garantisi istiyorsanız

Pratik öneri: Genellikle managed policy tercih edin. Inline policy’ler görünürlüğü düşürür ve yönetimini zorlaştırır.

CloudFormation ile IAM Rol Yönetimi

Gerçek ortamlarda IAM rollerini Infrastructure as Code (IaC) ile yönetmek şart. CloudFormation template’i:

cat << 'EOF' > iam-role-stack.yaml
AWSTemplateFormatVersion: '2010-09-09'
Description: Ornek IAM Rol Stack

Parameters:
  Environment:
    Type: String
    AllowedValues: [dev, staging, production]
    Default: dev

Resources:
  AppLambdaRole:
    Type: AWS::IAM::Role
    Properties:
      RoleName: !Sub "AppLambdaRole-${Environment}"
      AssumeRolePolicyDocument:
        Version: '2012-10-17'
        Statement:
          - Effect: Allow
            Principal:
              Service: lambda.amazonaws.com
            Action: sts:AssumeRole
      ManagedPolicyArns:
        - arn:aws:iam::aws:policy/service-role/AWSLambdaBasicExecutionRole
      Policies:
        - PolicyName: AppSpecificPolicy
          PolicyDocument:
            Version: '2012-10-17'
            Statement:
              - Effect: Allow
                Action:
                  - dynamodb:GetItem
                  - dynamodb:PutItem
                  - dynamodb:UpdateItem
                Resource: !Sub "arn:aws:dynamodb:${AWS::Region}:${AWS::AccountId}:table/App-${Environment}"
      Tags:
        - Key: Environment
          Value: !Ref Environment

Outputs:
  RoleArn:
    Value: !GetAtt AppLambdaRole.Arn
    Export:
      Name: !Sub "AppLambdaRoleArn-${Environment}"
EOF

# Stack'i deploy et
aws cloudformation deploy 
  --template-file iam-role-stack.yaml 
  --stack-name app-iam-roles 
  --parameter-overrides Environment=production 
  --capabilities CAPABILITY_NAMED_IAM

CAPABILITY_NAMED_IAM flag’ini unutmayın. CloudFormation IAM kaynakları oluşturduğunda bunu zorunlu tutar.

Güvenlik İpuçları ve Sık Yapılan Hatalar

IAM konusunda yıllar içinde gördüğüm yaygın hataları ve çözümlerini paylaşayım:

Wildcard kullanımından kaçının: "Action": "" veya "Resource": "" kullanmak güvenlik deliği açar. Her zaman spesifik action ve resource belirtin. Eğer tam olarak neye ihtiyacınız olduğunu bilmiyorsanız, CloudTrail loglarını inceleyerek gerçekte kullanılan izinleri bulun.

Access Key rotation:

# Tüm kullanıcıların access key yaşını kontrol et
aws iam generate-credential-report
aws iam get-credential-report --query 'Content' --output text | base64 -d | 
  awk -F',' 'NR>1 {print $1, $9, $11}' | 
  column -t

# 90 günden eski key'leri bul (basit bir kontrol)
aws iam list-users --query 'Users[*].UserName' --output text | 
  tr 't' 'n' | while read user; do
    aws iam list-access-keys --user-name "$user" 
      --query "AccessKeyMetadata[?Status=='Active'].[UserName,AccessKeyId,CreateDate]" 
      --output text
  done

IAM Access Analyzer kullanın:

# Herkese açık (public) kaynaklarınızı bul
aws accessanalyzer list-findings 
  --analyzer-arn "arn:aws:access-analyzer:eu-west-1:123456789012:analyzer/ConsoleAnalyzer" 
  --filter "status=eq=ACTIVE" 
  --query 'findings[*].{Resource:resource,Type:resourceType,Condition:condition}'

Sık yapılan hatalar:

  • Root hesabını günlük kullanmak: Root için MFA aktifleştirin, access key oluşturmayın ve asla günlük işlerde kullanmayın
  • AdministratorAccess’i cömertçe dağıtmak: Sadece gerçekten ihtiyacı olanlara verin ve bu kişi sayısını minimumda tutun
  • Rol yerine kullanıcı credential’ı uygulamaya gömmek: EC2, ECS, Lambda için her zaman rol kullanın
  • Policy’leri test etmeden deploy etmek: IAM Simulator’ü kullanın
  • Tag koymamak: IAM kaynaklarına environment, team, purpose tag’leri ekleyin, ileride neyin ne olduğunu anlamak için şart

IAM Rollerini Düzenli Auditleyin

Zamanla büyüyen sistemlerde “zombie” roller birikir. Kimse kullanmaz ama silinmez. Bunları bulmak için:

# Son 90 gün içinde hiç kullanılmamış rolleri bul
aws iam get-account-authorization-details 
  --filter Role 
  --query 'RoleDetailList[*].{RoleName:RoleName,LastUsed:RoleLastUsed.LastUsedDate}' 
  --output table

# Belirli bir rolün son kullanım tarihini kontrol et
aws iam get-role 
  --role-name MyEC2Role 
  --query 'Role.RoleLastUsed'

# Bir role attach edilmiş tüm policy'leri listele
aws iam list-attached-role-policies 
  --role-name MyEC2Role

# Inline policy'leri de kontrol et
aws iam list-role-policies 
  --role-name MyEC2Role

Bu audit’i aylık cron job olarak çalıştırıp sonuçları bir S3 bucket’ına veya Slack kanalına göndermek iyi bir pratiktir.

Sonuç

IAM, AWS’nin en kritik bileşenlerinden biri ve doğru kullanılmadığında hem operasyonel hem de güvenlik açısından ciddi sorunlara yol açar. Öğrendiklerimizi özetleyelim:

Her şeyden önce, servisler için kullanıcı değil rol kullanın. Least privilege prensibini asla esgeçmeyin; bugün işe yarıyor diye * vermek, yarın başınızı ağrıtır. Policy’lerinizi mutlaka IAM Simulator ile test edin, production ortamında keşfetmek zorunda kalmayın. Cross-account erişimlerde ExternalId kullanmayı alışkanlık haline getirin. IAM kaynaklarınızı CloudFormation veya Terraform gibi IaC araçlarıyla yönetin, console’dan manuel yapmak ölçeklenmez.

Access Analyzer ve CloudTrail’i aktif tutun, düzenli audit yapın. Kullanılmayan rolleri temizleyin ve permission boundary kullanarak developer’larınıza kontrollü özgürlük verin. Ve son olarak, root hesabınıza MFA ekleyin, access key oluşturmayın ve unutun.

IAM karmaşık görünebilir başta ama sistematik yaklaşınca mantıklı bir yapısı var. Yukarıdaki prensipleri benimsediğinizde hem güvenli hem de yönetilebilir bir AWS ortamı elde edersiniz.

Bir yanıt yazın

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