API Anahtarı Nedir: Güvenli Saklama ve Kullanım Rehberi

Bir sabah işe geldiğinizde production ortamınızdaki API anahtarının GitHub’a sızdığını öğrenseniz ne hissedersiniz? Bu senaryo, her yıl binlerce geliştiriciyi ve sistem yöneticisini etkileyen gerçek bir kabus. Stripe, AWS, SendGrid… hangi servis olursa olsun, bir API anahtarının yanlış ellere geçmesi maddi kayıptan itibar kaybına kadar ciddi sonuçlar doğurabilir. Bu yazıda API anahtarlarının ne olduğunu, neden bu kadar kritik olduklarını ve en önemlisi bunları nasıl güvenli saklayıp kullanacağınızı somut örneklerle ele alacağız.

API Anahtarı Nedir ve Neden Önemlidir

API anahtarı, bir uygulamanın başka bir servise kendini tanıtmak için kullandığı benzersiz bir kimlik dizisidir. Bunu bir kapı kartına benzetebilirsiniz: Binaya girmek için kartı okutursunuz, sistem sizi tanır ve yetkinize göre erişim sağlar.

Teknik olarak bakıldığında API anahtarları genellikle şu amaçlarla kullanılır:

  • Kimlik doğrulama: Çağrıyı kimin yaptığını belirlemek
  • Yetkilendirme: Bu kimliğin nelere erişebileceğini kontrol etmek
  • Rate limiting: Belirli bir sürede kaç istek yapılabileceğini sınırlamak
  • Fatura takibi: Kullanım bazlı faturalandırma için izleme

Bir API anahtarı genellikle şöyle görünür:

# Stripe API anahtarı örneği (format)
sk_live_4eC39HqLyjWDarjtT7vr56GM

# AWS Access Key ID örneği (format)
AKIAIOSFODNN7EXAMPLE

# SendGrid API anahtarı örneği (format)
SG.xxxxxxxxxxxxxxxxxxxxxx.xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx

Bu diziler rastgele görünse de her servisin kendine özgü bir format standardı vardır. Bu durum hem uygulamalar için kolaylık sağlar hem de güvenlik araçlarının anahtarları tespit etmesini mümkün kılar.

Neden Bu Kadar Tehlikeli

2022 yılında yapılan bir araştırmaya göre GitHub’a her gün yaklaşık 5000 adet API anahtarı ve credential sızıyor. Bu rakam düşündürücü, çünkü birçok geliştirici yanlışlıkla şu hataları yapıyor:

  • Anahtarları doğrudan kaynak koduna gömiyor
  • .env dosyalarını .gitignore‘a eklemeyi unutuyor
  • Log dosyalarına anahtarları yazdırıyor
  • Ekip içinde anahtarları düz metin olarak paylaşıyor

Bir AWS anahtarı sızdığında, saldırganlar dakikalar içinde binlerce EC2 instance açıp kripto madenciliği yapabilir. Bunun faturası size gönderilir. AWS bazı durumlarda anlayış gösterse de bu garanti değil.

Güvenli API Anahtarı Saklama Yöntemleri

1. Environment Variables Kullanımı

En temel ama etkili yöntem, API anahtarlarını environment variable olarak saklamaktır. Kod içine gömmek yerine işletim sistemi seviyesinde tanımlarsınız.

# Linux/macOS üzerinde geçici olarak tanımlama (oturum süresince geçerli)
export STRIPE_API_KEY="sk_live_xxxxxxxxxxxx"
export SENDGRID_API_KEY="SG.xxxxxxxxxxxx"

# Kalıcı olarak ~/.bashrc veya ~/.bash_profile dosyasına ekleme
echo 'export STRIPE_API_KEY="sk_live_xxxxxxxxxxxx"' >> ~/.bashrc
source ~/.bashrc

# Değeri kontrol etme (dikkatli olun, log'lara düşmesin)
echo $STRIPE_API_KEY

Production ortamlarında bu değerleri systemd servis dosyası üzerinden de yönetebilirsiniz:

# /etc/systemd/system/myapp.service dosyası
[Unit]
Description=My Application
After=network.target

[Service]
Type=simple
User=appuser
WorkingDirectory=/opt/myapp
# Environment dosyasından değerleri yükle
EnvironmentFile=/etc/myapp/secrets.env
ExecStart=/usr/bin/python3 app.py
Restart=always

