Bir uygulamanın çalışabilmesi için veritabanı parolasına, ödeme sağlayıcısının API anahtarına, e-posta gönderim servisinin token'ına ve TLS sertifikasının özel anahtarına ihtiyacı vardır. Bu değerlerin ortak özelliği, ele geçirildiklerinde saldırganın doğrudan sisteminize, verilerinize veya paranıza erişebilmesidir. İşte bu tür değerlere "secret" yani gizli anahtar diyoruz ve bunların nasıl saklandığı, dağıtıldığı ve döndürüldüğü konusuna da secrets yönetimi adı veriliyor.
Yıllardır süren güvenlik ihlali raporlarına baktığınızda tekrar eden bir tablo görürsünüz: en pahalı sızıntıların önemli bir kısmı sofistike bir sıfır-gün açığından değil, halka açık bir git deposuna yanlışlıkla itilmiş bir API anahtarından, log dosyasına düşmüş bir paroladan ya da yıllardır hiç değiştirilmemiş bir kök parolasından kaynaklanır. Bu rehberde sırların neden ve nasıl sızdığını, .env dosyalarından bulut secrets servislerine kadar seçenekleri, rotasyon prensiplerini ve en kritik senaryoyu, yani zaten sızmış bir sırrı nasıl iptal edip git geçmişinden temizleyeceğinizi kıdemli bir sistem yöneticisi gözüyle ele alıyoruz.
Secret Nedir, Yapılandırmadan Farkı Ne?#
Her yapılandırma değeri bir sır değildir. Uygulamanızın hangi portta dinleyeceği, önbellek süresinin kaç saniye olduğu ya da hangi zaman diliminde çalıştığı gibi bilgiler kamuya açık olsa bir zarar doğurmaz; bunlar sıradan yapılandırmadır. Bir değerin sır olup olmadığını ayırt etmenin pratik testi şudur: "Bu değeri bir yabancı görürse doğrudan bir zarar verebilir mi?" Cevap evet ise o bir secrettir ve farklı bir muameleyi hak eder.
Tipik sır kategorileri şunlardır: veritabanı ve mesaj kuyruğu kimlik bilgileri, üçüncü taraf API anahtarları (ödeme, SMS, e-posta, harita), OAuth istemci gizli anahtarları, JWT imzalama anahtarları, TLS özel anahtarları, SSH özel anahtarları ve şifreleme anahtarları. Bu değerlerin ortak paydası, uygulama tarafından okunabilir olmaları ama insan gözünden ve versiyon kontrolünden gizli tutulmaları gerektiğidir.
| Değer türü | Örnek | Sır mı? | Nerede saklanmalı |
|---|---|---|---|
| Uygulama ayarı | APP_PORT=8080 | Hayır | Kod/repo (sorun değil) |
| Özellik bayrağı | FEATURE_X=true | Hayır | Kod/repo veya config servisi |
| DB parolası | DB_PASS=... | Evet | Secrets yöneticisi / .env |
| API anahtarı | STRIPE_KEY=sk_live_... | Evet | Secrets yöneticisi |
| TLS özel anahtarı | server.key | Evet | Sunucu diski (0600) / vault |
| JWT imza anahtarı | JWT_SECRET=... | Evet | Secrets yöneticisi / env |
Bu ayrımı erken yapmak önemlidir, çünkü sır olmayan onlarca değerin arasına karışan tek bir gerçek sır çoğu zaman gözden kaçar ve kod incelemesinde fark edilmeden depoya girer.
Sırlar Neden Koda ve Git Geçmişine Sızıyor?#
Sır sızıntısının en yaygın sebebi kötü niyet değil, kolaylıktır. Geliştirici bir özelliği hızla çalıştırmak ister, anahtarı doğrudan koda yapıştırır, "sonra düzeltirim" der ve o satır bir commit ile geçmişe kazınır. Sorun şudur: git kaldırdığınız bir dosyayı silmez, yeni bir commit ekler; sır artık geçmişte, git log -p ile herkesin erişebileceği bir yerde yaşamaya devam eder. Depoyu daha sonra public yaparsanız veya birisi klonunu alırsa, anahtar da onunla gider.
Aşağıda gerçek hayatta en sık gördüğümüz sızma yollarını bir arada topladık:
# 1) Koda gömülü anahtar — en klasik hata
const stripe = new Stripe("sk_live_51H...gizli...");
# 2) Yanlışlıkla commit'lenen .env
git add . # .env dahil her şey eklendi
git commit -m "wip" # sır artık geçmişte
# 3) Örnek dosyada gerçek değer
# .env.example dosyasına placeholder yerine canlı anahtar yazmak
# 4) Log ve hata izlerine düşen sırlar
console.log("Bağlanılıyor:", process.env.DATABASE_URL);
# 5) Docker imajına ADD/COPY ile giren .env
# imaj katmanları da tıpkı git gibi geçmişi tutar
Bu sızıntıların büyük kısmı basit bir .gitignore disiplini ve otomatik tarama ile önlenebilir. Deponuza ekleyeceğiniz temel bir .gitignore:
# Sırlar asla versiyon kontrolüne girmesin
.env
.env.*
!.env.example
*.pem
*.key
id_rsa
*.p12
credentials.json
Bunun üzerine bir de commit öncesi tarama koyun. gitleaks gibi bir araç, bilinen anahtar desenlerini yakalayıp sızmadan önce commit'i durdurabilir:
# Depoyu tara — hem çalışma dizini hem tüm git geçmişi
gitleaks detect --source . --verbose
# Pre-commit hook olarak: sır içeren commit'i engelle
gitleaks protect --staged --verbose
Bunu bir pre-commit hook veya CI aşaması olarak zorunlu kılarsanız, "insan hatası" faktörünü büyük ölçüde ortadan kaldırırsınız. Otomatik tarama insan disiplininden her zaman daha güvenilirdir.
.env Dosyası ve Ortam Değişkenleri#
En yaygın ve en düşük eşikli yaklaşım, sırları koddan ayırıp bir .env dosyasına ve oradan da ortam değişkenlerine (environment variables) taşımaktır. Fikir basittir: kod, değerin kendisini değil yalnızca ismini bilir; gerçek değer çalışma zamanında ortamdan okunur. Böylece aynı kod, farklı ortamlarda (geliştirme, hazırlık, canlı) farklı sırlarla çalışabilir.
Tipik bir .env dosyası ve onun repoya giren zararsız ikizi .env.example:
# .env (ASLA commit'lenmez)
DATABASE_URL=postgres://app:[email protected]:5432/prod
STRIPE_SECRET_KEY=sk_live_51H0aBcD...
JWT_SECRET=8f3c1d9a72b04e6f...
SMTP_PASSWORD=r0tate-me-often
# .env.example (commit'lenir — sadece anahtar isimleri, değer YOK)
DATABASE_URL=
STRIPE_SECRET_KEY=
JWT_SECRET=
SMTP_PASSWORD=
.env yaklaşımı küçük ve orta ölçekli projeler için fazlasıyla yeterlidir, ancak sınırlarını bilmek gerekir. Dosya diskte düz metin durur; sunucuya erişebilen herkes okuyabilir. Bu yüzden dosya izinlerini daraltın ve dosyayı uygulamayı çalıştıran kullanıcıya kilitleyin:
# Sadece sahibi okuyup yazabilsin
chmod 600 /var/www/app/.env
chown appuser:appuser /var/www/app/.env
# Web sunucusunun .env'i asla servis etmediğinden emin olun (Nginx)
# Nginx: gizli dosyaların doğrudan indirilmesini engelle
location ~ /\.(env|git|ht) {
deny all;
return 404;
}
Bu Nginx bloğu kritik önemdedir. Uygulama kök dizininiz web köküyle aynıysa, tarayıcıdan siteadi.com/.env istendiğinde sunucunun bu dosyayı düz metin olarak servis etmesi felakettir ve maalesef çok yaygındır. Statik barındırmada bir dosyayı diske koyduysanız, aksini yapılandırmadıysanız o dosya indirilebilir varsayın. Paylaşımlı web hosting veya WordPress hosting ortamlarında çalışıyorsanız, sır içeren dosyaları web kökünün bir seviye dışına almak en temiz çözümdür.
Gizli Yönetim Araçları: Vault ve Bulut Secrets#
.env dosyaları ölçek büyüdükçe yetersiz kalır. On sunucuya aynı anahtarı dağıtmak, bir anahtarı değiştirdiğinizde her makineye tek tek gitmek, kimin hangi sırra ne zaman eriştiğini bilmemek ciddi bir yönetim yüküne dönüşür. Bu noktada devreye özel secrets yönetim araçları girer. Bunlar sırları merkezi, şifreli bir depoda tutar; uygulamalara kimlik doğrulama sonrası, denetim kaydı bırakarak ve genellikle kısa ömürlü olarak dağıtır.
En bilinen açık kaynak çözüm HashiCorp Vault'tur. Vault'ta sırlar hiçbir zaman düz metin diskte durmaz; ana anahtarla şifrelenir, erişim politikalarla sınırlanır ve her okuma denetim günlüğüne yazılır. Basit bir kullanım şöyle görünür:
# Bir sırrı yaz (KV motoru)
vault kv put secret/prod/db password="S3cr3t!" username="app"
# Uygulama, kimlik doğrulama token'ı ile sadece okur
vault kv get -field=password secret/prod/db
# Dinamik sır: Vault, DB kullanıcısını anında üretip 1 saat sonra siler
vault read database/creds/readonly
Son satır Vault'un en güçlü özelliğidir: statik parola yerine, uygulama her ihtiyaç duyduğunda saniyeler içinde geçerli, kısa ömürlü bir kimlik bilgisi üretilir ve süresi dolunca otomatik iptal edilir. Böylece sızan bir kimlik bilgisinin ömrü zaten dakikalarla sınırlıdır. Kendi VDS ya da sanal sunucunuzda Vault'u kendiniz çalıştırabilir, yönetim yükünü almak istemiyorsanız sunucu yönetim hizmetimizden destek alabilirsiniz.
Bulut sağlayıcılarının yönetilen eşdeğerleri de vardır: AWS Secrets Manager, Google Secret Manager, Azure Key Vault. Bunlar altyapıyı sizin yönetmenizi gerektirmez ama sağlayıcıya bağımlılık ve maliyet getirir. Seçenekleri kısaca karşılaştıralım:
| Yaklaşım | Güçlü yönü | Zayıf yönü | Kime uygun |
|---|---|---|---|
.env dosyası | Kurulumu sıfır, herkes bilir | Düz metin, rotasyon manuel | Küçük proje, tek sunucu |
| HashiCorp Vault | Dinamik sır, denetim, rotasyon | Kurulum ve işletim yükü | Orta/büyük, çok sunucu |
| Bulut Secrets Manager | Yönetilen, IAM entegre | Sağlayıcı kilidi, maliyet | Bulutta çalışan ekipler |
| Kişisel parola kasası | Ekip parolaları için ideal | Uygulama sırrı için değil | İnsan sırları (kod değil) |
Son satırdaki ayrım önemlidir: uygulamaların okuduğu sırlarla, insanların kullandığı parolalar farklı araçlar ister. Ekip içi parola paylaşımı, Wi-Fi anahtarları ve yönetici hesapları için kendi kendine barındırdığınız bir kasa çok daha uygundur; bu konuyu Vaultwarden nedir yazımızda ayrıntısıyla ele aldık.
Rotasyon ve En Az Yetki Prensibi#
Bir sırrı iyi saklamak yeterli değildir; onu düzenli olarak değiştirmeniz de gerekir. Rotasyon, bir anahtarın ele geçirilmiş olabileceği varsayımıyla belirli aralıklarla yenisiyle değiştirilmesidir. Mantık şudur: sızdığını fark etmeseniz bile, her rotasyon eski anahtarı işe yaramaz hale getirir ve saldırganın penceresini daraltır. Yüksek riskli sırları (ödeme, kök erişim) 30-90 günde bir, orta riskli olanları ise en az yılda bir döndürmek makul bir başlangıçtır.
Rotasyonun acı verici olmaması için "sıfır kesinti" yaklaşımı benimsenir: yeni anahtarı üretip her iki anahtarı da bir süre geçerli tutar, uygulamaları yeni anahtara geçirir, ardından eskisini iptal edersiniz. Örnek bir akış:
# 1) Yeni anahtar üret, ikisini de geçerli tut
aws secretsmanager rotate-secret --secret-id prod/stripe
# 2) Uygulamalar yeni sürümü okumaya başlasın (deploy)
# 3) Eski anahtarı sağlayıcının panelinden iptal et
# 4) Doğrula: eski anahtarla yapılan istek 401 dönmeli
curl -s -o /dev/null -w "%{http_code}" \
https://api.saglayici.com/v1/ping -H "Authorization: Bearer $OLD_KEY"
# Beklenen: 401
Rotasyonun ikizi en az yetki (least privilege) prensibidir. Her sır yalnızca yapması gereken işi yapabilecek kadar yetkiye sahip olmalıdır. Salt-okuma yeten bir raporlama servisine yazma yetkisi vermeyin; tek bir tabloya erişmesi yeten bir servise tüm veritabanını açmayın. Böylece bir anahtar sızsa bile hasarın yüzeyi dar kalır. PostgreSQL'de bunu şöyle uygularsınız:
-- Raporlama servisi için yalnızca okuma yetkisi
CREATE ROLE report_ro LOGIN PASSWORD 'rotate-me';
GRANT CONNECT ON DATABASE prod TO report_ro;
GRANT USAGE ON SCHEMA public TO report_ro;
GRANT SELECT ON ALL TABLES IN SCHEMA public TO report_ro;
-- Yazma, silme, DDL yetkisi bilinçli olarak verilmedi
Bu iki prensip birlikte çalışır: az yetkili anahtarlar hasarı sınırlar, düzenli rotasyon ise hasarın süresini kısaltır. İkisi bir araya geldiğinde, tek bir sızıntının şirketi yıkmasını engelleyen bir güvenlik ağı oluşur.
Sızmış Bir Sırrı İptal Etme ve Git Geçmişini Temizleme#
Bir anahtarın halka açık bir depoya, log'a veya yanlış bir kişiye gittiğini fark ettiğinizde yapılacak ilk şey, git geçmişini temizlemek değildir. Kritik sıra şudur ve karıştırmak pahalıya patlar: önce sırrı iptal edin, sonra geçmişi temizleyin. Bir anahtar bir kez internete düştüyse, saniyeler içinde otomatik tarayıcı botları tarafından toplanmış olabilir; onu değiştirmeden geçmişi ne kadar temizlerseniz temizleyin, sızmış değer hâlâ geçerli olduğu sürece risk sürer.
Doğru olay müdahale sırası şöyledir:
1. İPTAL ET → Sağlayıcı panelinden anahtarı hemen devre dışı bırak,
yenisini üret (revoke + rotate). Bu, en acil adımdır.
2. DEĞERLENDİR → Log'lara bak: anahtar ne zaman sızdı, kullanıldı mı,
anormal erişim var mı? Gerekirse ilgili hesapları da döndür.
3. TEMİZLE → Sırrı git geçmişinden ve yedeklerden kaldır.
4. ÖNLE → gitleaks/pre-commit tarama ekle ki tekrarlamasın.
İptal ettikten sonra sırayı geçmiş temizliğine getirebilirsiniz. Not: git rm ve yeni bir commit yeterli değildir, çünkü sır eski commit'lerde kalır. Geçmişi baştan yazmanız gerekir. Modern ve önerilen araç git filter-repo'dur:
# Belirli bir dosyayı TÜM geçmişten kaldır
git filter-repo --path .env --invert-paths
# Ya da bir metin desenini geçmişteki tüm dosyalarda maskele
echo 'sk_live_51H0aBcD==>***REMOVED***' > replacements.txt
git filter-repo --replace-text replacements.txt
# Geçmiş yeniden yazıldı; uzak depoyu zorla güncelle
git push origin --force --all
git push origin --force --tags
Buradaki iki kritik uyarıyı atlamayın. Birincisi, --force push geçmişi baştan yazar; ekip arkadaşlarınızın klonlarında hâlâ eski commit'ler bulunur, bu yüzden herkesin depoyu yeniden klonlaması gerekir. İkincisi, depo GitHub gibi bir platformdaysa, o platform silinmiş commit'leri bir süre önbellekte ve fork'larda tutabilir; bu yüzden sırrı iptal etmiş olmak yine de tek gerçek güvencedir. Depoya kod dışında yanlışlıkla giren büyük yedek dosyalarını da benzer şekilde temizleyebilir, düzenli yedekleme stratejinizi ise ayrı bir yedekleme çözümüyle tutabilirsiniz.
Uygulamada Secrets Yönetimi Kontrol Listesi#
Teoriyi pratiğe dökmek için ekiplerimize verdiğimiz kısa kontrol listesini paylaşalım. Bu maddeleri bir projeye başlarken uygularsanız, sırlarla ilgili sorunların büyük çoğunluğunu daha doğmadan önlersiniz.
- Hiçbir sır koda gömülmez; hepsi ortam değişkeni veya secrets yöneticisinden okunur.
.env,*.key,*.pemgibi dosyalar.gitignoreiçindedir ve.env.exampleyalnızca boş anahtar isimleri taşır.- Commit öncesi
gitleaksgibi bir tarama pre-commit veya CI aşamasında zorunludur. - Sır dosyalarının izinleri
600'dür ve web sunucusu bunları asla servis etmez. - Üretim, hazırlık ve geliştirme ortamları farklı sırlar kullanır; asla paylaşılmaz.
- Yüksek riskli anahtarlar için rotasyon takvimi vardır ve otomatikleştirilmiştir.
- Her sır en az yetki prensibiyle sınırlandırılmıştır.
- Bir sızıntı senaryosu için "önce iptal, sonra temizle" prosedürü yazılı ve bilinir durumdadır.
Bu listenin en değerli tarafı, ekipteki herkesin aynı disipline uymasıdır. Güvenlik tek bir kişinin dikkatiyle değil, süreçlerin herkes için otomatik ve zorunlu olmasıyla sağlanır. Sunucularınıza erişimi de aynı titizlikle koruduğunuzdan emin olun; anahtar tabanlı güvenli erişim için SSH bağlantısı ve güvenliği yazımıza göz atabilirsiniz.
Sıkça Sorulan Sorular#
.env dosyası sırlarımı saklamak için güvenli mi?#
Küçük ve orta ölçekli projeler için .env yaklaşımı makul bir başlangıçtır, çünkü sırları koddan ve versiyon kontrolünden ayırır. Ancak dosya diskte düz metin olarak durduğu için mutlak güvenli değildir. Dosya izinlerini 600 yapmalı, dosyayı .gitignore içine koymalı ve web sunucusunun onu servis etmediğinden emin olmalısınız. Çok sunuculu veya yüksek riskli ortamlarda Vault gibi bir merkezi çözüme geçmek daha doğrudur.
Bir API anahtarı yanlışlıkla GitHub'a gitti, ne yapmalıyım?#
Öncelikle paniklemeden ama hızla anahtarı iptal edin: sağlayıcının panelinden anahtarı devre dışı bırakın ve yeni bir tane üretin. Botlar halka açık anahtarları saniyeler içinde toplayabildiği için tek gerçek çözüm budur. Anahtarı iptal ettikten sonra log'ları kötüye kullanım için inceleyin, ardından git filter-repo ile sırrı geçmişten temizleyip zorla push yapın. Sıralamayı asla ters çevirmeyin; önce iptal, sonra temizlik.
Sırları ne sıklıkta döndürmeliyim?#
Kesin bir kural yerine risk seviyesine göre karar verin. Ödeme, kök erişim ve üretim veritabanı gibi yüksek riskli sırları 30-90 günde bir döndürmek iyi bir hedeftir. Orta riskli anahtarları en az yılda bir yenileyin. En önemlisi, bir sızıntı şüphesi veya ekipten ayrılan bir kişi olduğunda takvimi beklemeden hemen rotasyon yapmanızdır. Sıfır kesintili rotasyon için yeni ve eski anahtarı kısa bir süre birlikte geçerli tutmayı unutmayın.
HashiCorp Vault mı yoksa bulut secrets servisi mi tercih etmeliyim?#
Bu tercih altyapınıza ve ekibinizin kapasitesine bağlıdır. Zaten AWS, Google Cloud veya Azure üzerinde çalışıyor ve altyapı yönetmek istemiyorsanız, o sağlayıcının yönetilen secrets servisi hızlı ve entegre bir çözümdür. Buna karşılık çoklu bulut, kendi sunucularınız veya sağlayıcı bağımsızlığı önemliyse HashiCorp Vault daha esnektir ve dinamik sır gibi güçlü özellikler sunar. Küçük başlıyorsanız .env ile başlayıp büyüdükçe geçiş yapmak gayet meşrudur.
Parolaları kod içine yorum satırı olarak yazmak sorun olur mu?#
Kesinlikle sorun olur ve bu çok yaygın bir yanlış anlamadır. Bir değeri yorum satırına almak onu gizlemez; kod dosyası da, git geçmişi de o metni aynen taşır. Yorum satırındaki bir parola, aktif koddaki parola kadar kolay okunur ve tarama araçları tarafından da yakalanır. Sırlar hiçbir biçimde kod dosyasında yer almamalı, ne aktif satırda ne yorumda ne de örnek dosyada gerçek değerle bulunmalıdır.
.env.example dosyasına gerçek değerleri koyabilir miyim?#
Hayır, .env.example dosyasının tüm amacı tam tersidir. Bu dosya repoya commit'lenir ve yalnızca hangi anahtarların gerektiğini gösterir; değer kısmı boş bırakılır veya changeme gibi açık bir yer tutucu içerir. Buraya gerçek bir anahtar yazarsanız, onu doğrudan versiyon kontrolüne, dolayısıyla geçmişe kaydetmiş olursunuz ki bu, kaçınmaya çalıştığınız sızıntının ta kendisidir. Örnek dosya bir şablondur, sır deposu değil.
Kapanış#
Secrets yönetimi, güvenlik dünyasında az konuşulan ama en çok işe yarayan disiplinlerden biridir. Sofistike saldırıları önlemek zordur; ancak koda gömülü anahtarları, korunmasız .env dosyalarını ve hiç döndürülmeyen parolaları önlemek tamamen sizin elinizdedir. Sırları koddan ayırın, doğru izinlerle saklayın, düzenli olarak döndürün, en az yetkiyle sınırlayın ve bir sızıntı anında "önce iptal et, sonra temizle" refleksini ekibinize yerleştirin. Bu basit alışkanlıklar, en pahalı ihlallerin büyük çoğunluğunu daha başlamadan durdurur.
Clou.TR olarak bu prensipleri altyapınıza taşımanıza yardımcı oluyoruz. Kendi Vault örneğinizi çalıştırmak veya sırlarınızı izole bir ortamda tutmak için VDS ve sanal sunucu çözümlerimize, yönetim yükünü bize bırakmak için sunucu yönetim hizmetimize, uygulamalarınızı güvenli barındırmak için hosting paketlerimize ve trafiğinizi uçtan uca şifrelemek için SSL sertifikası seçeneklerimize göz atabilirsiniz. Güvenli bir altyapı, doğru saklanan tek bir anahtarla başlar.