AWS Certificate Manager ile SSL/TLS Sertifika Yönetimi

SSL sertifika yönetimi, her sysadmin’in başını ağrıtan konulardan biri. Sertifika süresi dolmuş, yenilemeyi unutmuşsun, production’da site çökmüş, müşteriler arıyor… Bu senaryoyu yaşamayan var mı? AWS Certificate Manager (ACM) tam da bu acıyı dindirmek için tasarlanmış bir servis. Ücretsiz SSL/TLS sertifikaları verip otomatik yenileme yapıyor, üstüne üstlük AWS servisleriyle neredeyse sıfır sürtünmeyle entegre çalışıyor. Bu yazıda ACM’i A’dan Z’ye ele alacağız.

AWS Certificate Manager Nedir?

ACM, AWS’in yönetilen SSL/TLS sertifika servisi. Temel olarak iki iş yapıyor: sertifika sağlama ve sertifika yönetimi. Public sertifikalar için Let’s Encrypt benzeri bir mekanizma işletiyor, ancak AWS altyapısıyla çok daha sıkı entegre. Private sertifikalar için ise kendi CA (Certificate Authority) altyapını kurabiliyorsun.

ACM’in öne çıkan özellikleri:

  • Public sertifikalar tamamen ücretsiz
  • Otomatik yenileme (80 gün kala başlıyor)
  • ALB, CloudFront, API Gateway ile native entegrasyon
  • Wildcard sertifika desteği
  • Multi-domain (SAN) sertifika desteği
  • Private CA ile kurumsal PKI altyapısı

Bir önemli not: ACM sertifikaları sadece AWS servisleriyle kullanılabiliyor. Yani sertifikayı indirip kendi sunucuna kuramazsın. EC2 üzerinde çalışan bir Nginx veya Apache için ACM kullanmak istiyorsan, önüne bir ALB koyman gerekiyor.

Ön Koşullar ve Kurulum

AWS CLI kurulu ve konfigüre edilmiş olmasını varsayıyorum. Değilse:

# AWS CLI kurulumu (Linux)
curl "https://awscli.amazonaws.com/awscli-exe-linux-x86_64.zip" -o "awscliv2.zip"
unzip awscliv2.zip
sudo ./aws/install

# Konfigürasyon
aws configure
# AWS Access Key ID, Secret Access Key, Region, Output format gir

IAM tarafında şu izinlere ihtiyacın var:

# Mevcut kullanıcının ACM yetkilerini kontrol et
aws iam simulate-principal-policy 
  --policy-source-arn arn:aws:iam::ACCOUNT_ID:user/kullanici-adi 
  --action-names acm:RequestCertificate acm:DescribeCertificate acm:ListCertificates 
  --query 'EvaluationResults[*].{Action:EvalActionName,Decision:EvalDecision}' 
  --output table

Minimum gerekli IAM policy:

{
  "Version": "2012-10-17",
  "Statement": [
    {
      "Effect": "Allow",
      "Action": [
        "acm:RequestCertificate",
        "acm:DescribeCertificate",
        "acm:ListCertificates",
        "acm:DeleteCertificate",
        "acm:GetCertificate",
        "acm:RenewCertificate",
        "acm:AddTagsToCertificate"
      ],
      "Resource": "*"
    }
  ]
}

Sertifika Talep Etme

DNS Doğrulama ile Sertifika Talebi

DNS doğrulama her zaman tavsiye ettiğim yöntem. Email doğrulamasından çok daha güvenilir ve wildcard sertifikalar için zorunlu.

# Tekil domain için sertifika talebi
aws acm request-certificate 
  --domain-name "ornek.com" 
  --validation-method DNS 
  --subject-alternative-names "www.ornek.com" "api.ornek.com" 
  --tags Key=Environment,Value=production Key=Project,Value=web 
  --region us-east-1

# Wildcard sertifika talebi
aws acm request-certificate 
  --domain-name "*.ornek.com" 
  --validation-method DNS 
  --subject-alternative-names "ornek.com" 
  --tags Key=Environment,Value=production 
  --region us-east-1

Komut çalıştıktan sonra bir sertifika ARN alacaksın. Bu ARN’ı not et, her işlemde lazım olacak:

arn:aws:acm:us-east-1:123456789012:certificate/12345678-1234-1234-1234-123456789012

DNS Doğrulama Kayıtlarını Alma

# Sertifika detaylarını ve DNS validation kayıtlarını görüntüle
CERT_ARN="arn:aws:acm:us-east-1:123456789012:certificate/12345678-1234-1234-1234-123456789012"