[Install]
WantedBy=multi-user.target
# /etc/myapp/secrets.env dosyası oluşturma ve izinleri ayarlama
sudo mkdir -p /etc/myapp
sudo touch /etc/myapp/secrets.env

# Anahtarları dosyaya yaz
sudo bash -c 'cat > /etc/myapp/secrets.env << EOF
STRIPE_API_KEY=sk_live_xxxxxxxxxxxx
DATABASE_URL=postgresql://user:pass@localhost/mydb
SENDGRID_API_KEY=SG.xxxxxxxxxxxx
EOF'

# Güvenlik için sadece root okuyabilsin
sudo chmod 600 /etc/myapp/secrets.env
sudo chown root:root /etc/myapp/secrets.env

2. HashiCorp Vault Kullanımı

Kurumsal ortamlarda HashiCorp Vault, secret yönetimi için altın standarttır. Anahtarları şifreli saklar, erişim loglar ve rotasyonu otomatikleştirir.

# Vault CLI ile secret okuma örneği
# Önce Vault'a login olun
vault login -method=ldap username=sysadmin

# Secret yazma
vault kv put secret/myapp/production 
  stripe_key="sk_live_xxxxxxxxxxxx" 
  sendgrid_key="SG.xxxxxxxxxxxx"

# Secret okuma
vault kv get secret/myapp/production

# Belirli bir alanı okuma ve environment variable'a atama
export STRIPE_API_KEY=$(vault kv get -field=stripe_key secret/myapp/production)

# TTL ile dinamik secret oluşturma (AWS için)
vault read aws/creds/my-role
# Bu komut geçici AWS credentials üretir, TTL sonunda otomatik iptal olur

Vault’un gerçek gücü dinamik secret’larda ortaya çıkar. Database credentials veya AWS IAM anahtarları için TTL tanımlarsınız, Vault bunları otomatik oluşturur ve süresi dolunca iptal eder. Bu sayede uzun ömürlü statik anahtarlar yerine kısa ömürlü, otomatik dönen kimlik bilgileri kullanırsınız.

3. .env Dosyaları ve .gitignore

Küçük ve orta ölçekli projelerde .env dosyası yaygın kullanılan çözümdür. Burada dikkat edilmesi gereken kritik nokta .gitignore yapılandırmasıdır.

# .env dosyası oluşturma
cat > .env << 'EOF'
# Production API Anahtarları
STRIPE_API_KEY=sk_live_xxxxxxxxxxxx
SENDGRID_API_KEY=SG.xxxxxxxxxxxx
AWS_ACCESS_KEY_ID=AKIAIOSFODNN7EXAMPLE
AWS_SECRET_ACCESS_KEY=wJalrXUtnFEMI/K7MDENG/bPxRfiCYEXAMPLEKEY

# Database
DATABASE_URL=postgresql://user:[email protected]:5432/production
EOF

# .gitignore dosyasına ekleme (MUTLAKA yapılmalı)
echo ".env" >> .gitignore
echo ".env.local" >> .gitignore
echo ".env.production" >> .gitignore
echo "*.env" >> .gitignore

# .env.example dosyası oluştur (değerler olmadan, yapıyı göstermek için)
cat > .env.example << 'EOF'
STRIPE_API_KEY=your_stripe_key_here
SENDGRID_API_KEY=your_sendgrid_key_here
AWS_ACCESS_KEY_ID=your_aws_key_id
AWS_SECRET_ACCESS_KEY=your_aws_secret_key
DATABASE_URL=postgresql://user:password@host:5432/dbname
EOF

# Bu dosyayı git'e ekleyebilirsiniz, güvenli
git add .env.example
git commit -m "Add .env.example template"

4. AWS Secrets Manager

AWS ekosistemindeyseniz Secrets Manager ve Parameter Store güçlü alternatiflerdır.

# AWS CLI ile secret oluşturma
aws secretsmanager create-secret 
  --name "production/myapp/stripe" 
  --description "Stripe API key for production" 
  --secret-string '{"api_key":"sk_live_xxxxxxxxxxxx"}'

# Secret okuma
aws secretsmanager get-secret-value 
  --secret-id "production/myapp/stripe" 
  --query SecretString 
  --output text

