Sır yönetimi: .env dosyasından sonrası
.env bir sırrı koddan çıkarır ama döndürülebilir yapmaz. Dosya izninden platform deposuna ve kısa ömürlü kimliğe kadar, sır yönetiminin katmanları ve her katmanın gerçek maliyeti.
.env bir çözüm değil, bir erteleme. Sırrı koddan çıkarıp dosyaya alır ve tek bir soruyu cevaplar: kaynak kodda düz metin API anahtarı durmasın. Geri kalan her soruyu açık bırakır. Bu yazı, .env'in yetmediği anı nasıl tanıyacağınız ve o andan sonra ne yapacağınız üzerine.
.env üç yerde kırılır
Ekip büyüdüğünde. İkinci geliştirici katıldığı gün sır bir Slack mesajına, bir WhatsApp'a ya da bir zip dosyasına düşer. O andan sonra anahtarın kaç kopyası olduğunu kimse bilmez.
Dağıtım eklendiğinde. Yerelde .env, sunucuda başka bir .env, CI'da üçüncü bir kopya. Üçü arasındaki fark, üretimde "bende çalışıyordu" hatasının en yaygın kaynağıdır.
Sır döndürmek gerektiğinde. Bir anahtarı iptal etmek istiyorsunuz. Nerelerde durduğunu bilmiyorsanız iptal edemezsiniz. Sır yönetiminin asıl işi saklamak değil, döndürebilmektir.
Katman 0: .env'i doğru kullanmak
Çoğu proje burada kalıyor ve bu bazen doğru karar. Ama şu üçü olmadan olmaz.
Depoda sırrın kendisi değil, şeması dursun:
# .gitignore
.env
.env.local
.env.*.local
!.env.example
# .env.example — değer yok, anahtar var
DATABASE_URL=
STRIPE_SECRET_KEY=
RESEND_API_KEY=
Eksik değişkeni üretimde değil, açılışta yakalayın. Uygulamanın ilk satırında doğrulayın:
const gerekli = ['DATABASE_URL', 'STRIPE_SECRET_KEY', 'RESEND_API_KEY'];
const eksik = gerekli.filter((k) => !process.env[k]);
if (eksik.length) {
throw new Error(`Eksik ortam değişkeni: ${eksik.join(', ')}`);
}
Bu üç satır, yarım yapılandırmayla ayağa kalkıp ilk isteğe kadar sessiz kalan servisleri engeller.
Dosya izni de bir kontroldür. Sunucudaki .env herkes tarafından okunabiliyorsa dosyaya taşımanın anlamı kalmaz:
chmod 600 /etc/uygulama/env
chown uygulama:uygulama /etc/uygulama/env
systemd ile çalışıyorsanız sırrı unit dosyasına değil, ayrı dosyaya koyun; unit dosyaları genellikle dünyaya okunabilir:
[Service]
EnvironmentFile=/etc/uygulama/env
User=uygulama
Sır depoya girdiyse: silmek yetmez
Bir anahtar commit'lendiyse, sonraki commit'te silmek onu geçmişten çıkarmaz. Aramak için:
git log -p -S 'sk_live' --all | head -50
Geçmişi temizlemek mümkün (git filter-repo, bfg), ama sıralama şudur: önce anahtarı iptal edip yenisini üretin, sonra geçmişi temizleyin. Depo bir kez klonlandıysa geçmiş temizliği o kopyaya ulaşmaz. İptal edilmemiş anahtar, temizlenmiş geçmişten daha tehlikelidir.
Depoya kaza eseri sır girmesini engellemek için bir commit kancası işe yarar. gitleaks, trufflehog ya da GitHub'ın kendi push protection'ı bu işi yapar; hangisi olursa olsun, çalıştığını bir kez sahte anahtarla test edin. Test edilmemiş kanca, olmayan kancadan kötüdür, çünkü güven verir.
Katman 1: platformun kendi deposu
Vercel, Railway, Fly, Render ve benzeri platformlarda ortam değişkenleri panelde tutulur ve dağıtıma enjekte edilir. Bu, dosyayı sunucudan tamamen kaldırır. İki tuzağı var.
Birincisi build-time / runtime ayrımı. Derleme sırasında okunan bir değişken, çıktının içine gömülür. Next.js'te NEXT_PUBLIC_ önekli her değişken tarayıcıya iner:
// Bu değer client bundle'ına girer. Sır koymayın.
const key = process.env.NEXT_PUBLIC_ANALYTICS_ID;
// Bu yalnızca sunucuda okunur.
const secret = process.env.STRIPE_SECRET_KEY;
Kontrol etmenin en hızlı yolu derlenmiş çıktıda aramaktır:
grep -r "sk_live" .next/static/ && echo "SIZINTI VAR"
İkincisi önizleme ortamları. Preview dağıtımları çoğu kurulumda üretim değişkenlerini görmemeli. Üretim veritabanı anahtarı bir preview URL'ine düştüğünde, o anahtarın erişim alanı da o URL kadar geniş olur.
Katman 2: kısa ömürlü kimlik
Asıl kırılma, uzun ömürlü sırların kendisinde. Yıllardır dönmeyen bir anahtar, sızdığında sızdığı gün belli olmaz. Yönetilen sır depoları (HashiCorp Vault, AWS Secrets Manager, Google Secret Manager, Doppler, Infisical) iki şey getirir: merkezi kayıt ve erişim günlüğü. Asıl kazanç ise kısa ömürlü kimlik bilgileri — sabit bir anahtar yerine, servise dakikalar boyunca geçerli bir token verilmesi.
CI tarafında aynı fikir OIDC ile karşılığını buluyor: CI çalışmasına bulut sağlayıcısında kalıcı bir anahtar tanımlamak yerine, iş akışına kısa ömürlü bir kimlik veriliyor. Depoda saklanan bir bulut anahtarı ortadan kalkıyor.
Bu katmana geçmenin bedeli işletme karmaşıklığı. Tek geliştiricili bir projede Vault kurmak, çözdüğünden fazla sorun üretir. Ölçüt basit: sırrı görebilen insan sayısı üçü geçtiyse ya da dağıtım hedefi ikiden fazlaysa, merkezi depo kendini ödemeye başlar.
Sızıntının unutulan kanalları
- Loglar. Hata yakalayıcıya tüm
process.env'i gönderen bir satır, sırların tamamını üçüncü tarafa taşır. Sentry benzeri araçlarda gönderilen bağlamı bir kez elle okuyun. - Process listesi. Sırrı komut satırı argümanı olarak geçirmeyin;
ps auxçıktısında görünür. Ortam değişkeni ya da dosya kullanın. - Hata sayfaları. Üretimde ayrıntılı yığın izi kapalı olmalı; bazı çerçeveler hata sayfasında yapılandırmayı basar.
- Yedekler. Veritabanı yedeği alan script'in kendi kimlik bilgisi de bir sırdır ve genellikle en eski, en az dönen anahtardır.
Bu hafta yapılacak
Bir tablo açın ve her sır için üç sütun doldurun: nerede duruyor, kim erişebiliyor, nasıl döndürülür. Üçüncü sütunu dolduramadığınız her satır, sır yönetiminizin gerçek sınırıdır. Araç seçimi o tablodan sonra gelir.
- Güvenlik
- DevOps
- Sır Yönetimi
- CI/CD