aws acm describe-certificate 
  --certificate-arn $CERT_ARN 
  --query 'Certificate.DomainValidationOptions[*].{Domain:DomainName,Name:ResourceRecord.Name,Value:ResourceRecord.Value,Type:ResourceRecord.Type}' 
  --output json

Bu çıktıda CNAME kayıtlarını göreceksin. Bu kayıtları DNS provider’ına ekliyorsun. Route 53 kullanıyorsan bu işlemi otomatize edebilirsin.

Route 53 ile Otomatik DNS Doğrulama

Gerçek dünyada çoğu zaman domain Route 53’te yönetiliyordur. Bu durumda ACM ile Route 53 entegrasyonu işini çok kolaylaştırır:

#!/bin/bash
# Sertifika talep et ve Route 53'te otomatik doğrulama kaydı oluştur

DOMAIN="ornek.com"
REGION="us-east-1"

# Sertifika talep et
CERT_ARN=$(aws acm request-certificate 
  --domain-name "$DOMAIN" 
  --validation-method DNS 
  --subject-alternative-names "www.$DOMAIN" 
  --query 'CertificateArn' 
  --output text 
  --region $REGION)

echo "Sertifika ARN: $CERT_ARN"

# DNS validation kayıtlarını bekle (birkaç saniye sürebilir)
sleep 10

# DNS kayıtlarını al
DNS_RECORDS=$(aws acm describe-certificate 
  --certificate-arn $CERT_ARN 
  --query 'Certificate.DomainValidationOptions[0].ResourceRecord' 
  --output json 
  --region $REGION)

RECORD_NAME=$(echo $DNS_RECORDS | jq -r '.Name')
RECORD_VALUE=$(echo $DNS_RECORDS | jq -r '.Value')

# Route 53 Hosted Zone ID'yi al
HOSTED_ZONE_ID=$(aws route53 list-hosted-zones-by-name 
  --dns-name "$DOMAIN" 
  --query 'HostedZones[0].Id' 
  --output text | cut -d'/' -f3)

echo "Hosted Zone ID: $HOSTED_ZONE_ID"

# CNAME kaydını Route 53'e ekle
aws route53 change-resource-record-sets 
  --hosted-zone-id $HOSTED_ZONE_ID 
  --change-batch "{
    "Changes": [{
      "Action": "UPSERT",
      "ResourceRecordSet": {
        "Name": "$RECORD_NAME",
        "Type": "CNAME",
        "TTL": 300,
        "ResourceRecords": [{
          "Value": "$RECORD_VALUE"
        }]
      }
    }]
  }"

echo "DNS kaydı eklendi. Doğrulama birkaç dakika sürebilir..."

# Sertifikanın verify olmasını bekle
aws acm wait certificate-validated 
  --certificate-arn $CERT_ARN 
  --region $REGION

echo "Sertifika doğrulandı ve kullanıma hazır!"

Sertifikaları Listeleme ve İzleme

Üretim ortamında onlarca sertifika yönetebilirsin. Bunları düzenli takip etmek kritik:

# Tüm sertifikaları listele
aws acm list-certificates 
  --certificate-statuses ISSUED PENDING_VALIDATION EXPIRED 
  --query 'CertificateSummaryList[*].{Domain:DomainName,ARN:CertificateArn,Status:Status}' 
  --output json 
  --region us-east-1

# Belirli bir sertifikanın tüm detayları
aws acm describe-certificate 
  --certificate-arn $CERT_ARN 
  --query 'Certificate.{Domain:DomainName,Status:Status,NotBefore:NotBefore,NotAfter:NotAfter,RenewalStatus:RenewalSummary.RenewalStatus}' 
  --output json

Süresi dolmaya yakın sertifikaları bulmak için bir script yazalım:

#!/bin/bash
# Süresi 30 gün içinde dolacak sertifikaları bul ve bildirim gönder

REGION="us-east-1"
THRESHOLD_DAYS=30
SNS_TOPIC_ARN="arn:aws:sns:us-east-1:123456789012:ssl-alerts"

echo "=== SSL Sertifika Durum Raporu ==="
echo "Tarih: $(date)"
echo ""

EXPIRING_CERTS=""

# Tüm sertifikaları al
CERTS=$(aws acm list-certificates 
  --certificate-statuses ISSUED 
  --query 'CertificateSummaryList[*].CertificateArn' 
  --output text 
  --region $REGION)

