Series · 3 partsWhen Access Checks FailPart 1 · You are here
- 1CI/CD ve OIDC Güven Sınırı: GitHub Actions'tan Buluta Yetki GeçişiYou are here
- 2İmza Geçerli. Token Hâlâ Başka Bir Yere Ait: JWT Doğrulama Sınırı
- 3İstek Sunucu Tarafında Kaldı. Kimlik Bilgisi Kalmadı: SSRF ve Cloud Metadata
60 saniyede CI/CD OIDC güven sınırı
Çoğu ekibin yaptığı en iyi CI/CD güvenlik iyileştirmesi, uzun ömürlü bulut erişim anahtarlarını depodan silip yerine OpenID Connect (OIDC) entegrasyonunu getirmektir. İş akışı kısa ömürlü bir kimlik belirteci (identity token) talep eder, bulut sağlayıcı bunu geçici kimlik bilgileriyle takas eder; böylece rotasyona tabi tutulacak, sızdırılacak veya eski derleme günlüklerinde unutulacak hiçbir statik gizli anahtar (secret) kalmaz.
Bu kesinlikle gerçek bir kazanımdır. Ancak tüm gizli anahtar tarayıcılarında (secret scanners) kusursuz görünen yeni bir hata modunu da beraberinde getirir: Kimlik bilgisi ortadan kalkmıştır fakat yeni bir tane üretme hakkı herkesin düşündüğünden çok daha geniştir.
OIDC, güven ihtiyacını boru hattından (pipeline) tamamen silmez. Güveni, claim’lere ve politika koşullarına taşır. Eğer bu koşullar “korumalı production dalındaki incelenmiş dağıtım işi” yerine “bu organizasyondaki herhangi bir iş akışı” diyorsa, boru hattınız tüm organizasyonu kapsayan otomatik kayıt politikasına sahip bir bulut kimlik sağlayıcısına dönüşmüştür.
Statik anahtar hiçbir zaman yetkilendirme sınırı olmadı
Statik bir erişim anahtarı, kimlik doğrulama (authentication) ile yetkilendirmeyi (authorisation) tek bir dizede birleştirir: Bu değere sahip olan herkes ilgili kimliği kullanabilir. OIDC ise bunları birbirinden ayırır. GitHub iş akışını doğrular ve imzalı bir token üretir; AWS ise bu token içindeki claim’lerin belirli bir rolü devralmasına (assume) izin verilip verilmediğine karar verir.
Yapısal yükü taşıyan asıl karar ikinci karardır.
GitHub Actions için bir AWS rol güven politikası (trust policy) normalde iki temel claim’i değerlendirir:
aud, resmi AWS credentials action’ı kullanıldığında yaygın olaraksts.amazonaws.comşeklinde hedeflenen token takasını belirtir.sub, token’ı talep eden depo bağlamını tanımlar: İşe bağlı olarak depo adı, dal (branch), etiket (tag), pull request veya ortam (environment).
Rolün izin politikası (permission policy) oturumun ne yapabileceğini belirler. Güven politikası (trust policy) ise hangi iş akışının o oturuma dönüşebileceğini belirler. Canlı ortama bağlı bir role en az yetki (least privilege) izin politikası tanımlamak, yanlış deponun bu rolü devralmasına izin veren gevşek bir güven politikasını telafi edemez. En az yetki prensibi, çoğu denetimin başladığı noktadan tam bir adım önce başlar.
Tek bir joker karakter (wildcard) ihlal birimini değiştirir
AWS; sub koşulu bulunmayan, null olan veya yalnızca tek bir çıplak joker karakterden (*) oluşan yeni bir GitHub güven politikasını reddeder. Bu güvenlik korkuluğu değerlidir ancak kabul edilen her desenin dar kapsamlı olduğu anlamına gelmez. Aşağıdaki koşul sözdizimsel olarak kısıtlı görünür ancak operasyonel olarak devasa bir risk taşır:
{
"StringEquals": {
"token.actions.githubusercontent.com:aud": "sts.amazonaws.com"
},
"StringLike": {
"token.actions.githubusercontent.com:sub": "repo:example-org/*"
}
}
Bunun anlamı şudur: Güvenlik sınırınız artık tek bir deployment deposu değildir. Bu organizasyon desenine uyan mevcut ve gelecekteki her depo ve bu depolardan herhangi birinin token talep etmesini sağlayabilecek her kullanıcı ve iş akışı bu sınırın içindedir.
Bu hataya düşmek çok kolaydır; çünkü politika merkezi bir kural gibi okunur: “GitHub organizasyonumuz dağıtım yapabilir.” Oysa organizasyonlar arşivlenmiş projeleri, geçiş araçlarını, şirket içi küçük denemeleri, fork’ları ve çok farklı dal koruma kurallarına sahip depoları barındırır. Düşük öneme sahip tek bir depo, iş akışı dağıtım deposuyla aynı sub desenini karşılayabildiği anda canlı ortam için doğrudan bir saldırı vektörü haline gelir.
Güvenilir sınır, sağlayıcının ve bulutun birlikte zorunlu kılabileceği en küçük ve kararlı claim kümesidir: Tam eşleşen depo kimliği, beklenen audience ve korumalı bir dal ya da korumalı bir GitHub ortamı (environment). Bir iş akışında environment tanımlandığında, varsayılan sub biçimi dal yerine o ortamı içerecek şekilde değişir. Bu kozmetik bir fark değildir; güven politikası ile deponun ortam koruma kuralları artık birleşerek tek bir güvenlik kontrolü oluşturur.
Politika yazmadan önce sağlayıcının terminolojisini test edin
İşe internetteki güven politikası örneklerini kopyalayarak başlamayın. Ayırt etmek istediğiniz her iş akışı bağlamının (canlı ortam, ana dal, pull-request işi, etiket yayını ve yeniden kullanılabilir iş akışları) fiilen hangi claim’leri ürettiğini gözlemleyerek başlayın.
Yetkilendirilmiş bir test deposunda, token’ı yalnızca yerel olarak başlığını ve claim’lerini çözecek kadar talep edin. Kodlanmış token’ı loglara yazdırmayın veya canlı bir rolle takas etmeyin:
permissions:
contents: read
id-token: write
jobs:
inspect-claims:
runs-on: ubuntu-latest
environment: oidc-lab
steps:
- uses: actions/github-script@v8
with:
script: |
const token = await core.getIDToken('sts.amazonaws.com')
const claims = JSON.parse(Buffer.from(token.split('.')[1], 'base64url'))
core.info(JSON.stringify({ aud: claims.aud, sub: claims.sub, ref: claims.ref }))
Yalnızca sts:GetCallerIdentity iznine sahip ayrıcalıksız bir laboratuvar rolü kullanın. Pozitif test durumu bu rolü hedeflenen ortamdan devralmalıdır. Negatif test durumları ise bir özellik dalından (feature branch), bir pull request’ten, ikinci bir depodan ve korumalı ortama referans vermeyen bir işten çalıştırıldığında başarısız olmalıdır. Bunlardan herhangi biri başarılı oluyorsa, güven politikası yazarının düşündüğünden çok daha geniştir.
Token’ın tamamını asla ekrana yazdırmayın. Kısa ömrü boyunca bu bir bearer kimlik bilgisidir ve bir değer hızla sona erse dahi loglara yazılması bir sızıntıdır.
İsimler her zaman en kalıcı kimlikler değildir
Depo isimleri OIDC politikasını okunabilir kılar ancak isimler değiştirilebilir, transfer edilebilir ve bazı sistemlerde yeniden kullanılabilir. GitHub’ın güncel OIDC referansı, sahip ve depo ID’lerini içeren değiştirilemez (immutable) bir subject formatı sunar. Eski depolar taşınana kadar önceki isim tabanlı formatı üretmeye devam edebilir.
Bu geçiş çoğu örneğin atladığı bir inceleme sorusu yaratır: Bu depo bugün fiilen hangi subject formatını üretiyor? Yeni şemaya göre yazılmış bir politika eski bir depoyu reddeder. Bulut güveni güncellenmeden yapılan bir geçiş dağıtımı bozar. Kesinti sırasında eklenen geçici bir joker karakter ise her iki formatı sessizce kalıcı hale getirerek rolü eskisinden daha savunmasız bırakabilir.
Subject formatı geçişini bir kimlik geçişi gibi ele alın: Mevcut claim’leri yakalayın, tam eşleşen yeni koşulu hazırlayın, pozitif ve negatif kontrolleri çalıştırın ve ardından eski formatı kaldırın. Geriye dönük uyumluluk kalıcı bir joker karakter değil, ölçülebilir bir geçiş penceresi olmalıdır.
Kanıt matrisi (Evidence matrix)
| Sinyal | Neyi kanıtlar | Negatif kontrol | Savunucu doğrulaması |
|---|---|---|---|
Korumalı işten gözlemlenen aud ve sub | Sağlayıcı terminolojisi ve kesin dağıtım kimliği bilinmektedir | Pull request, özellik dalı ve ikinci depodan claim’leri toplayın; her biri beklenen alanda farklı olmalıdır | Canlı claim’leri güven politikası operatörleri ve değerleriyle karşılaştırın |
| Rol devralma yalnızca onaylı ortamdan başarılı oluyor | Claim koşulları hedeflenen kaynak sınırını zorunlu kılıyor | Aynı rolü en yakın komşu bağlamlardan devralmayı deneyin ve reddedildiğini teyit edin | AssumeRoleWithWebIdentity olaylarını depo, subject, rol ve oturum adıyla ilişkilendirin |
| Organizasyon veya depo joker karakteri belgelenenden daha fazla kimlikle eşleşiyor | İhlal birimi tek bir deployment deposundan daha büyüktür | Deseni kesin koşullarla değiştirin ve meşru dağıtımın çalıştığını doğrulayın | Her wildcard desenini karşılayabilecek her depoyu ve iş akışını envantere alın |
| Ortam koruması incelenmemiş bir dağıtım işini engelliyor | Depo kontrolleri ve bulut güveni birleşerek tek bir sınır oluşturur | İncelemeci/dal uygunluğunu kaldırın ve token’ın artık canlı yolu karşılayamadığını teyit edin | Ortam incelemecilerini, dağıtım dallarını, yöneticileri ve atlatma izinlerini denetleyin |
| Değiştirilemez subject geçişi yeni formatı kabul edip eskiyi reddediyor | Uyumluluk süreci ikinci bir kalıcı güven yolu bırakmamıştır | Geçişten sonra eski subject formatını kullanan bir token sunun ve reddedildiğini teyit edin | Subject formatını, repo ID’sini, owner ID’sini ve politika geçiş tarihini takip edin |
Sıkça karşılaştığım ortak örüntü
Ekip bulut erişim anahtarını sildiği için kutlama yapar, rotasyon biletini kapatır ve onun yerine geçen güven politikasının sahipliğini hiçbir zaman kimseye atamaz. Platform mühendisliği iş akışının sahibidir. Bulut güvenliği IAM’in sahibidir. Depo yöneticileri ortamların sahibidir. Kimlik ancak her üç sistem uzlaştığında var olur; dolayısıyla hiçbir sahip tek başına tüm kayıt kuralını görmez.
Bu nedenle kalıcı bulgu “OIDC yanlış yapılandırılmış” değildir. Şudur: “Bu canlı ortam rolü şu ek iş akışı bağlamlarından gelen token’ları kabul ediyor ve sınır tam olarak bu koşul nedeniyle genişliyor.” Bu saldırı yolu da diğer tüm kimlik yükseltme yolları kadar somut ve izlenebilir olmalıdır.
Savunuculara teslim edilmesi gerekenler
Çözümlenmiş güven popülasyonu. Her StringLike desenini bugün fiilen eşleştiği depolara, dallara, etiketlere, pull-request işlerine ve ortamlara dönüştürün.
Claim sözleşmesi. Beklenen sağlayıcıyı, audience’ı, subject formatını, depo kimliğini ve dağıtım bağlamını kaydedin. Depo transferlerinden, ortam değişikliklerinden veya format geçişlerinden sonra bu sözleşmeyi yeniden test edin.
Negatif senaryolar. Başarılı bir canlı dağıtım yalnızca erişilebilirliği kanıtlar; tekilliği (münhasırlığı) kanıtlamaz. En yakın güvenilmeyen bağlamlar için otomatik ret testlerini hazır tutun; çünkü güven politikasının yeniden kontrolsüzce genişlediğini tespit edecek olanlar yalnızca bu testlerdir.
Boru hattı artık bir bulut kimlik bilgisi saklamıyor. Çok daha kritik bir şeyi saklıyor: O kimlik bilgisini kimin isteyebileceğine karar veren güvenlik politikasını.
Bu teknik not ne kadar güncel?
En son kaynak incelemesi, içerik güncellemesi veya yayın tarihi gösterilmektedir.
Yazar teknik incelemeyi tamamladı. Bu etiket tek başına laboratuvar yeniden üretimi iddiası taşımaz.