# Shell script içinde kullanım örneği
#!/bin/bash
STRIPE_KEY=$(aws secretsmanager get-secret-value 
  --secret-id "production/myapp/stripe" 
  --query 'SecretString' 
  --output text | python3 -c "import sys,json; print(json.load(sys.stdin)['api_key'])")

export STRIPE_API_KEY="$STRIPE_KEY"
echo "Uygulama başlatılıyor..."
python3 /opt/myapp/app.py

AWS Parameter Store ise daha basit konfigürasyon değerleri için tercih edilir:

# SecureString tipiyle şifreli saklama
aws ssm put-parameter 
  --name "/production/myapp/sendgrid-key" 
  --value "SG.xxxxxxxxxxxx" 
  --type SecureString 
  --key-id alias/aws/ssm

# Değeri okuma (otomatik decrypt)
aws ssm get-parameter 
  --name "/production/myapp/sendgrid-key" 
  --with-decryption 
  --query Parameter.Value 
  --output text

Git History Temizliği: İş İşten Geçmeden

Bir API anahtarını yanlışlıkla commit ettiyseniz sadece dosyayı silmek yetmez. Git history’de hala görünür. Bu durumda yapmanız gerekenler:

# BFG Repo Cleaner ile geçmişten temizleme
# Önce BFG'yi indirin: https://rtyley.github.io/bfg-repo-cleaner/

# Temizlenecek string'leri bir dosyaya yaz
echo "sk_live_xxxxxxxxxxxx" > secrets-to-remove.txt
echo "SG.xxxxxxxxxxxx" >> secrets-to-remove.txt

# BFG ile git geçmişini temizle
java -jar bfg.jar --replace-text secrets-to-remove.txt myrepo.git

# Ardından force push yap
cd myrepo.git
git reflog expire --expire=now --all
git gc --prune=now --aggressive
git push --force

# VEYA git-filter-branch kullanımı (eski yöntem, BFG önerilir)
git filter-branch --force --index-filter 
  'git rm --cached --ignore-unmatch config/secrets.yml' 
  --prune-empty --tag-name-filter cat -- --all

Önemli uyarı: Git geçmişini temizlese bile anahtarı hemen iptal etmeli ve yenisini oluşturmalısınız. Geçmişten silmek, o zamana kadar görmüş olabilecekleri engellemez.

API Anahtarlarını Kod İçinde Güvenli Kullanmak

Anahtarları doğru sakladıktan sonra, kod içinde de dikkatli olmalısınız.

# Bash script örneği: Anahtarı güvenli kullanma
#!/bin/bash

# Environment variable'dan oku, yoksa hata ver
if [ -z "$STRIPE_API_KEY" ]; then
  echo "HATA: STRIPE_API_KEY environment variable tanımlı değil!" >&2
  exit 1
fi

# API çağrısı yap - anahtarı header'da gönder
RESPONSE=$(curl -s -X POST https://api.stripe.com/v1/charges 
  -H "Authorization: Bearer $STRIPE_API_KEY" 
  -H "Content-Type: application/x-www-form-urlencoded" 
  -d "amount=2000&currency=usd&source=tok_visa" 
  --write-out "n%{http_code}")

HTTP_CODE=$(echo "$RESPONSE" | tail -1)
BODY=$(echo "$RESPONSE" | head -1)

if [ "$HTTP_CODE" -eq 200 ]; then
  echo "Ödeme başarılı"
else
  echo "Hata: HTTP $HTTP_CODE" >&2
  # BODY'yi loglama! İçinde hassas veri olabilir
  # echo "$BODY" >> /var/log/myapp.log  <-- YANLIS
  echo "Ödeme işlemi başarısız, detaylar için uygulama loglarını kontrol edin" >> /var/log/myapp.log
fi

Log yönetimi konusunda ekstra dikkatli olun. API yanıtları zaman zaman hassas bilgiler içerir ve bunların log dosyalarına düşmesi bir başka güvenlik açığı oluşturur.

Rotasyon Stratejisi: Anahtarları Periyodik Yenileme

API anahtarları sonsuza kadar kullanılmamalıdır. Düzenli rotasyon, bir anahtarın ele geçirilmesi durumunda hasar süresini sınırlar.