for CERT_ARN in $CERTS; do
  CERT_INFO=$(aws acm describe-certificate 
    --certificate-arn $CERT_ARN 
    --query 'Certificate.{Domain:DomainName,NotAfter:NotAfter,RenewalStatus:RenewalSummary.RenewalStatus}' 
    --output json 
    --region $REGION)

  DOMAIN=$(echo $CERT_INFO | jq -r '.Domain')
  NOT_AFTER=$(echo $CERT_INFO | jq -r '.NotAfter')
  RENEWAL_STATUS=$(echo $CERT_INFO | jq -r '.RenewalStatus // "N/A"')

  # Gün hesaplama
  EXPIRY_DATE=$(date -d "$NOT_AFTER" +%s 2>/dev/null || date -j -f "%Y-%m-%dT%H:%M:%S" "$NOT_AFTER" +%s)
  CURRENT_DATE=$(date +%s)
  DAYS_REMAINING=$(( ($EXPIRY_DATE - $CURRENT_DATE) / 86400 ))

  if [ $DAYS_REMAINING -le $THRESHOLD_DAYS ]; then
    echo "UYARI: $DOMAIN - $DAYS_REMAINING gun kaldi (Yenileme: $RENEWAL_STATUS)"
    EXPIRING_CERTS="$EXPIRING_CERTSn$DOMAIN: $DAYS_REMAINING gun kaldi"
  else
    echo "OK: $DOMAIN - $DAYS_REMAINING gun kaldi"
  fi
done

# SNS bildirimi gönder
if [ -n "$EXPIRING_CERTS" ]; then
  aws sns publish 
    --topic-arn $SNS_TOPIC_ARN 
    --subject "UYARI: Surecine yaklasan SSL Sertifikalari" 
    --message "Asagidaki sertifikalar $THRESHOLD_DAYS gun icinde surecek:n$EXPIRING_CERTS" 
    --region $REGION
fi

ALB ile Entegrasyon

ACM sertifikalarının en yaygın kullanım senaryosu Application Load Balancer ile. HTTPS listener oluşturalım:

# Mevcut ALB'ye HTTPS listener ekle
ALB_ARN="arn:aws:elasticloadbalancing:us-east-1:123456789012:loadbalancer/app/benim-alb/1234567890"
TARGET_GROUP_ARN="arn:aws:elasticloadbalancing:us-east-1:123456789012:targetgroup/benim-tg/1234567890"
CERT_ARN="arn:aws:acm:us-east-1:123456789012:certificate/12345678-1234-1234-1234-123456789012"

# HTTPS listener oluştur
aws elbv2 create-listener 
  --load-balancer-arn $ALB_ARN 
  --protocol HTTPS 
  --port 443 
  --certificates CertificateArn=$CERT_ARN 
  --ssl-policy ELBSecurityPolicy-TLS13-1-2-2021-06 
  --default-actions Type=forward,TargetGroupArn=$TARGET_GROUP_ARN

# HTTP'yi HTTPS'e yönlendir
HTTP_LISTENER_ARN="arn:aws:elasticloadbalancing:us-east-1:123456789012:listener/app/benim-alb/1234567890/abcdef123456"

aws elbv2 modify-listener 
  --listener-arn $HTTP_LISTENER_ARN 
  --default-actions Type=redirect,RedirectConfig="{Protocol=HTTPS,Port=443,StatusCode=HTTP_301}"

SSL Policy seçimi kritik bir konu. Eski istemci desteği gerekmiyorsa her zaman en güncel policy’i seç. Önerilen politikalar:

  • ELBSecurityPolicy-TLS13-1-2-2021-06: TLS 1.2 ve 1.3, modern sistemler için ideal
  • ELBSecurityPolicy-TLS13-1-2-Res-2021-06: Daha kısıtlı cipher suite, yüksek güvenlik gereken yerler için
  • ELBSecurityPolicy-2016-08: Eski istemci uyumluluğu gerekiyorsa, ancak TLS 1.0 içerdiği için tercih edilmemeli

CloudFront ile ACM Kullanımı

CloudFront için sertifikanın us-east-1 bölgesinde olması zorunlu. Bu çok önemli, başka bölgede açtığın sertifikayı CloudFront’a atayamazsın.

# CloudFront distribution'a sertifika ata (us-east-1 zorunlu!)
DISTRIBUTION_ID="E1234567890ABC"
CERT_ARN="arn:aws:acm:us-east-1:123456789012:certificate/12345678-1234-1234-1234-123456789012"

