deniz.in

Piyasalar

Hava durumu

Hava durumu yükleniyor

· kaynak dev.to (home feed)

Fork PR'lerde secret'lar erişilemediğinde GitHub Actions için güvenli desenler

Dev.to'daki bir yazı, fork'tan gelen pull request'lerde GitHub Actions secret'larının neden boş göründüğünü açıklıyor ve repository kimlik bilgilerini ifşa etmeden CI'yi işlevsel tutan desenleri sıralıyor.

Fork PR'lerde secret'lar erişilemediğinde GitHub Actions için güvenli desenler

Yanlış yapılandırma gibi görünen arıza

Dev.to'daki bir yazıya göre, tanıdık bir GitHub Actions bulmacasının kasıtlı ve sıradan bir nedeni var. Kendi branch'lerinizde geçen bir job, aynı commit bir katkıcının fork'undan gelen pull request'e ulaştığında hemen başarısız oluyor; eksik şifre girdisi, kullanılamayan cloud kimlik bilgileri ya da bir HTTP 401 hatasıyla şikayet ediyor. "Secret" kelimesi hiçbir yerde nadiren görünür, çünkü secret yalnızca boş bir string olarak çözümlenir ve onu tüketen neyse ona kendi dilinde hata verir.

Yazarın da belirttiği gibi, ipucunu karşılaştırma verir: aynı workflow, aynı commit, repo içinde yeşil, fork'tan kırmızı. Kısa bir tanı adımı, hiçbir değer yazdırmadan işi çözer: ilgili secret'ın boş olup olmadığını, event adını ve github.event.pull_request.head.repo.fork bayrağını log'layın; fork pull request'te bu false ve true yazdırır. Bozuk bir şey yok — GitHub Actions, fork'tan tetiklenen pull_request çalıştırmalarında secret'ları vermez ve GITHUB_TOKEN'ı salt okunur kapsamla sınırlar; bunu tersine çeviren bir ayar yoktur.

Bu sınır neden var

Gerekçe, çalışan kodu kimin kontrol ettiğine dair. Bir pull_request çalıştırması PR yazarının yazdığı her şeyi yürütür ve GitHub hesabı olan herkes herkese açık bir repository'ye PR açabilir. Bu çalıştırmalar deploy anahtarları ya da publish token'ları taşısaydı, bir test'e masum görünen bir düzenleme, package.'daki bir prepare script'i veya bir Makefile hedefi, yazma erişimi gerektirmeden tek commit'te repository'deki tüm secret'ları sızdırabilirdi. Bu yüzden güvenilmeyen kod secret'sız ve salt okunur bir token ile çalışır; secret taşıyan iki tetikleyici — pull_request_target ve workflow_run — ise base repository'nin bağlamında çalışır ve varsayılan olarak PR'ın değil sizin kodunuzu checkout eder. Anlamlı sınır, branch'i hangi repository barındırdığı değil, yürütülen kodu kimin yazdığıdır.

Önce secret ihtiyacını ortadan kaldırın

Yazarın çoğu ekibin atladığını söylediği adım, bağımlılığın etrafından dolaşmak değil onu ortadan kaldırmaktır. Kimlik bilgilerine bağlı birçok CI adımı tesadüfen öyledir: yerel bir stub'ın karşılayabileceği bir staging API'sine dokunan test, yalnızca publish için gereken bir registry girişi, bir service container'ın kapsayacağı bir entegrasyon paketi. Service container'lar ve geçici yerel bağımlılıklar, tamamen kimlik bilgisi gerektirmedikleri için fork PR'lerde sorunsuz çalışır.

Bir adımın gerçekten taklit edilemediği durumlarda önerilen varsayılan, fork PR'lerde onu atlamak ve bu atlamayı görünür kılmaktır. Bir detay önemli: secret'ı önce job düzeyinde bir ortam değişkenine eşleyin, örneğin HAS_TOKEN: ${{ secrets.STAGING_API_TOKEN != '' }}, sonra adım düzeyinde bu değişkene göre dallanın ve atlamayı açıklayan bir notice yayınlayın. Job düzeyindeki if içinde çıplak bir secrets.* referansı insanların beklediği gibi değerlendirilmezken, eşlenen değişkendeki adım düzeyi kontrolü tutarlı davranır.

Pipeline'ı workflow_run ile bölün

Gerçekten kimlik bilgisi gerektiren işler için yazının merkezindeki desen iki workflow'dur. Workflow A pull_request üzerinde çalışır, secret tutmaz, PR'ı build eder ve PR numarasını içeren bir artifact yükler. Workflow B, A'nın tamamlanmasıyla workflow_run üzerinden tetiklenir, sizin repository'nizin bağlamında tam secret'larla çalışır, yalnızca artifact'ı indirir ve ayrıcalıklı adımı — örneğin bir preview yayınlama — gerçekleştirir.

İki detay bunu ya yapar ya bozar. workflow_run job'ları pull request üzerinde check olarak görünmez; bu yüzden workflow B, GitHub API üzerinden head SHA'ya bir commit status göndermelidir; bu adım olmadında maintainers hiçbir sinyal görmez. Ve deploy mantığı kendi checkout ettiğiniz repository'den gelmeli ya da satır içi olmalı, asla indirilen artifact'tan gelmemelidir — güvenilmeyen bir build'in ürettiği her şey güvenilmeyen girdidir. Onu yürütmeyin ve hazırlanmış arşivlerdeki path traversal nedeniyle, daha sonra çalıştıracağınız dizinlere açarken dikkatli olun.

Alternatifler ve tuzak

Yazı kalan seçenekleri de haritalıyor. Base repository koduyla sınırlanan pull_request_target, secret'ları düşük riskle erişilebilir kılar ama sonradan eklenecek bir checkout ile kolayca bozulur. pull_request_target'ı PR head'inin checkout'uyla birleştirmekse ağır durumdur: aynı çalıştırmada secret'lar ve güvenilmeyen kod, klasik "pwn request". Zorunlu onaylayıcıları olan bir deployment ortamı, sürece insan katar ve job'u bir maintainer onaylayana dek duraklatır — ara sıra dış katkı gelen küçük repository'ler için makul, karşılığında onay yorgunluğu getirir. Yazarın belirttiğine göre Vercel, Netlify ve Cloudflare'in yönetilen preview-deployment ürünleri fork durumunu kendi kimlik bilgileriyle zaten çözüyor; bu, aynı sorunun sizin yerinize çözülmüş hâli.

Neden önemli

Bu davranış saatler yakar, çünkü arıza secret'lardan söz eden bir şey olarak değil, aşağı akış aracının hata mesajı olarak yüzeye çıkar ve içgüdü, var olmayan bir yapılandırma düzeltmesi aramaktır. Gerçek sınırı bilmek — güvenilmeyen kod kimlik bilgisi almaz — açıklanamaz bir kırmızı build'i, iyi anlaşılmış birkaç biçimi olan bir tasarım kararına dönüştürür. Aynı zamanda savunmasal olarak da önemli: pull_request_target artı PR kodunun checkout'u, tam secret ele geçirmeye giden bilinen bir yoldur ve bunu gelişigüzel benimseyen repository'ler bunun bedelini öder.

  • #github-actions
  • #ci-cd
  • #devops
  • #security
  • #open-source

İlgili yazılar