#!/bin/bash
# api-key-rotation.sh: Basit bir anahtar rotasyon scripti

LOG_FILE="/var/log/api-key-rotation.log"
DATE=$(date '+%Y-%m-%d %H:%M:%S')

echo "[$DATE] Anahtar rotasyonu başlıyor..." >> $LOG_FILE

# 1. Yeni anahtarı API üzerinden oluştur (servis bazlı değişir)
# Bu örnekte SendGrid API kullanıyoruz
NEW_KEY=$(curl -s -X POST "https://api.sendgrid.com/v3/api_keys" 
  -H "Authorization: Bearer $SENDGRID_ADMIN_KEY" 
  -H "Content-Type: application/json" 
  -d '{"name":"production-key-'$(date +%Y%m%d)'","scopes":["mail.send"]}' 
  | python3 -c "import sys,json; print(json.load(sys.stdin)['api_key'])")

if [ -z "$NEW_KEY" ]; then
  echo "[$DATE] HATA: Yeni anahtar oluşturulamadı!" >> $LOG_FILE
  exit 1
fi

# 2. Yeni anahtarı Secrets Manager'a kaydet
aws secretsmanager put-secret-value 
  --secret-id "production/myapp/sendgrid" 
  --secret-string "{"api_key":"$NEW_KEY"}"

# 3. Uygulamayı restart et (yeni anahtarı yüklemesi için)
systemctl restart myapp

echo "[$DATE] Anahtar rotasyonu tamamlandı" >> $LOG_FILE

# 4. Bildirim gönder
echo "API anahtarı başarıyla rotasyona alındı: $(date)" | 
  mail -s "API Key Rotation Completed" [email protected]

Kubernetes Ortamında Secret Yönetimi

Kubernetes kullananlar için native Secret objesi temel çözümdür, ancak bunu Sealed Secrets veya External Secrets Operator ile güçlendirmenizi öneririm.

# Kubernetes Secret oluşturma
kubectl create secret generic myapp-api-keys 
  --from-literal=stripe-key="sk_live_xxxxxxxxxxxx" 
  --from-literal=sendgrid-key="SG.xxxxxxxxxxxx" 
  --namespace production

# Secret'ı kontrol et (değerler base64 encode görünür)
kubectl get secret myapp-api-keys -n production -o yaml

# Belirli bir değeri decode et
kubectl get secret myapp-api-keys -n production 
  -o jsonpath='{.data.stripe-key}' | base64 --decode

# Deployment YAML içinde kullanım
cat << 'EOF'
apiVersion: apps/v1
kind: Deployment
metadata:
  name: myapp
spec:
  template:
    spec:
      containers:
      - name: myapp
        image: myapp:latest
        env:
        - name: STRIPE_API_KEY
          valueFrom:
            secretKeyRef:
              name: myapp-api-keys
              key: stripe-key
        - name: SENDGRID_API_KEY
          valueFrom:
            secretKeyRef:
              name: myapp-api-keys
              key: sendgrid-key
EOF

Önemli not: Kubernetes Secret’ları varsayılan olarak sadece base64 encode’dur, şifreli değildir. etcd encryption at rest aktif etmek veya External Secrets Operator ile Vault/AWS Secrets Manager entegrasyonu yapmak production için şiddetle önerilir.

Sızdırma Tespiti: Git Pre-commit Hook

Commit öncesinde anahtarların koda girip girmediğini kontrol eden bir hook kurabilirsiniz:

# .git/hooks/pre-commit dosyası oluştur
cat > .git/hooks/pre-commit << 'EOF'
#!/bin/bash

# API anahtarı pattern'larını tara
PATTERNS=(
  "sk_live_[0-9a-zA-Z]{24}"
  "sk_test_[0-9a-zA-Z]{24}"
  "SG.[0-9a-zA-Z_-]{22}.[0-9a-zA-Z_-]{43}"
  "AKIA[0-9A-Z]{16}"
  "AIza[0-9A-Za-z\-_]{35}"
  "-----BEGIN (RSA|EC|DSA) PRIVATE KEY-----"
)

FOUND=0

