Prod erişimi tek kişideydi, o kişi izne çıktı
Üretim veritabanına erişimi olan tek kişi tatile gidince geliştirme durdu. İhtiyaç dört cümleye indi; her biri bir tasarım kararına dönüştü.
Ekipte üretim veritabanına erişimi olan tek kişi vardı. Bu, uzun süre bir sorun gibi görünmedi — ta ki o kişi izne çıkana kadar. Bir hafta içinde şunu fark ettik: bug’lar tespit edilemiyordu. Kod okunabiliyordu, testler koşuyordu, hipotezler kuruluyordu; ama hiçbiri “üretimde bu kaydın hâli ne” sorusunun yerine geçmiyordu. Geliştirme durmadı, ama teşhis durdu — ve teşhis durunca geri kalanı da yavaşladı.
Bu yazı o haftanın çıkardığı dört cümlelik ihtiyaç listesinin, dört tasarım kararına nasıl dönüştüğünün hikâyesi. Kısa cevap şu: sorunun çözümü erişimi genişletmek değil, erişimi bir kapıdan geçirmek. Geliştirici üretim parolasını hiç görmeden veriye bakabilir; bunun için sorgunun kendisinin denetlenmesi, bir onaydan geçmesi, kalıcı bir ize düşmesi ve sonucun maskelenmesi yeterli. Bu dördünü kuran şey QueryProxy oldu.
Yanlış çözümler neden yanlıştı
İki hazır cevap vardı ve ikisi de bir hafta içinde elendi.
“Parolayı ekiple paylaşalım.” Bunun bedeli ilk gün görünmüyor. Parola bir
kez dağıldığında geri toplanamıyor: kimde olduğu bilinmiyor, biri ayrıldığında
döndürmek gerekiyor, ve en önemlisi kimin ne çalıştırdığı sorusunun cevabı
kalmıyor. Bir UPDATE yanlış satırı güncellediğinde elinizde yalnızca bir
tahmin oluyor.
“Herkese salt-okunur kullanıcı açalım.” Bu daha iyi ama yetmiyor. Salt okunur bir kullanıcı da tablonun tamamını çekebiliyor; kişisel verinin maskelenmesi diye bir şey yok, ve gerçek teşhisin bir kısmı okumayla bitmiyor — bazen bozuk bir kaydı düzeltmek gerekiyor. O an geldiğinde yine tek kişiye dönüyorsunuz.
Ortak kusur şu: ikisi de soruyu kim ekseninde çözmeye çalışıyor. Oysa asıl soru ne — hangi ifadenin çalışacağı.
Birinci ihtiyaç: parolayı görmeden erişmek
İlk karar, kimlik bilgisinin nerede duracağıydı. Bağlantı künyesi uygulamanın içinde şifreli duruyor, parola hiçbir arayüzde geri gösterilmiyor; sorguyu çalıştıran da geliştiricinin makinesi değil, portalın kendisi. Geliştiricinin elinde kalan tek şey yazdığı SQL.
Bunun bedeli gerçek ve peşinen kabul edildi: sorgu artık anında çalışmıyor. Karşılığında üretim parolası hiçbir zaman bir insanın eline geçmiyor. Bir kurum için asıl kazanç da bu — erişimi geri almak, artık bir kullanıcıyı silmekten ibaret.
İkinci ihtiyaç: her SQL bir kapıdan geçsin
İkinci karar en çok düşündüğümüz yerdi: kapı neye bakacak?
İlk akla gelen yol desen eşleştirmesi — DELETE görünce uyar, DROP görünce
reddet. Bu yol ilk gün aşılır. Araya yorum sıkıştırmak (DROP/**/DATABASE),
ifadeyi bölmek ya da bir alt sorguya saklanmak yeterli oluyor. Düzenli ifadeler
metne bakar; SQL ise metin değil, yapı.
O yüzden gelen sorgu ayrıştırılıyor ve ne olduğu çözümlenmiş yapısından okunuyor. Pratik karşılıkları şunlar:
WHERE’i olmayan birUPDATEya daDELETEreddediliyor. Tabloyu bilerek güncellemek isteyenWHERE 1 = 1yazıyor — niyetini beyan etmiş oluyor.- Limitsiz bir
SELECTvarsayılan bir satır sınırıyla dönüyor, üst sınırı aşan istek tavana kırpılıyor. - Veritabanı silme, kullanıcı/rol yönetimi ve sunucu tarafı dosya işlemleri koşulsuz engelleniyor — rolü ne olursa olsun.
- Yorumlar ve dize sabitleri normalize edildiği için araya yorum sıkıştırarak kapı aşılamıyor.
Bir ayrıntı bu tasarımın özetini veriyor: kapının anlayamadığı bir limit ifadesi kırpılmıyor, reddediliyor. Anlaşılmayan bir sınır, zorlanamayan bir sınırdır; belirsizlikte doğru davranış geçirmek değil durdurmaktır.
Kapı yalnız yarısı. Diğer yarısı onay: istek bir DBA’ya düşüyor, onaylanınca kuyrukta çalışıyor. Buradaki sert kural, bir DBA’nın kendi isteğini onaylayamaması; sistem admini bunu aşabiliyor ve aşma denetim kaydına aşım olarak düşüyor. Onay üç kanaldan gelebiliyor — web, Slack, Teams — ama üçü de aynı servise iniyor, çünkü kuralı kanal başına yazmak, kuralın kanal başına ayrışması demek.
Üçüncü ihtiyaç: sonradan kimin ne çalıştırdığını bulmak
Üçüncü ihtiyaç bir tarih sorusuydu: üç ay sonra “bu kaydı kim değiştirdi” sorulduğunda cevap bulunabilmeli.
Buradaki karar, denetim kaydını değiştirilemez kılmak oldu; ve bunun uygulamadaki karşılığı basit üç şey: kayıt tablosunda güncelleme sütunu yok, güncelleme ve silme model düzeyinde istisna atıyor ve kayıt satırları hiçbir yabancı anahtar kısıtına bağlanmıyor. Son madde en kolay kaçırılan yer: bir bağlantı silindiğinde onun geçmişinin de silinmesi, denetim izini tam ihtiyaç duyduğunuz anda boşaltır.
Dürüst bir sınır: bu, uygulama düzeyinde bir değiştirilemezlik. Veritabanına doğrudan erişen biri satırı hâlâ değiştirebilir. Kriptografik bir zincir değil, uygulamanın sızdırmadığı bir kapı — ve neyi vaat ettiğini bilerek kullanmak gerekiyor.
Dördüncü ihtiyaç: kritik bilgi maskelensin
Son karar, maskelemenin nerede durduğuyla ilgiliydi ve en öğretici olanı bu.
Kolay yol, sonucu kaydedip gösterirken maskelemek. O tasarımda maskesiz veri diske bir kez yazılıyor ve ondan sonrası temenniye kalıyor: yedek alındığında, dosya indirildiğinde ya da log’a düştüğünde maskesiz hâl orada duruyor.
Bunun yerine sonuç akışı satır satır okunuyor ve her satır dosyaya yazılmadan önce maskeleniyor. Sonuç deposuna maskesiz bir hücre hiç girmiyor. Fark kulağa küçük geliyor ama güvenlik açısından kategorik: birinde “maskelemeyi atlatan bir yol var mı” diye düşünmeniz gerekiyor, diğerinde atlatılacak bir şey yok.
Aynı disiplin kuralların kendisinde de var. Maskeleme kuralları düzenli ifade kabul ediyorsa, kötü yazılmış bir ifade işçiyi kilitleyebilir; o yüzden kural kaydedilirken uzun bir prob dizesiyle sınanıyor. Ve çalışma anında bir ifade değerlendirilemezse değer açıkta bırakılmıyor, maskeleniyor — belirsizlikte kapalı tarafa düşmek, kapı kuralının aynısı.
Bunun toplam bedeli
Dürüst olmak gerekirse bu kurulumun bir maliyeti var ve saklanacak bir tarafı yok.
Sorgu artık anlık değil; birinin onaylaması gerekiyor ve bu, gece yarısı bir olayda sürtünme demek. Ekip yeni bir servis işletiyor. Ve en önemlisi, onay kuyruğu bir ritüele dönüşürse — yani DBA bakmadan onaylıyorsa — bütün yapı tiyatroya dönüşüyor; o hâlde parolayı paylaşmaktan tek farkı, yanlış bir güven duygusu vermesi olur.
Karşılığında alınan şey ise şu: teşhis artık bir kişinin takvimine bağlı değil, üretim parolası kimsede yok, ve üç ay sonra sorulacak soruların cevabı duruyor. Bir hafta boyunca teşhis edemediğimiz bug’ların bana öğrettiği şey, erişim yönetiminin bir izin meselesi değil bir tasarım meselesi olduğuydu.
Aracın kendisi açık kaynak ve self-hosted; kurduğum yol ile kararların gerekçesi Labs kaydında, ürünün künyesi portfolyoda.
Kaynaklar
Bu konudaki deneyler
Üretim veritabanına giden ad-hoc SQL'i onaya, maskelemeye ve değiştirilemez bir ize bağlayan self-hosted portal; QueryProxy ürününe dönüştü.
Şu an ne yapıyor
Geliştiricinin yazdığı SQL'i üretim veritabanında doğrudan değil, bir onaydan geçirerek çalıştırıyor; sonuçlar diske yazılırken maskeleniyor ve her istek değiştirilemez bir kayda düşüyor. Prod erişimi tek kişide toplanmış ekipler kurabilir.
Yanındaki cihaz uzaklaşınca bilgisayarı kilitleyen yakınlık kilidi; menü çubuğu uygulaması SignalLock'a dönüştü.
Şu an ne yapıyor
Yanındaki cihaz uzaklaşınca macOS ekranını kilitliyor; karar ham "var/yok" sinyaline değil bir yakınlık değerlendirmesine dayandığı için sinyal dalgalanması yanlış kilit üretmiyor. Menü çubuğu uygulaması yayında, indirilip kullanılabilir.
Yorumlar
Yorum yapmak için GitHub hesabınızla giriş yapmanız yeterli. Yorumlar GitHub Discussions üzerinde saklanır.