Tekrarlanabilir derlemeler tam olarak neyi kanıtlar?
Bir checksum dosyanın bütünlüğünü, tekrarlanabilir derleme ise ikili dosyanın kaynak kodla birebir eşleştiğini doğrular. Bu iki farklı güvenlik katmanının farkını öğrenin.
Tekrarlanabilir derlemelerin kanıtladığı durum
Tekrarlanabilir derlemeler tek bir dar gerçeği kanıtlar: size teslim edilen ikili dosya (binary), tam olarak bu kaynak kodun ürettiği dosyadır. Herkes aynı kaynağı alıp tekrar derleyebilir ve baytları karşılaştırabilir. Doğrulama işlemi, yalnızca yayıncının yapabildiği bir eylem olmaktan çıkar.
Reproducible Builds projesi bunu şu şekilde tanımlar: "Bir derleme; aynı kaynak kod, derleme ortamı ve derleme talimatları verildiğinde, herhangi bir tarafın tüm belirtilen çıktıların bit-bit aynı kopyalarını yeniden oluşturabilmesi durumunda tekrarlanabilirdir." Karşılaştırmanın kendisi bir hash işlemidir. Tüm zorluk, ortamı ve talimatları iki farklı makinenin aynı fikirde olacağı kadar sıkı bir şekilde sabitlemekte yatar.
Neden bir sağlama toplamı (checksum) bu soruyu yanıtlamaz
Yayınlanmış bir sağlama toplamı, dosyanın bozulmadan ulaştığını kanıtlar. Bu sağlama toplamı üzerindeki bir imza ise dosyanın, anahtarı elinde bulunduran kişiden geldiğini doğrular. Ancak bunların hiçbiri, yapay nesne (artifact) oluşturulmadan önce ne olduğu hakkında bilgi vermez. Yayıncının derleme makinesi ele geçirilmişse, kötü niyetli ikili dosya (binary) tıpkı temiz bir dosya gibi sağlama toplamı ile imzalanır; bu nedenle sonraki tüm kontroller başarıyla geçer. Bir geliştirici, depoya (repository) hiç gönderilmemiş bir çalışma ağacından (working tree) derleme yaparsa da durum aynıdır.
Aradaki boşluk budur. Kaynak kodunu okuyabilir, imzayı doğrulayabilir, sağlama toplamını kontrol edebilirsiniz; ancak yine de depoda hiç yer almamış bir kodu çalıştırıyor olabilirsiniz. Bu nedenle tekrarlanabilirlik (reproducibility), yayınlanmış bir sağlama toplamı ile indirme işlemini doğrulamaktan farklı bir konudur. Sağlama toplamı aktarımı korur. Yeniden derleme ise aktarımdan önce gerçekleşen her şeyi korur.
Bu saldırı teorik değildir. 2020 SolarWinds Orion ihlali tam olarak bu noktada gerçekleşmiştir: derleme sistemi, kimsenin incelemediği kaynak koduna karşılık gelmeyen imzalı yapay nesneler üretmiştir. İmzalar doğrudan yapay nesne üzerinden doğrulandığı için tüm imza kontrolleri başarıyla geçmiştir.
Tekrarlanabilir bir derlemenin kanıtlamadığı durumlar
Bu kısım genellikle olduğundan fazla abartıldığı için sınırları konusunda kesin olmak gerekir.
- Kaynak kodun güvenli olduğunu söylemez. Açık kaynak koduna eklenen bir arka kapı (backdoor) tekrarlanabilir şekilde derlenir ve tüm yeniden derleyiciler aynı kötü niyetli kaynağı derledikleri için bunu doğrular. Tekrarlanabilirlik, odak noktasını kaynak ağacına kaydırır. O ağacın birileri tarafından incelenmesi gerekir; bu nedenle açık kaynak projelerinde yapay zeka destekli kod politikaları dahil olmak üzere inceleme politikaları ayrı bir kontrol mekanizması olarak kalmaya devam eder.
- Girdilerinizin güvenli olduğunu söylemez. Bağımlılıklar, derlediğiniz şeyin bir parçasıdır. Derleme sırasında çözümlenen kötü niyetli bir paket, oluşturulan yapıya (artifact) dahil edilir ve aynı bağımlılığı çözümleyen her yeniden derleyici sizinle aynı sonucu verir. Bir npm tedarik zinciri saldırısının sunucuya ulaşması bu şekilde gerçekleşir ve tekrarlanabilir bir derleme bunu sadakatle yeniden üretir.
- Araç zincirinin (toolchain) dürüst olduğunu söylemez. Eğer derleyici (compiler) ele geçirilmişse, o derleyiciyi kullanan her yeniden derleyici aynı bozulmuş çıktıyı üretir ve tüm doğrulama sonuçları birbiriyle uyumlu olur. Tekrarlanabilirlik, bu tür bir saldırının maliyetini artırır ancak saldırıyı tespit etmez.
- Güvenlik açıkları hakkında hiçbir şey söylemez. Bit düzeyinde yeniden üretilmiş eski bir kütüphane, yayınlanmış kusurlarıyla birlikte hala eski bir kütüphanedir; bu nedenle sunucunuzu bilinen CVE'ler için tarama işlemini kendi takviminize göre yapmaya devam edin.
Tekrarlanabilirliğin ortadan kaldırdığı şey, belirli bir saldırgan konumudur: derleme makinesi ve kaynak koddan ikili dosyaya (binary) giden yolun tamamı. Bir paket tekrarlanabilir hale gelene kadar, yayıncı dışındaki hiç kimse bu yolu denetleyemez.
Aynı kaynak neden farklı baytlar üretir
Çoğu yazılım varsayılan olarak yeniden üretilebilir değildir ve bunun nedenleri oldukça basittir. Derleyiciler ve arşiv formatları, onları çalıştıran makineye dair verileri kaydeder.
- Zaman damgası.
tar,arvezipformatları dosya değiştirme zamanlarını saklar; bu nedenle farklı bir saniyede derleme yapmak çıktı dosyasını değiştirir. - Yol bilgisi. Hata ayıklama bilgileri mutlak derleme dizinini kaydeder; bu nedenle kod aynı olsa bile
/home/alice/srciçindeki bir derleme ile/build/pkgiçindeki bir derleme birbirinden farklı olur. - Sıralama. Bir dizini okumak, girdileri dosya sistemi sırasına göre döndürür; bu nedenle bağlantı satırı veya arşiv üye sırası makineler arasında değişebilir.
- Kimlik bilgisi. Derleme betikleri, derlemeyi yapan kişinin kullanıcı adını, ana makine adını veya yerel ayarlarını gömer.
- Derleme zamanında alınan kararlar. CPU özelliklerini algılamak veya rastgele bir değer üretmek, çıktının kaynaktan ziyade makineye bağlı olmasına neden olur.
İlk nedenin gerçekleştiğini yaklaşık on saniye içinde gözlemleyebilirsiniz:
mkdir -p /tmp/rb && cd /tmp/rb
echo hello > a.txt && tar cf one.tar a.txt
sleep 2
echo hello > a.txt && tar cf two.tar a.txt
sha256sum one.tar two.tarİki hash değerinin farklı olmasının nedeni, tar başlığının a.txt dosyasının değiştirilme zamanını saklaması ve dosyayı yeniden yazmanın bu zamanı iki saniye ileri taşımasıdır. İçerik, bayt bazında tamamen aynıdır. Meta verileri sabitlemek bu sorunu çözer:
export SOURCE_DATE_EPOCH=1700000000
tar --sort=name --mtime="@${SOURCE_DATE_EPOCH}" --owner=0 --group=0 --numeric-owner -cf three.tar a.txt
touch a.txt
tar --sort=name --mtime="@${SOURCE_DATE_EPOCH}" --owner=0 --group=0 --numeric-owner -cf four.tar a.txt
sha256sum three.tar four.tarArtık hash değerleri eşleşiyor, çünkü arşiv başlığındaki hiçbir alan makinenin o anki durumundan gelmiyor. --sort=name sıralamayı, --mtime ise saati sabitler; sahiplik bayrakları ise kullanıcı kimliğinizin kaydedilmesini engeller.
diffoscope ile farkları okuma
İki derleme birbirinden farklı olduğunda, sha256sum size sadece farklı olduklarını söyler, başka bir bilgi vermez. diffoscope, neden farklı olduklarını bir insanın okuyabileceği şekilde açıklamak için geliştirilmiştir. Her iki tarafı özyinelemeli olarak açar, ikili biçimleri metne dönüştürür ve metinleri karşılaştırır. Debian paketlerini, ELF ikili dosyalarını, tar ve ZIP arşivlerini, PDF'leri, SQLite veritabanlarını ve yüzden fazla başka biçimi destekler.
sudo apt install -y diffoscope
diffoscope one.tar two.tarYukarıdaki tar çifti için rapor kısadır. Kırpılmış hali şu şekildedir:
--- one.tar
+++ two.tar
├── file list
│ @@ -1 +1 @@
│ -rw-r--r-- 0/0 6 2026-08-18 10:14:02.000000 a.txt
│ +rw-r--r-- 0/0 6 2026-08-18 10:14:04.000000 a.txtTüm teşhis budur: aynı boyut, aynı yol, aynı izinler, farklı değiştirilme zamanı. Gerçek bir paket çok daha uzun bir rapor üretir; bu nedenle raporu bir dosyaya yazdırıp tarayıcıda açın:
diffoscope --html report.html build1.changes build2.changesdiffoscope, girdiler aynı olduğunda 0, farklı olduğunda 1, bir sorunla karşılaştığında ise 2 çıkış kodu döndürür; bu sayede herhangi bir sarmalayıcı betiğe ihtiyaç duymadan doğrudan bir CI işine entegre edilebilir. Küçük bir VPS üzerinde, diffoscope yerine diffoscope-minimal paketini kurun: tam paket, muhtemelen hiçbir zaman kullanmayacağınız çok sayıda biçim yardımcısını da beraberinde getirir.
SOURCE_DATE_EPOCH neyi düzeltir ve nerede durur
SOURCE_DATE_EPOCH, tek bir sayı tutan bir ortam değişkenidir: kaynağın son değişiklik zamanı, 1 Ocak 1970 UTC'den itibaren geçen saniye cinsinden hesaplanır. Bunu destekleyen bir derleme aracı, normalde işletim sisteminden o anki zamanı isteyeceği her yerde bu sayıyı kullanır. Değeri derlemeye değil kaynağa bağlamak için bunu sürüm kontrol sisteminden ayarlayın:
export SOURCE_DATE_EPOCH=$(git log -1 --pretty=%ct)Debian paketlerinde debhelper, bunu changelog dosyasından sizin için dışa aktarır. debian/rules içinde manuel olarak ayarlamak şu şekilde görünür:
export SOURCE_DATE_EPOCH ?= $(shell dpkg-parsechangelog -STimestamp)Destek araca özeldir, genel değildir. cmake 3.8 ve üzeri, gcc 7 ve üzeri, rpm 4.13 üzeri ve Docker buildx 0.10 ve üzeri sürümlerin tümü bunu okur. Kendi betikleriniz, siz kodlamadığınız sürece bunu okumaz. Eğer bir betik date çağırıyorsa, değişkeni şu şekilde besleyin:
BUILD_DATE="$(date --utc --date="@${SOURCE_DATE_EPOCH:-$(date +%s)}" +%Y-%m-%d)"Uygulama yaparken tek bir kural önemlidir. Değişken zaten ayarlanmışsa, derlemeniz için o değer o anki zamandır; bu nedenle çağırıcı tarafından verilen değeri asla üzerine yazmayın.
Container imajları aynı sorunu farklı bir sarmalayıcı içinde yaşar. Docker buildx 0.10 ve üzeri sürümler, SOURCE_DATE_EPOCH değerini shell ortamınızdan derleme argümanı olarak derlemeye aktarır. Katmanların içindeki dosyalarda bulunan zaman damgalarının yeniden yazılması için dışa aktarıcının (exporter) bunu desteklemesi gerekir; BuildKit bunu 0.13 sürümünde eklemiştir ve belgelenen yöntem sonucu bir registry'ye iter:
export SOURCE_DATE_EPOCH=$(git log -1 --pretty=%ct)
docker buildx build --output type=image,name=registry.example.com/app:1.0,push=true,rewrite-timestamp=true .reprotest ile kendi derlemenizi test etme
reprotest, aynı kaynak kodunu iki kez derler, derlemeler arasında ortamı kasıtlı olarak değiştirir ve sonuçları karşılaştırır. Varyasyonlar bu sürecin temelidir. Varsayılan olarak derleme yolu, zaman, saat dilimi, yerel ayar, umask, ana makine adı, kullanıcı ve grup, CPU sayısı, ev dizini ve dosya sıralaması gibi değişkenleri değiştirir.
sudo apt install -y reprotest
reprotest . -- null-- sonrasındaki her şey derleme ortamı arka ucunu seçer; null ise üzerinde çalıştığınız sistemi ifade eder. Geçici dizinleri incelemek üzere tutmak için reprotest . -vv -- null -d örneğinde olduğu gibi -vv -d parametresini ekleyin. Kaynak ağacının türünü otomatik olarak algılaması için reprotest auto -- null kullanın.
Bazı varyasyonlar ayrıcalık veya ek paketler gerektirir; çalıştırılamadıklarında belirgin hata mesajları verirler. Tüm süreci root yetkileriyle çalıştırmak yerine bu varyasyonları devre dışı bırakın:
reprotest --vary=-user_group,-domain_host,-fileordering auto -- nullreprotest tarafından bildirilen her sorun, daha sonra bir yeniden derleyici tarafından herkese açık olarak ve projenizin adıyla raporlanacak bir sorundur.
Yeniden oluşturucu (rebuilder) kararı ne anlama gelir
Yeniden oluşturucu, yayıncının makinesi olmayan bir makinedir. Yayınlanan kaynağı ve kaydedilmiş derleme ortamını alır, paketi tekrar derler ve kendi çıktısını arşivdeki yapıtla karşılaştırır. Karar, yalnızca makine bağımsız olduğu için bir değer taşır.
Debian, ortamı .buildinfo dosyasında kaydeder ve dpkg-buildpackage bunu .deb dosyasının yanına yazar. Alanlar işin ilginç kısmıdır. Installed-Build-Depends, derlemeyi etkileyebilecek her yüklü paketi tam sürümleriyle listeler. Build-Path, derlemenin nerede çalıştığını kaydeder. Environment, önemli olduğu bilinen ortam değişkenlerini kaydeder. Checksums-Sha256 ise çıktıları kapsar. Bu dosya, ikinci bir deneme için reçetedir:
sudo apt install -y devscripts mmdebstrap
debrebuild --buildresult=./artifacts --builder=mmdebstrap hello_2.10-2_amd64.buildinfodebrebuild, buildinfo dosyasını okur ve içinde belirtilen tam bağımlılık sürümlerini snapshot.debian.org üzerinden çeker; böylece bugün yapılan bir yeniden derleme, orijinal derlemenin yapıldığı gün mevcut olan paket sürümlerini kullanabilir. mmdebstrap derleyicisi, chroot kurulumuna veya süper kullanıcı haklarına ihtiyaç duymaz. Ürettiği yapıtları, diffoscope kullanarak arşiv kopyasıyla karşılaştırın.
Arch Linux, bunu sürekli olarak yapan ve kararları yayınlayan rebuilderd aracını çalıştırır:
rebuildctl -H https://reproducible.archlinux.org pkgs ls --name rebuilderdDurumlar GOOD, BAD ve UNKWN şeklindedir ve her birinin düz okuması farklı bir yönde yanlıştır. GOOD, bağımsız bir tarafın aynı baytları elde ettiği anlamına gelir; bu, derleme hakkında güçlü bir ifadeyken, kaynak hakkında hiçbir şey ifade etmez. BAD neredeyse hiçbir zaman bir saldırı değildir: yaygın neden, paketlemenin sabitlemeyi unuttuğu bir zaman damgası veya yoldur; bu yüzden rebuilderd, hataya bir diffoscope raporu ekleyebilir. UNKWN, kimsenin test etmediği anlamına gelir ve test edilmemiş bir paket, onaylanmış bir paket değildir.
Bu nedenle operasyonel kural kısadır. BAD kararı, raporu okumak için bir nedendir. Rapor zaman damgalarını, derleme yollarını veya üye sıralamasını gösteriyorsa, bir paketleme hatası kaydı açın. Eğer bu tür bir açıklama olmaksızın farklı yürütülebilir kod gösteriyorsa, o derlemeyi dağıtmayı durdurun ve durumu üst birimlere bildirin.
Debian şu anda ne kadar tekrarlanabilir?
The data behind this chart
[
{
"label": "unstable",
"percent_reproducible": 94.2,
"tested_count": "41,163"
},
{
"label": "forky",
"percent_reproducible": 93.4,
"tested_count": "39,059"
},
{
"label": "experimental",
"percent_reproducible": 67.0,
"tested_count": "588"
}
]Bu yazının kaleme alındığı gün, amd64 mimarisindeki unstable sürümü, test edilen 41,163 paket genelinde 94.2% oranında tekrarlanabilirdi. Experimental sürümü ise, henüz düzeltme çalışmaları tamamlanmamış paketlerden oluşan 588 adetlik çok daha küçük ve yeni bir örneklem üzerinde 67.0% oranındaydı.
Bu veriler, 2026-08-18 tarihinde "Son güncelleme: 2026-08-18 16:02 UTC" damgasıyla görüntülenen tests.reproducible-builds.org adresindeki Debian sayfasından alınmıştır. Bu oranlar değişkenlik gösterir. Altı ay sonra bu paragrafı alıntılamak yerine takip sistemini kontrol edin.
Yüzde oranından daha önemli bir uyarı bulunmaktadır. Bu çerçeve, her paketi kendi donanımı üzerinde iki kez derler, iki derleme arasında ortamı değiştirir ve elde edilen iki sonucu karşılaştırır. Bu işlem, bir paketin tekrarlanabilir şekilde derlenip derlenemeyeceğini ölçer. Bu, arşivde bulunan .deb dosyasının yayınlanan yapıtla eşleşip eşleşmediğini kontrol eden bir mekanizma değildir; bu, yayınlanmış yapıtla karşılaştırma yapan bir yeniden derleyicinin (rebuilder) ayrı bir görevidir. Her iki veri de faydalıdır. Farklı sorulara yanıt verirler; ancak insanlar genellikle ilkini ikincisiymiş gibi alıntılamaktadır.
Kendi sunucunuzda yapmanız gerekenler
Bir dağıtımı yeniden oluşturmayacaksınız. Sıradan bir sunucuya aktarılan parçalar daha küçük ve ucuzdur.
- Araç zincirini (toolchain) sabitleyin. Etiketle referans verilen bir temel imaj, siz fark etmeden değişebilir. İmajı digest değeriyle referans alın ve bu değeri sürüm kaydına ekleyin.
- Girdileri kaydedin. Lockfile dosyasını, imaj digest değerini ve derleyici sürümünü artifact ile birlikte saklayın. Ortamını yeniden oluşturamadığınız bir yapı (build) tekrar derlenemez, dolayısıyla asla denetlenemez.
- CI sürecinde iki kez derleme yapın ve çıktılar farklı olduğunda işi başarısız sayın. Bu, bir ekstra derleme maliyetiyle, belirsizliği (nondeterminism) bir yıl sonra bir olay anında değil, sisteme girdiği gün yakalamanızı sağlar.
- Derleyicinin gömdüğü yolları temizleyin. Go için
go build -trimpath -buildvcs=falsederleme dizinini ve sürüm kontrol damgasını kaldırır,go version -m ./appise ikili dosyada (binary) gerçekte neyin kaldığını yazdırır. - Dağıttığınız şeyin hash değerini saklayın. Çalışan ikili dosyanın bir kaynak revizyonuna karşılık gelip gelmediğini bilmeniz gerektiğinde, bu kayıt yanıt verebilecek tek şeydir.
CI kontrolü dört satırdan oluşur:
set -eu
./build.sh && mv dist/app app.1
./build.sh && mv dist/app app.2
diffoscope --text - app.1 app.2diffoscope, iki artifact birbirinden farklı olduğunda sıfır olmayan bir çıkış kodu döndürür; böylece iş kendiliğinden başarısız olur ve günlük kayıtlarında okunabilir bir açıklama bırakır. Tüm fikir, tek bir depoya indirgenmiş olarak budur: bir ikili dosyanın bir kaynak ağacından geldiği iddiası, ikinci bir makinenin doğrulayabileceği bir şey olmalıdır.
FAQ
Yeniden üretilebilir (reproducible) bir derleme, yazılımın güvenli olduğu anlamına mı gelir?
Hayır. Bu durum, yalnızca ikili dosyanın kaynak kodla eşleştiğini kanıtlar, başka bir şey değil. Genel kaynak ağacına işlenmiş bir arka kapı (backdoor) yeniden üretilebilir şekilde derlenir ve her yeniden derleyici, aynı kötü niyetli kaynağı derlediği için bunu doğrular. Bilinen bir CVE içeren bir paket mükemmel şekilde yeniden üretilir ve savunmasız kalmaya devam eder. Yeniden üretilebilirlik, saldırganın elindeki bir avantajı, yani derleme makinesini ve kaynak koddan ikili dosyaya giden yolu ortadan kaldırır. Kaynak kodu okumak ve güvenlik açıklarını takip etmek, yeniden üretilebilirliğin sizin yerinize yapmadığı ayrı işlerdir.
Kaynak kodda hiçbir şey değişmediği halde neden iki derlemem birbirinden farklı?
Neredeyse her zaman bir zaman damgası, bir yol veya bir sıralama farkından kaynaklanır. tar ve zip gibi arşiv formatları dosya değiştirme zamanlarını saklar; bu nedenle farklı bir saniyede yapılan checkout işlemi farklı baytlar üretir. Hata ayıklama bilgileri mutlak derleme dizinini kaydeder, bu yüzden /home/alice/src ve /build/pkg aynı koddan farklı ikili dosyalar üretir. Dizin okuma işlemleri, dosya sistemi sırasına göre girdi döndürür; bu nedenle bir bağlantı satırındaki nesne dosyaları başka bir makinede farklı şekilde sıralanabilir. diffoscope build1 build2 komutunu çalıştırın; rapor, tahmin yürütmenize gerek kalmadan sorunun hangisi olduğunu size söyleyecektir.
SOURCE_DATE_EPOCH nedir ve bunu ayarlamam gerekir mi?
Bu, tek bir sayı tutan standart bir ortam değişkenidir: kaynağın son değiştirilme zamanı, 1 Ocak 1970 UTC'den itibaren geçen saniye cinsinden. Bunu dikkate alan araçlar, aksi takdirde sistem saatini okuyacakları her yerde bu değeri kullanırlar. Bunu sürüm kontrol sisteminden export SOURCE_DATE_EPOCH=$(git log -1 --pretty=%ct) ile ayarlayın. Otomatik değildir ve genel bir çözüm değildir. Yalnızca bunu uygulayan araçlar bu değeri okur ve kendi derleme betikleriniz de bunu kendileri okumalıdır; bu nedenle date komutunu çağıran bir betik, siz değiştirene kadar geçerli zamanı damgalamaya devam eder.
Bir yeniden derleyici (rebuilder) BAD raporu verdiğinde ne yapmalıyım?
Başka bir şey yapmadan önce raporu okuyun. BAD kararı, bağımsız bir yeniden derlemenin aynı baytları üretmediği anlamına gelir ve bunun olağan nedeni bir saldırıdan ziyade paketlemedeki deterministik olmayan durumlardır. rebuilderd tam da bu nedenle bir diffoscope raporu oluşturabilir. Eğer farklar zaman damgaları, derleme yolları veya dosya sıralaması ise, bu bildirilmesi gereken bir paketleme hatasıdır. Eğer fark, bu tür bir açıklaması olmayan yürütülebilir kod ise, o derlemeyi dağıtmayı durdurun, yapıları (artifacts) saklayın ve durumu yayıncıya bildirin.