for PATTERN in "${PATTERNS[@]}"; do
  MATCHES=$(git diff --cached --diff-filter=A -U0 | grep -E "$PATTERN")
  if [ ! -z "$MATCHES" ]; then
    echo "HATA: Potansiyel API anahtarı tespit edildi!"
    echo "Pattern: $PATTERN"
    echo "Commit iptal edildi. Lütfen hassas verileri kaldırın."
    FOUND=1
  fi
done

if [ $FOUND -eq 1 ]; then
  exit 1
fi

exit 0
EOF

# Hook'u çalıştırılabilir yap
chmod +x .git/hooks/pre-commit

Alternatif olarak gitleaks veya detect-secrets gibi araçları CI/CD pipeline’ınıza entegre edebilirsiniz. Bu araçlar çok daha kapsamlı pattern kütüphanelerine sahiptir.

En İyi Pratikler Özeti

Şimdiye kadar anlattıklarımızı somut kurallar olarak sıralayalım:

  • En az yetki prensibi: Her API anahtarına sadece ihtiyaç duyduğu izinleri verin. Mail göndermek için kullanacağınız anahtar veritabanı okuma yetkisine sahip olmamalı.
  • Ortam ayrımı: Development, staging ve production için ayrı anahtarlar kullanın. Test anahtarını production’da kullananlar bu hatayı bir kez yapar.
  • Rotasyon planı: Kritik anahtarları en az 90 günde bir, mümkünse daha sık yenileyin.
  • Merkezi yönetim: Anahtarları ayrı ayrı yönetmek yerine Vault, AWS Secrets Manager veya benzeri bir araç kullanın.
  • Erişim loglama: Kim, ne zaman, hangi anahtarla ne yaptı? Bu soruların cevabı bir güvenlik olayında son derece değerlidir.
  • Anlık iptal mekanizması: Bir anahtar sızdığında onu hemen iptal edebilecek süreçler oluşturun.
  • Asla log’a yazmayın: API anahtarlarını ve yanıtlarını ham haliyle log dosyalarına yazmayın.
  • CI/CD değişkenleri: Pipeline secret’ları için GitHub Actions Secrets, GitLab CI Variables veya Jenkins Credentials Store kullanın, YAML dosyasına gömmeyin.

Gerçek Dünya Senaryosu: Sızıntı Anında Ne Yapmalı

Bir API anahtarının sızdığını öğrendiğinizde paniğe kapılmak yerine şu adımları hızla uygulayın:

  • Hemen iptal edin: İlgili servisin dashboard’una girin ve anahtarı devre dışı bırakın. Bu ilk 5 dakika içinde olmalı.
  • Hasarı değerlendirin: Servisin kullanım loglarını inceleyin, yetkisiz işlem var mı?
  • Yeni anahtar oluşturun: İptal ettiğinizin yerine yeni bir anahtar oluşturup servislere dağıtın.
  • Geçmişi temizleyin: Eğer Git’e commit edildiyse BFG veya filter-branch ile temizleyin.
  • Kök nedeni bulun: Nasıl sızdı? Kod mı, log mu, Slack mesajı mı?
  • Bildirin: GDPR veya benzer düzenlemeler kapsamındaysanız ilgili bildirimleri yapın.
  • Postmortem yazın: Aynı hatanın tekrar yaşanmaması için süreci belgeleyin.

Sonuç

API anahtarı güvenliği, “bir kez kurup unutulacak” bir şey değil, sürekli dikkat gerektiren bir disiplindir. Environment variable’lardan Vault’a, basit .gitignore kurallarından Kubernetes Sealed Secrets’a kadar her yöntemin kendi kullanım senaryosu var. Önemli olan, ekibinizin büyüklüğüne ve altyapınızın karmaşıklığına uygun bir çözüm seçip bunu tutarlı biçimde uygulamak.

Küçük bir startup için .env dosyaları ve AWS Parameter Store yeterli olabilirken, büyük bir kurumsal yapıda HashiCorp Vault ve kapsamlı audit loglama kaçınılmaz hale gelir. Nerede olursanız olun, pre-commit hook kurmak ve ekibi bilinçlendirmek sıfır maliyetle uygulayabileceğiniz iki temel adımdır.

Anahtarlarınızı güvende tutun, rotasyon planınızı bugün yapın ve “sızdı, ne yapacağım” sorusunun cevabını iş başında öğrenmek yerine önceden hazırlayın.

Bir yanıt yazın

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