# Mevcut distribution konfigürasyonunu al
aws cloudfront get-distribution-config 
  --id $DISTRIBUTION_ID 
  --query 'DistributionConfig' 
  --output json > /tmp/cf-config.json

# ETag'i ayrı al (güncelleme için gerekli)
ETAG=$(aws cloudfront get-distribution-config 
  --id $DISTRIBUTION_ID 
  --query 'ETag' 
  --output text)

# Config'i düzenle ve sertifikayı ekle
# ViewerCertificate bölümünü güncelle:
# "ViewerCertificate": {
#   "ACMCertificateArn": "$CERT_ARN",
#   "SSLSupportMethod": "sni-only",
#   "MinimumProtocolVersion": "TLSv1.2_2021"
# }

# Güncellenmiş config'i uygula
aws cloudfront update-distribution 
  --id $DISTRIBUTION_ID 
  --distribution-config file:///tmp/cf-config.json 
  --if-match $ETAG

Terraform ile ACM Yönetimi

Gerçek üretim ortamlarında manuel CLI komutları yerine IaC kullanmak çok daha mantıklı. Terraform ile ACM yönetimi:

# acm.tf

# ACM Sertifikası
resource "aws_acm_certificate" "main" {
  domain_name               = "ornek.com"
  subject_alternative_names = ["www.ornek.com", "api.ornek.com"]
  validation_method         = "DNS"

  tags = {
    Environment = "production"
    ManagedBy   = "terraform"
  }

  lifecycle {
    create_before_destroy = true
  }
}

# Route 53'te DNS validation kayıtları
resource "aws_route53_record" "cert_validation" {
  for_each = {
    for dvo in aws_acm_certificate.main.domain_validation_options : dvo.domain_name => {
      name   = dvo.resource_record_name
      record = dvo.resource_record_value
      type   = dvo.resource_record_type
    }
  }

  allow_overwrite = true
  name            = each.value.name
  records         = [each.value.record]
  ttl             = 60
  type            = each.value.type
  zone_id         = data.aws_route53_zone.main.zone_id
}

# Sertifika doğrulamasını bekle
resource "aws_acm_certificate_validation" "main" {
  certificate_arn         = aws_acm_certificate.main.arn
  validation_record_fqdns = [for record in aws_route53_record.cert_validation : record.fqdn]
}

# ALB HTTPS Listener
resource "aws_lb_listener" "https" {
  load_balancer_arn = aws_lb.main.arn
  port              = "443"
  protocol          = "HTTPS"
  ssl_policy        = "ELBSecurityPolicy-TLS13-1-2-2021-06"
  certificate_arn   = aws_acm_certificate_validation.main.certificate_arn

  default_action {
    type             = "forward"
    target_group_arn = aws_lb_target_group.main.arn
  }
}

# HTTP'yi HTTPS'e yönlendir
resource "aws_lb_listener" "http_redirect" {
  load_balancer_arn = aws_lb.main.arn
  port              = "80"
  protocol          = "HTTP"

  default_action {
    type = "redirect"
    redirect {
      port        = "443"
      protocol    = "HTTPS"
      status_code = "HTTP_301"
    }
  }
}

# Data source - Route 53 Hosted Zone
data "aws_route53_zone" "main" {
  name         = "ornek.com."
  private_zone = false
}

CloudWatch Alarms ile Sertifika İzleme

ACM otomatik yenileme yapıyor ama bazen aksilikler olabiliyor. Domain’in DNS yapılandırması değişmişse yenileme başarısız olabilir. Bu durumu yakalamak için CloudWatch alarm kur:

# ACM yenileme hatası için CloudWatch alarm
aws cloudwatch put-metric-alarm 
  --alarm-name "ACM-Certificate-Renewal-Failed" 
  --alarm-description "ACM sertifika yenileme basarisiz oldu" 
  --metric-name DaysToExpiry 
  --namespace AWS/CertificateManager 
  --statistic Minimum 
  --period 86400 
  --evaluation-periods 1 
  --threshold 30 
  --comparison-operator LessThanThreshold 
  --treat-missing-data breaching 
  --alarm-actions "arn:aws:sns:us-east-1:123456789012:ssl-alerts" 
  --dimensions Name=CertificateArn,Value=$CERT_ARN 
  --region us-east-1

EventBridge ile ACM olaylarını da yakalayabilirsin:

# ACM olaylarını EventBridge ile yakala
aws events put-rule 
  --name "ACM-Certificate-Events" 
  --event-pattern '{
    "source": ["aws.acm"],
    "detail-type": ["ACM Certificate Approaching Expiry", "ACM Certificate Expired"]
  }' 
  --state ENABLED 
  --region us-east-1

