AWS Organizations ile Çoklu Hesap Yönetimi
Onlarca AWS hesabını tek tek yönetmeye çalışmak, bir noktadan sonra gerçek bir kabusa dönüşüyor. Hangi hesapta hangi servis var, faturaları kim ödüyor, güvenlik politikaları tutarlı mı? Bunların hepsini manuel takip etmeye çalışmak hem zaman kaybı hem de hata riskini ciddi ölçüde artırıyor. AWS Organizations tam da bu sorunu çözmek için tasarlandı ve doğru kurulduğunda çok hesaplı ortamları yönetmek hem güvenli hem de verimli hale geliyor.
AWS Organizations Nedir ve Neden Kullanmalısın?
AWS Organizations, birden fazla AWS hesabını merkezi olarak yönetmenizi sağlayan bir servistir. Tek bir management account (eski adıyla master account) üzerinden tüm member hesaplara politika uygulayabilir, fatura konsolidasyonu yapabilir ve hesap oluşturmayı otomatize edebilirsiniz.
Gerçek dünya senaryosu olarak düşünün: Bir teknoloji şirketiniz var, development, staging ve production ortamlarınız mevcut. Bir de bunların üstüne GDPR uyumluluğu için ayrı bir veri hesabı, güvenlik ekibi için ayrı bir security hesabı gerekiyor. Birkaç yıl içinde 15-20 hesaba ulaşmak çok normal. İşte o noktada Organizations olmadan hayat çekilmez hale geliyor.
Temel kavramlar:
- Management Account: Organizasyonun sahibi olan hesap. Buraya kritik iş yükleri koymayın, sadece yönetim için kullanın.
- Member Account: Organizasyona dahil olan diğer hesaplar.
- Organizational Unit (OU): Hesapları gruplamak için kullanılan hiyerarşik yapı.
- Service Control Policy (SCP): OU veya hesap seviyesinde izin sınırları belirleyen politikalar.
- Consolidated Billing: Tüm hesapların faturasını tek yerden görme ve ödeme imkanı.
Organizasyon Yapısını Tasarlamak
Organizations’ı kurmadan önce hiyerarşinizi planlamanız şart. Çoğu şirket aşağıdaki yapıyı kullanır:
Root
├── Security OU
│ └── Security Account
├── Infrastructure OU
│ └── Shared Services Account
├── Workloads OU
│ ├── Production OU
│ │ └── Prod Accounts
│ └── NonProd OU
│ ├── Dev Accounts
│ └── Staging Accounts
└── Sandbox OU
└── Developer Accounts
Bu yapı AWS’in kendisinin önerdiği landing zone yaklaşımına dayanıyor. Sandbox hesapları geliştiricilerin özgürce deney yapabileceği, production hesapları ise sıkı kısıtlamalar altındaki hesaplar olacak.
CLI ile Organizations Kurulumu
Organizations’ı AWS Console üzerinden de kurabilirsiniz ama gerçek sysadmin olarak CLI ve Infrastructure as Code kullanmak tercih edilmeli. Önce mevcut durumu kontrol edelim:
# Mevcut organizasyon bilgisini al
aws organizations describe-organization
# Eğer organizations henüz kurulmadıysa oluştur
aws organizations create-organization --feature-set ALL
# Mevcut OU'ları listele
aws organizations list-roots
# Root ID'yi not al, aşağıdaki komutlarda kullanacağız
# Root altındaki OU'ları listele
ROOT_ID=$(aws organizations list-roots --query 'Roots[0].Id' --output text)
aws organizations list-organizational-units-for-parent --parent-id $ROOT_ID
Şimdi OU’ları oluşturalım:
#!/bin/bash
# OU yapısını oluşturan script
ROOT_ID=$(aws organizations list-roots --query 'Roots[0].Id' --output text)
# Ana OU'ları oluştur
SECURITY_OU=$(aws organizations create-organizational-unit
--parent-id $ROOT_ID
--name "Security"
--query 'OrganizationalUnit.Id'
--output text)
INFRA_OU=$(aws organizations create-organizational-unit
--parent-id $ROOT_ID
--name "Infrastructure"
--query 'OrganizationalUnit.Id'
--output text)
WORKLOADS_OU=$(aws organizations create-organizational-unit
--parent-id $ROOT_ID
--name "Workloads"
--query 'OrganizationalUnit.Id'
--output text)
SANDBOX_OU=$(aws organizations create-organizational-unit
--parent-id $ROOT_ID
--name "Sandbox"
--query 'OrganizationalUnit.Id'
--output text)
# Workloads altına Production ve NonProd OU'larını oluştur
PROD_OU=$(aws organizations create-organizational-unit
--parent-id $WORKLOADS_OU
--name "Production"
--query 'OrganizationalUnit.Id'
--output text)
NONPROD_OU=$(aws organizations create-organizational-unit
--parent-id $WORKLOADS_OU
--name "NonProduction"
--query 'OrganizationalUnit.Id'
--output text)
echo "OU Yapısı oluşturuldu:"
echo "Security OU: $SECURITY_OU"
echo "Infrastructure OU: $INFRA_OU"
echo "Production OU: $PROD_OU"
echo "NonProduction OU: $NONPROD_OU"
echo "Sandbox OU: $SANDBOX_OU"
Yeni Hesap Oluşturma ve Taşıma
Organizations içinde yeni hesap oluşturmak çok basit:
# Yeni hesap oluştur
aws organizations create-account
--email "[email protected]"
--account-name "Development-App1"
--iam-user-access-to-billing ALLOW
--role-name "OrganizationAccountAccessRole"
# Hesap oluşturma durumunu kontrol et (biraz zaman alabilir)
aws organizations list-create-account-status
--states SUCCEEDED
--query 'CreateAccountStatuses[*].[AccountName,AccountId,State]'
--output table
# Hesabı ilgili OU'ya taşı
ACCOUNT_ID="123456789012"
aws organizations move-account
--account-id $ACCOUNT_ID
--source-parent-id $ROOT_ID
--destination-parent-id $NONPROD_OU
Önemli bir not: OrganizationAccountAccessRole rolü, management account’ın member hesaplara erişmesini sağlar. Bu rolü silmeyin veya adını değiştirmeyin, aksi halde hesap üzerindeki kontrolünüzü kaybedebilirsiniz.
Service Control Policy (SCP) ile Güvenlik Sınırları
SCP’ler Organizations’ın en güçlü özelliklerinden biri. Bir SCP, hedef hesaptaki root kullanıcı dahil tüm kullanıcı ve rollerin yapabileceği işlemlerin üst sınırını belirler. IAM politikaları ile SCP’nin kesişim noktası geçerlidir.
Pratik bir senaryo: Production ortamınızda hiç kimsenin EC2 instance’ları durdurup silememesini istiyorsunuz, bu işlem sadece özel bir role verilen erişimle yapılabilmeli.
{
"Version": "2012-10-17",
"Statement": [
{
"Sid": "DenyEC2StopTerminate",
"Effect": "Deny",
"Action": [
"ec2:StopInstances",
"ec2:TerminateInstances"
],
"Resource": "*",
"Condition": {
"StringNotLike": {
"aws:PrincipalARN": [
"arn:aws:iam::*:role/ProductionOpsRole",
"arn:aws:iam::*:role/OrganizationAccountAccessRole"
]
}
}
}
]
}
Bu SCP’yi oluşturup uygulamak için:
# SCP'yi dosyadan oluştur
aws organizations create-policy
--name "DenyEC2StopTerminateInProd"
--description "Production'da EC2 durdurma ve silmeyi engeller"
--type SERVICE_CONTROL_POLICY
--content file://deny-ec2-stop-terminate.json
# Policy ID'yi al
POLICY_ID=$(aws organizations list-policies
--filter SERVICE_CONTROL_POLICY
--query "Policies[?Name=='DenyEC2StopTerminateInProd'].Id"
--output text)
# SCP'yi Production OU'ya uygula
aws organizations attach-policy
--policy-id $POLICY_ID
--target-id $PROD_OU
# Uygulandığını doğrula
aws organizations list-policies-for-target
--target-id $PROD_OU
--filter SERVICE_CONTROL_POLICY
Güvenlik için Temel SCP’ler
Aşağıdaki SCP her organizasyonda olması gereken temel politikaları içeriyor. Bunu root seviyesine uygulayın:
{
"Version": "2012-10-17",
"Statement": [
{
"Sid": "DenyLeavingOrganization",
"Effect": "Deny",
"Action": [
"organizations:LeaveOrganization"
],
"Resource": "*"
},
{
"Sid": "DenyDisablingCloudTrail",
"Effect": "Deny",
"Action": [
"cloudtrail:StopLogging",
"cloudtrail:DeleteTrail",
"cloudtrail:UpdateTrail"
],
"Resource": "*",
"Condition": {
"StringNotLike": {
"aws:PrincipalARN": "arn:aws:iam::*:role/SecurityAuditRole"
}
}
},
{
"Sid": "DenyRootUserActions",
"Effect": "Deny",
"Action": "*",
"Resource": "*",
"Condition": {
"StringLike": {
"aws:PrincipalType": "Root"
}
}
},
{
"Sid": "DenyNonApprovedRegions",
"Effect": "Deny",
"NotAction": [
"iam:*",
"organizations:*",
"support:*",
"cloudfront:*",
"route53:*",
"waf:*"
],
"Resource": "*",
"Condition": {
"StringNotEquals": {
"aws:RequestedRegion": [
"eu-west-1",
"eu-central-1",
"us-east-1"
]
}
}
}
]
}
DenyLeavingOrganization: Bir hesabın organizasyonu terk etmesini önler. Bunu unutursanız bir gün gelir birisi kazayla (ya da kasıtlı) hesabı organizasyondan çıkarır ve kontrolü kaybedersiniz.
DenyDisablingCloudTrail: CloudTrail’in kapatılmasını engeller. Audit log’larınızın silinmemesi kritik önem taşır.
DenyRootUserActions: Root kullanıcısının herhangi bir işlem yapmasını engeller. Evet, root bile SCP ile kısıtlanabilir.
DenyNonApprovedRegions: Onaylanmamış bölgelerde kaynak oluşturulmasını önler. Hem maliyet kontrolü hem de veri egemenliği için önemli.
AWS Config ve CloudTrail’i Merkezi Hale Getirme
Her hesapta ayrı ayrı CloudTrail kurmak yerine Organizations düzeyinde merkezi bir trail oluşturun:
# Önce merkezi log bucket'ı management account'ta oluşturun
# sonra bu komutu çalıştırın
aws cloudtrail create-trail
--name "OrganizationTrail"
--s3-bucket-name "merkezi-cloudtrail-logs-sizinid"
--is-organization-trail
--is-multi-region-trail
--enable-log-file-validation
--include-global-service-events
# Trail'i aktif et
aws cloudtrail start-logging --name "OrganizationTrail"
# Trail durumunu kontrol et
aws cloudtrail get-trail-status --name "OrganizationTrail"
AWS Config için de benzer bir yaklaşım:
# Organizations genelinde Config aggregator oluştur
aws configservice put-configuration-aggregator
--configuration-aggregator-name "OrganizationAggregator"
--organization-aggregation-source '{
"RoleArn": "arn:aws:iam::MANAGEMENT_ACCOUNT_ID:role/aws-service-role/config.amazonaws.com/AWSServiceRoleForConfig",
"AllAwsRegions": true
}'
# Tüm hesaplardaki Config kurallarını listele
aws configservice describe-aggregate-compliance-by-config-rules
--configuration-aggregator-name "OrganizationAggregator"
--query 'AggregateComplianceByConfigRules[?ComplianceType!=`COMPLIANT`]'
Terraform ile Organizations Yönetimi
Gerçek production ortamında Organizations’ı Terraform ile yönetmek çok daha sağlıklı. Sürüm kontrolü, gözden geçirme süreci ve tekrarlanabilirlik açısından Infrastructure as Code vazgeçilmez:
# organizations.tf
terraform {
required_providers {
aws = {
source = "hashicorp/aws"
version = "~> 5.0"
}
}
}
# Organizations yapısı
resource "aws_organizations_organization" "main" {
aws_service_access_principals = [
"cloudtrail.amazonaws.com",
"config.amazonaws.com",
"sso.amazonaws.com",
"securityhub.amazonaws.com",
"guardduty.amazonaws.com",
]
feature_set = "ALL"
enabled_policy_types = [
"SERVICE_CONTROL_POLICY",
"TAG_POLICY",
]
}
# OU'ları oluştur
resource "aws_organizations_organizational_unit" "security" {
name = "Security"
parent_id = aws_organizations_organization.main.roots[0].id
}
resource "aws_organizations_organizational_unit" "workloads" {
name = "Workloads"
parent_id = aws_organizations_organization.main.roots[0].id
}
resource "aws_organizations_organizational_unit" "production" {
name = "Production"
parent_id = aws_organizations_organizational_unit.workloads.id
}
resource "aws_organizations_organizational_unit" "sandbox" {
name = "Sandbox"
parent_id = aws_organizations_organization.main.roots[0].id
}
# Temel SCP
resource "aws_organizations_policy" "deny_leaving_org" {
name = "DenyLeavingOrganization"
description = "Hesapların organizasyonu terk etmesini engeller"
type = "SERVICE_CONTROL_POLICY"
content = jsonencode({
Version = "2012-10-17"
Statement = [
{
Sid = "DenyLeaveOrg"
Effect = "Deny"
Action = ["organizations:LeaveOrganization"]
Resource = "*"
}
]
})
}
# SCP'yi root'a uygula
resource "aws_organizations_policy_attachment" "deny_leaving_org_root" {
policy_id = aws_organizations_policy.deny_leaving_org.id
target_id = aws_organizations_organization.main.roots[0].id
}
# Yeni hesap oluştur
resource "aws_organizations_account" "sandbox_developer" {
name = "sandbox-developer-01"
email = "[email protected]"
parent_id = aws_organizations_organizational_unit.sandbox.id
role_name = "OrganizationAccountAccessRole"
lifecycle {
ignore_changes = [role_name]
}
}
Hesaplar Arası IAM Role Assumption
Member hesaplara erişmek için management account’tan role assumption yapmanız gerekir. Günlük operasyonlar için kullanabileceğiniz basit bir script:
#!/bin/bash
# assume-role.sh - Hedef hesaba geçiş yap
TARGET_ACCOUNT_ID=$1
ROLE_NAME=${2:-"OrganizationAccountAccessRole"}
SESSION_NAME="ops-session-$(date +%s)"
if [ -z "$TARGET_ACCOUNT_ID" ]; then
echo "Kullanım: $0 <account-id> [role-name]"
exit 1
fi
echo "Hesap $TARGET_ACCOUNT_ID'ye geçiliyor..."
CREDENTIALS=$(aws sts assume-role
--role-arn "arn:aws:iam::${TARGET_ACCOUNT_ID}:role/${ROLE_NAME}"
--role-session-name "$SESSION_NAME"
--duration-seconds 3600
--query 'Credentials'
--output json)
export AWS_ACCESS_KEY_ID=$(echo $CREDENTIALS | jq -r '.AccessKeyId')
export AWS_SECRET_ACCESS_KEY=$(echo $CREDENTIALS | jq -r '.SecretAccessKey')
export AWS_SESSION_TOKEN=$(echo $CREDENTIALS | jq -r '.SessionToken')
# Doğrulama
CURRENT_IDENTITY=$(aws sts get-caller-identity)
echo "Başarıyla geçiş yapıldı:"
echo $CURRENT_IDENTITY | jq '.'
echo ""
echo "Bu terminali kapatmak için 'exit' yazın."
echo "Kimlik bilgileri 1 saat geçerlidir."
# Yeni shell aç
$SHELL
Bu scripti çalıştırdıktan sonra o terminal penceresinde verdiğiniz tüm AWS komutları hedef hesap üzerinde çalışır. Terminal kapatıldığında eski kimliğinize geri dönersiniz.
Tag Policy ile Maliyet Yönetimi
Tag policy’ler, tüm organizasyonda tutarlı tagging sağlar. Maliyet dağılımını izlemek için hayati öneme sahiptir:
# Tag policy oluştur
cat > tag-policy.json << 'EOF'
{
"tags": {
"Environment": {
"tag_key": {
"@@assign": "Environment"
},
"tag_value": {
"@@assign": [
"production",
"staging",
"development",
"sandbox"
]
},
"enforced_for": {
"@@assign": [
"ec2:instance",
"rds:db",
"s3:bucket"
]
}
},
"CostCenter": {
"tag_key": {
"@@assign": "CostCenter"
},
"enforced_for": {
"@@assign": [
"ec2:instance",
"rds:db"
]
}
}
}
}
EOF
aws organizations create-policy
--name "RequiredTags"
--description "Kritik kaynaklar için zorunlu tag politikası"
--type TAG_POLICY
--content file://tag-policy.json
# Tag policy'yi workloads OU'ya uygula
TAG_POLICY_ID=$(aws organizations list-policies
--filter TAG_POLICY
--query "Policies[?Name=='RequiredTags'].Id"
--output text)
aws organizations attach-policy
--policy-id $TAG_POLICY_ID
--target-id $WORKLOADS_OU
Yaygın Hatalar ve Çözümleri
Organizations kullanırken sıkça karşılaşılan sorunlar:
Management account’a iş yükü koymak: Management account’ta EC2 instance çalıştırıyorsanız yanlış yapıyorsunuzdur. Bu hesap sadece yönetim için olmalı, içinde uygulama bulunmamalı.
SCP’leri test etmeden uygulamak: Production OU’ya SCP uygulamadan önce sandbox hesapta test edin. Yanlış bir SCP tüm ekibin erişimini kesebilir.
Consolidated billing’i yanlış anlamak: Fatura konsolidasyonu otomatik olarak maliyet azaltmaz. Reserved Instance ve Savings Plans paylaşımı için özellikle yapılandırmanız gerekir.
OrganizationAccountAccessRole’ü silmek: Member hesaplarda bu rolü silerseniz management account’tan erişim imkanını kaybedersiniz. Kurtarmanın tek yolu o hesabın root email’ine erişmek.
Sonuç
AWS Organizations, büyüyen cloud altyapılarını yönetmek için gerçekten güçlü bir araç. Doğru OU yapısı, iyi tasarlanmış SCP’ler ve merkezi loglama ile çok hesaplı ortamları güvenli ve yönetilebilir hale getirebilirsiniz.
Başlangıç için minimum yapı şöyle olmalı: Management account, Security account, Shared Services account ve iş yükleri için ayrı hesaplar. Buradan itibaren ihtiyaçlarınıza göre büyütebilirsiniz.
En önemli tavsiyem, Organizations’ı Terraform veya CloudFormation gibi bir IaC aracıyla yönetmeniz. Hangi hesabın nerede olduğunu, hangi SCP’nin neye uygulandığını kod olarak takip etmek, hem audit açısından hem de ekip içi işbirliği açısından büyük fark yaratıyor. AWS Control Tower’a da bakmanızı öneririm, Organizations’ın üzerine inşa edilmiş hazır bir landing zone çözümü sunuyor ve başlangıç kurulumunu önemli ölçüde kolaylaştırıyor.