# SNS hedefi ekle
aws events put-targets 
  --rule "ACM-Certificate-Events" 
  --targets '[{
    "Id": "SNS-SSL-Alert",
    "Arn": "arn:aws:sns:us-east-1:123456789012:ssl-alerts"
  }]' 
  --region us-east-1

Sık Karşılaşılan Sorunlar ve Çözümleri

Sertifika PENDING_VALIDATION durumunda takılı kaldı:

DNS doğrulama kaydını doğru ekledin mi kontrol et. CNAME kaydında bazen nokta karakteri sorun çıkarıyor. Bazı DNS provider’lar sonu nokta ile biten değerleri otomatik kırpıyor.

# Doğrulama durumunu kontrol et
aws acm describe-certificate 
  --certificate-arn $CERT_ARN 
  --query 'Certificate.{Status:Status,ValidationOptions:DomainValidationOptions}' 
  --output json

# DNS'i manuel kontrol et
dig CNAME _acme-challenge.ornek.com

Sertifika yenileme başarısız oluyor:

ACM 80 gün kala yenileme sürecini başlatır. Eğer DNS doğrulama kaydı hala geçerliyse otomatik yenilenir. Sorun şurada çıkıyor: DNS sağlayıcısı değişmişse veya CNAME kaydı silinmişse yenileme başarısız olur.

# Yenileme durumunu kontrol et
aws acm describe-certificate 
  --certificate-arn $CERT_ARN 
  --query 'Certificate.RenewalSummary' 
  --output json

# Manuel yenileme tetikle
aws acm renew-certificate 
  --certificate-arn $CERT_ARN 
  --region us-east-1

Farklı region’lar için sertifika kullanımı:

CloudFront us-east-1 zorunluluğu sık karşılaşılan bir sorun. Diğer servisler için sertifika mutlaka aynı region’da olmalı. ap-southeast-1’deki ALB için us-east-1 sertifikası kullanamazsın.

Maliyet Yönetimi

ACM public sertifikaları tamamen ücretsiz. Ancak Private CA kullanıyorsan aylık 400 USD + sertifika başına ücret var. Private CA ihtiyacın yoksa bu masraftan kaçınabilirsin.

Sertifika kullanımını takip etmek için:

# Kullanılmayan sertifikaları bul (herhangi bir servise bağlı olmayan)
aws acm list-certificates 
  --certificate-statuses ISSUED 
  --query 'CertificateSummaryList[*].CertificateArn' 
  --output text 
  --region us-east-1 | tr 't' 'n' | while read CERT_ARN; do
    IN_USE=$(aws acm describe-certificate 
      --certificate-arn $CERT_ARN 
      --query 'Certificate.InUseBy' 
      --output text 
      --region us-east-1)
    
    DOMAIN=$(aws acm describe-certificate 
      --certificate-arn $CERT_ARN 
      --query 'Certificate.DomainName' 
      --output text 
      --region us-east-1)
    
    if [ -z "$IN_USE" ] || [ "$IN_USE" == "None" ]; then
      echo "Kullanilmiyor: $DOMAIN ($CERT_ARN)"
    fi
done

Sonuç

ACM, SSL sertifika yönetiminin en can sıkıcı kısımlarını ortadan kaldırıyor. Sertifika takibini, zamanında yenilemeyi, kompleks kurulum süreçlerini AWS’e bırakıp asıl işine odaklanabiliyorsun.

Özetlemek gerekirse:

  • Doğrulama yöntemi olarak DNS’i tercih et, özellikle wildcard sertifikalar için zorunlu
  • Route 53 kullanıyorsan otomasyonu tam kur, manuel müdahale ihtiyacı kalmasın
  • CloudFront için us-east-1 bölgesini unutma, bu hatayı bir kez yaşayan unutmuyor
  • CloudWatch alarmlarını ve EventBridge kurallarını mutlaka ekle, otomatik yenileme güvenilir ama %100 değil
  • Terraform veya CloudFormation kullan, production ortamında manuel sertifika yönetimi tehlikeli
  • Kullanılmayan sertifikaları temizle, karmaşayı önler ve private CA kullanıyorsan maliyeti düşürür

ACM’i düzgün kurduğunda SSL sertifikası nedeniyle production’da patlak yaşama ihtimalin minimuma iniyor. O 3’te gelen “site çöktü” telefonu artık tarihe karışabilir.

Bir yanıt yazın

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