feat: add blog #7
1
Gemfile
1
Gemfile
|
@ -1,2 +1,3 @@
|
||||||
source "https://rubygems.org"
|
source "https://rubygems.org"
|
||||||
gem "jekyll-theme-console", path: "./_vendor/jekyll-theme-console"
|
gem "jekyll-theme-console", path: "./_vendor/jekyll-theme-console"
|
||||||
|
gem 'jekyll-feed'
|
|
@ -30,6 +30,7 @@ header_pages:
|
||||||
- about.md
|
- about.md
|
||||||
- services.md
|
- services.md
|
||||||
- tools.md
|
- tools.md
|
||||||
|
- blog.md
|
||||||
- contact.md
|
- contact.md
|
||||||
|
|
||||||
style: dark # dark (default), light or hacker
|
style: dark # dark (default), light or hacker
|
||||||
|
@ -37,9 +38,13 @@ listen_for_clients_preferred_style: false # false (default) or true
|
||||||
|
|
||||||
footer: '2023 Distrust, LLC'
|
footer: '2023 Distrust, LLC'
|
||||||
|
|
||||||
# Build settings
|
|
||||||
theme: jekyll-theme-console
|
theme: jekyll-theme-console
|
||||||
|
|
||||||
|
permalink: blog/:title.html
|
||||||
|
|||||||
|
|
||||||
|
plugins:
|
||||||
|
- jekyll-feed
|
||||||
|
|
||||||
# Exclude from processing.
|
# Exclude from processing.
|
||||||
# The following items will not be processed, by default.
|
# The following items will not be processed, by default.
|
||||||
# Any item listed under the `exclude:` key here will be automatically added to
|
# Any item listed under the `exclude:` key here will be automatically added to
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
<footer style="height: 40px">
|
<footer style="height: 40px">
|
||||||
<span><img src="assets/base/distrust-white.svg" width="20px" alt="copyleft"/></span> {{ site.footer }}
|
<span><img src="/assets/base/distrust-white.svg" width="20px" alt="copyleft"/></span> {{ site.footer }}
|
||||||
anton marked this conversation as resolved
Outdated
danny
commented
This should use site absolute path
This should use site absolute path
```
/assets/base/distrust-white.svg
```
danny
commented
Would be good to use the jekyll built-in function for static assets Would be good to use the jekyll built-in function for static assets
|
|||||||
<script type="text/javascript" src="/assets/js/main.js"></script>
|
<script type="text/javascript" src="/assets/js/main.js"></script>
|
||||||
</footer>
|
</footer>
|
||||||
|
|
|
@ -35,6 +35,9 @@
|
||||||
<div>
|
<div>
|
||||||
<a href="/tools.html">Tools</a>
|
<a href="/tools.html">Tools</a>
|
||||||
</div>
|
</div>
|
||||||
|
<div>
|
||||||
|
<a href="/blog.html">Blog</a>
|
||||||
|
</div>
|
||||||
<div>
|
<div>
|
||||||
<a href="/contact.html">Contact</a>
|
<a href="/contact.html">Contact</a>
|
||||||
</div>
|
</div>
|
||||||
|
|
|
@ -3,7 +3,7 @@
|
||||||
<div class="menu">
|
<div class="menu">
|
||||||
<div>
|
<div>
|
||||||
<a id="home-link" href="/index.html">
|
<a id="home-link" href="/index.html">
|
||||||
<img class="menu-logo" src="assets/base/distrust-text-white.svg"
|
<img class="menu-logo" src="/assets/base/distrust-text-white.svg"
|
||||||
anton marked this conversation as resolved
Outdated
danny
commented
Same here Same here
|
|||||||
alt="Distrust broken chain logo with white text" />
|
alt="Distrust broken chain logo with white text" />
|
||||||
</a>
|
</a>
|
||||||
</div>
|
</div>
|
||||||
|
@ -20,6 +20,12 @@
|
||||||
<li class="show">
|
<li class="show">
|
||||||
<a href="/contact.html" class="action-button">Free Consultation</a>
|
<a href="/contact.html" class="action-button">Free Consultation</a>
|
||||||
</li>
|
</li>
|
||||||
|
<li class="show">
|
||||||
|
<a href="/feed.xml" style="vertical-align: middle;">
|
||||||
|
<img style="filter: grayscale(100%); width: 22px; vertical-align: sub" src="/assets/base/rss.png" />
|
||||||
|
</a>
|
||||||
|
</li>
|
||||||
|
|
||||||
</ul>
|
</ul>
|
||||||
<div id="hamburger-menu" class="hide menu-button-container" for="menu-toggle">
|
<div id="hamburger-menu" class="hide menu-button-container" for="menu-toggle">
|
||||||
<input id="menu-toggle" type="checkbox" />
|
<input id="menu-toggle" type="checkbox" />
|
||||||
|
|
|
@ -8,7 +8,7 @@
|
||||||
{%- include header.html -%}
|
{%- include header.html -%}
|
||||||
|
|
||||||
<main>
|
<main>
|
||||||
<section class="flex-container">
|
<section class="flex-container extra-spacing">
|
||||||
<div class="flex-container-inner">
|
<div class="flex-container-inner">
|
||||||
<div class="text-well">
|
<div class="text-well">
|
||||||
<h2>Understand and mitigate security threats others won't see coming.</h2>
|
<h2>Understand and mitigate security threats others won't see coming.</h2>
|
||||||
|
@ -22,14 +22,21 @@
|
||||||
<div id="carousel"></div>
|
<div id="carousel"></div>
|
||||||
<br>
|
<br>
|
||||||
<div style="margin-left: 10px; font-size: 14px">
|
<div style="margin-left: 10px; font-size: 14px">
|
||||||
<a style="color: rgb(73, 73, 73)" href="../assets/js/carousel-items.json">Full list of articles</a>
|
<a style="color: rgb(73, 73, 73)" href="/assets/js/carousel-items.json">Full list of articles</a>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</section>
|
</section>
|
||||||
|
|
||||||
<hr />
|
<!-- <div>
|
||||||
|
<a href="{{ site.posts.first.url }}">
|
||||||
|
<img id="lp-post-img" src="{{ site.posts.first.cover_image }}"
|
||||||
|
alt="Cover image for {{ site.posts.first.title }}">
|
||||||
|
<h2>Latest Post: {{ site.posts.first.title }}</h2>
|
||||||
|
</a>
|
||||||
|
</div> -->
|
||||||
|
|
||||||
<section class="">
|
|
||||||
|
<section class="extra-spacing">
|
||||||
<div class="flex-container-inner">
|
<div class="flex-container-inner">
|
||||||
<div class="text-well">
|
<div class="text-well">
|
||||||
<h2>We specialize in working with high risk clients.</h2>
|
<h2>We specialize in working with high risk clients.</h2>
|
||||||
|
@ -43,94 +50,92 @@
|
||||||
<div class="companies">
|
<div class="companies">
|
||||||
<div>
|
<div>
|
||||||
<a href="https://coinbase.com">
|
<a href="https://coinbase.com">
|
||||||
<img style="height: 30px" src="assets/base/companies/coinbase-white.svg" />
|
<img style="height: 30px" src="/assets/base/companies/coinbase-white.svg" />
|
||||||
</a>
|
</a>
|
||||||
</div>
|
</div>
|
||||||
<div>
|
<div>
|
||||||
<a href="https://bitgo.com">
|
<a href="https://bitgo.com">
|
||||||
<img src="assets/base/companies/bitgo-logo-white.svg" />
|
<img src="/assets/base/companies/bitgo-logo-white.svg" />
|
||||||
</a>
|
</a>
|
||||||
</div>
|
</div>
|
||||||
<div>
|
<div>
|
||||||
<a href="https://bishopfox.com">
|
<a href="https://bishopfox.com">
|
||||||
<img style="height: 30px; filter: invert(100%) sepia(100%) saturate(0%) hue-rotate(288deg) brightness(102%) contrast(102%);" src="assets/base/companies/bishop-fox-dark.png" />
|
<img style="height: 30px; filter: invert(100%) sepia(100%) saturate(0%) hue-rotate(288deg) brightness(102%) contrast(102%);" src="/assets/base/companies/bishop-fox-dark.png" />
|
||||||
</a>
|
</a>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="companies">
|
<div class="companies">
|
||||||
<div>
|
<div>
|
||||||
<a href="http://www.falconx.io/">
|
<a href="http://www.falconx.io/">
|
||||||
<img style="height: 20px" src="assets/base/companies/falconx-white.svg" />
|
<img style="height: 20px" src="/assets/base/companies/falconx-white.svg" />
|
||||||
</a>
|
</a>
|
||||||
</div>
|
</div>
|
||||||
<div>
|
<div>
|
||||||
<a href="http://www.turnkey.io/">
|
<a href="http://www.turnkey.io/">
|
||||||
<img style="filter: invert(100)" src="assets/base/companies/turnkey-black.svg" />
|
<img style="filter: invert(100)" src="/assets/base/companies/turnkey-black.svg" />
|
||||||
</a>
|
</a>
|
||||||
</div>
|
</div>
|
||||||
<div>
|
<div>
|
||||||
<a href="https://exodus.com">
|
<a href="https://exodus.com">
|
||||||
<img src="assets/base/companies/exodus-white.svg" />
|
<img src="/assets/base/companies/exodus-white.svg" />
|
||||||
</a>
|
</a>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="companies">
|
<div class="companies">
|
||||||
<div>
|
<div>
|
||||||
<a href="https://siderolabs.com">
|
<a href="https://siderolabs.com">
|
||||||
<img style="height: 60px" src="assets/base/companies/sidero-labs-white.png" />
|
<img style="height: 60px" src="/assets/base/companies/sidero-labs-white.png" />
|
||||||
</a>
|
</a>
|
||||||
</div>
|
</div>
|
||||||
<div>
|
<div>
|
||||||
<a href="https://zoom.com">
|
<a href="https://zoom.com">
|
||||||
<img style="height: 35px;" src="assets/base/companies/zoom-white.png" />
|
<img style="height: 35px;" src="/assets/base/companies/zoom-white.png" />
|
||||||
</a>
|
</a>
|
||||||
</div>
|
</div>
|
||||||
<div>
|
<div>
|
||||||
<a href="https://mystenlabs.com">
|
<a href="https://mystenlabs.com">
|
||||||
<img style="height: 25px" src="assets/base/companies/mysten-labs-white.svg" />
|
<img style="height: 25px" src="/assets/base/companies/mysten-labs-white.svg" />
|
||||||
</a>
|
</a>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="companies">
|
<div class="companies">
|
||||||
<div>
|
<div>
|
||||||
<a href="http://www.ankr.com/">
|
<a href="http://www.ankr.com/">
|
||||||
<img style="height: 75px; filter: invert(100%) sepia(100%) saturate(0%) hue-rotate(288deg) brightness(200%) contrast(102%);" src="assets/base/companies/ankr.png" />
|
<img style="height: 75px; filter: invert(100%) sepia(100%) saturate(0%) hue-rotate(288deg) brightness(200%) contrast(102%);" src="/assets/base/companies/ankr.png" />
|
||||||
</a>
|
</a>
|
||||||
</div>
|
</div>
|
||||||
<div>
|
<div>
|
||||||
<a href="http://www.hashicorp.io/">
|
<a href="http://www.hashicorp.io/">
|
||||||
<img style="height: 60px" src="assets/base/companies/hashicorp-white.png" />
|
<img style="height: 60px" src="/assets/base/companies/hashicorp-white.png" />
|
||||||
</a>
|
</a>
|
||||||
</div>
|
</div>
|
||||||
<div>
|
<div>
|
||||||
<a href="http://www.b1.com/">
|
<a href="http://www.b1.com/">
|
||||||
<img style="filter: invert(100)" src="assets/base/companies/block-one-dark.svg" />
|
<img style="filter: invert(100)" src="/assets/base/companies/block-one-dark.svg" />
|
||||||
</a>
|
</a>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="companies">
|
<div class="companies">
|
||||||
<div>
|
<div>
|
||||||
<a href="http://www.ledn.io/">
|
<a href="http://www.ledn.io/">
|
||||||
<img src="assets/base/companies/ledn-white.svg" />
|
<img src="/assets/base/companies/ledn-white.svg" />
|
||||||
</a>
|
</a>
|
||||||
</div>
|
</div>
|
||||||
<div>
|
<div>
|
||||||
<a href="https://fitbit.com">
|
<a href="https://fitbit.com">
|
||||||
<img src="assets/base/companies/fitbit-white.png" />
|
<img src="/assets/base/companies/fitbit-white.png" />
|
||||||
</a>
|
</a>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div>
|
<div>
|
||||||
<a href="https://dfns.co">
|
<a href="https://dfns.co">
|
||||||
<img src="assets/base/companies/dfns-color.png" />
|
<img src="/assets/base/companies/dfns-color.png" />
|
||||||
</a>
|
</a>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</section>
|
</section>
|
||||||
|
|
||||||
<hr/>
|
|
||||||
|
|
||||||
<section class="">
|
<section class="">
|
||||||
<div class="flex-container-inner" style="align-items: baseline">
|
<div class="flex-container-inner" style="align-items: baseline">
|
||||||
<div class="text-well">
|
<div class="text-well">
|
||||||
|
|
|
@ -0,0 +1,27 @@
|
||||||
|
<!DOCTYPE html>
|
||||||
|
<html lang="{{ page.lang | default: site.lang | default: en }}">
|
||||||
|
|
||||||
|
{%- include head.html -%}
|
||||||
|
|
||||||
|
<body>
|
||||||
|
<div class="container">
|
||||||
|
|
||||||
|
{%- include header.html -%}
|
||||||
|
<article class="post">
|
||||||
|
<h1>{{ page.title }}</h1>
|
||||||
|
|
||||||
|
<div class="entry">
|
||||||
|
{{ content }}
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="date">
|
||||||
|
Written on {{ page.date | date: "%B %e, %Y" }}
|
||||||
|
</div>
|
||||||
|
|
||||||
|
</article>
|
||||||
|
|
||||||
|
{%- include footer.html -%}
|
||||||
|
</div>
|
||||||
|
</body>
|
||||||
|
|
||||||
|
</html>
|
|
@ -69,7 +69,7 @@
|
||||||
<section class="flex-container">
|
<section class="flex-container">
|
||||||
<div class="flex-container-inner">
|
<div class="flex-container-inner">
|
||||||
<div class="text-well">
|
<div class="text-well">
|
||||||
<h3>StageX</h3>
|
<h3>[Stage<sup>x</sup>]</h3>
|
||||||
anton marked this conversation as resolved
Outdated
danny
commented
To support more browsers I'd probably do
To support more browsers I'd probably do
```
[Stage<sup>x</sup>]
```
|
|||||||
<a href="https://codeberg.org/stagex/stagex" target="_blank" rel="noopener noreferrer">https://codeberg.org/stagex/stagex</a>
|
<a href="https://codeberg.org/stagex/stagex" target="_blank" rel="noopener noreferrer">https://codeberg.org/stagex/stagex</a>
|
||||||
<p>Minimalism and security first repository of reproducible and multi-signed OCI images of common open source software toolchains full-source bootstrapped from Stage 0 all the way up.</p>
|
<p>Minimalism and security first repository of reproducible and multi-signed OCI images of common open source software toolchains full-source bootstrapped from Stage 0 all the way up.</p>
|
||||||
</div>
|
</div>
|
||||||
|
|
|
@ -0,0 +1,298 @@
|
||||||
|
---
|
||||||
|
layout: post
|
||||||
|
title: Adventures In Supply Chain Integrity
|
||||||
|
date: 2024-03-28
|
||||||
|
cover_image: "/assets/images/whale_shark.jpg"
|
||||||
|
authors:
|
||||||
|
- name: Ryan Heywood
|
||||||
|
bio: Professional bonker / twerker.
|
||||||
|
twitter: le twitter
|
||||||
|
- name: Anton Livaja
|
||||||
|
bio: Professional banana juggler.
|
||||||
|
twitter: antonlivaja
|
||||||
|
- name: Lance R. Vick
|
||||||
|
bio: Dolphin trainer
|
||||||
|
twitter: no.
|
||||||
|
---
|
||||||
|
|
||||||
|
When a compiler is used to compile some piece of software, how do we verify
|
||||||
|
that the compiler can be trusted? Is it well known who compiled the compiler
|
||||||
|
itself? Usually compilers are not built from source, and even when they are,
|
||||||
|
they are seeded from a binary that itself is opaque and difficult to verify.
|
||||||
|
How does one check if the supply chain integrity of the compiler itself is
|
||||||
|
intact, even before we get to building software with it?
|
||||||
|
|
||||||
|
Compiler supply chains are obscured and at many points seeded from binaries,
|
||||||
|
making it nearly impossible to verify their integrity. In 1984, Ken Thompson
|
||||||
|
wrote "Reflections on Trusting Trust" and illustrated that a compiler can
|
||||||
|
modify software during the compilation process, compromising the software. Put
|
||||||
|
simply, this means that reviewing the source code is not enough. We need to be
|
||||||
|
sure that the compiler itself isn't compromised, as it could be used to modify
|
||||||
|
the intended behavior of the software.
|
||||||
|
|
||||||
|
What about the software that's built using the compiler? Has the source code
|
||||||
|
been modified during compilation? Has the resulting binary of the software been
|
||||||
|
tampered with, perhaps in the CI/CD runner which runs an OS with a
|
||||||
|
vulnerability in one of its sub dependencies? Or perhaps the server host has
|
||||||
|
been compromised and attackers have gained control of the infrastructure?
|
||||||
|
These are difficult software supply chain security issues which are often swept
|
||||||
|
under the rug or completely overlooked due to lack of understanding. To
|
||||||
|
eliminate this surface area of attack, we need a good answer to these
|
||||||
|
questions, and more importantly we need tooling and practical methods which can
|
||||||
|
help close these gaps in the supply chain.
|
||||||
|
|
||||||
|
This line of questioning becomes especially concerning in the context of widely
|
||||||
|
used software, such as images pulled from DockerHub, package managers, and
|
||||||
|
Linux distributions. Software procured via these channels are used widely and
|
||||||
|
are pervasive in almost all software and as such pose a severe attack vector.
|
||||||
|
If the maintainer of a widely used DockerHub image has their machine
|
||||||
|
compromised, or are coerced or even forced under duress to insert malicious
|
||||||
|
code into the binaries they are responsible for, there is no effective measure
|
||||||
|
in place to detect and catch this, resulting in millions of downstream
|
||||||
|
consumers being impacted. Imagine what would happen if the maintainer of a
|
||||||
|
default DockerHub image of a widely used language was compromised, and the
|
||||||
|
binary they released had a backdoor in it. The implications are extremely far
|
||||||
|
reaching, and would be disastrous.
|
||||||
|
|
||||||
|
There are two distinct problems at hand which share a solution:
|
||||||
|
|
||||||
|
1. How do we ensure that we can trust the toolchain used to build software
|
||||||
|
2. How do we ensure that we can trust software built with the toolchain
|
||||||
|
|
||||||
|
The answer to both questions is the same. We achieve it via verifiability and
|
||||||
|
determinism. To be clear, we are not trying to solve the problem of the code
|
||||||
|
itself being compromised in the source. If the source code is compromised,
|
||||||
|
determinism does not help prevent that. If the code is reviewed and verified as
|
||||||
|
being secure, then determinism and multiple reproductions of the software
|
||||||
|
add a set of excellent guarantees.
|
||||||
|
|
||||||
|
Deterministically built software is any software which always compiles to the
|
||||||
|
same bit-for-bit exact binary. This is useful because it makes it trivial to
|
||||||
|
check the integrity of the binary. If the binary is always the same, we can use
|
||||||
|
hashing to ensure that nothing about the binary has changed. Typically minor
|
||||||
|
differences which are introduced during the build process, such as time stamps,
|
||||||
|
mean that software is typically non-deterministic. By pinning all aspects of
|
||||||
|
the environment the software is built in and removing any changing factors such
|
||||||
|
as time and user or machine IDs, we can force the software to always be
|
||||||
|
bit-for-bit.
|
||||||
|
|
||||||
|
Now, imagine a scenario where a developer is compiling software, and they are
|
||||||
|
not doing it deterministically. Any time they build the software, they have no
|
||||||
|
way to easily verify if the binary changed in a meaningful way compared to the
|
||||||
|
previous one without doing low level inspection. With determinism, it's as
|
||||||
|
simple as hashing one binary, repeating the compilation, hashing the second
|
||||||
|
result, and comparing it with the original. This is great, but it's still not
|
||||||
|
enough to ensure that the binary can be trusted, as there may be malware which
|
||||||
|
always modifies the binary in the same manner. To mitigate this, we can build
|
||||||
|
the software on multiple different machines, ideally by different maintainers,
|
||||||
|
using different operating systems and even different hardware, as it's much
|
||||||
|
less likely that multiple diverse stacks and individuals are compromised by the
|
||||||
|
same malware or attacker. Following this process, we can eliminate the risk of
|
||||||
|
modification during compilation going undetected. To add a layer of trust that
|
||||||
|
the hashes can be trusted, we can use cryptographic signing, as is customary
|
||||||
|
for many software releases.
|
||||||
|
|
||||||
|
Assessing the current state of affairs regarding software package managers and
|
||||||
|
Linux distributions, and how far they have gone to mitigate these risks, we
|
||||||
|
performed an analysis of popular projects:
|
||||||
|
|
||||||
|
Alpine is the most popular Linux distribution (distro) in the container
|
||||||
|
ecosystem and has made great strides in providing a minimal `musl` based
|
||||||
|
distribution with reasonable security defaults and is suitable for a lot of use
|
||||||
|
cases, however in the interest of developer productivity and low friction for
|
||||||
|
contributors, none of it is cryptographically signed.
|
||||||
|
|
||||||
|
Debian (and derivatives like Ubuntu) is one of most popular option for servers
|
||||||
|
and is largely reproducible and also signs all packages. Being `glibc` based
|
||||||
|
with a focus on compatibility and desktop use cases, it results in a huge
|
||||||
|
number of dependencies for almost any software run on it, enacts partial code
|
||||||
|
freezes for long periods of time between releases, and often has very stale
|
||||||
|
packages as various compatibility goals block updates. This overhead introduces
|
||||||
|
a lot of surface area of malicious code to hide itself in. Unfortunately, due
|
||||||
|
to its design, when building software deterministically on this OS, each and
|
||||||
|
every repo needs to keep costly snapshots of all dependencies to reproduce
|
||||||
|
build containers, as Debian packages are archived and retired after some time
|
||||||
|
to servers with low bandwidth. This creates a lot of friction for teams who, as
|
||||||
|
a result, have to archive often hundreds of .deb files for every project, and
|
||||||
|
also has the added issue of Debian having very old versions of software such as
|
||||||
|
Rust, which is a common requirement. This can be quite problematic for teams
|
||||||
|
who want to access latest language features. Even with all this work, Debian
|
||||||
|
does not have truly reproducible Rust (which will be discussed later in this
|
||||||
|
post), and packages are signed only by single maintainers whom we have to fully
|
||||||
|
trust that they didn't release a compromised binary.
|
||||||
|
|
||||||
|
Fedora (and RedHat based distros) also sign all packages, but otherwise suffer
|
||||||
|
from similar one-size-fits-all bloat problems as Debian with a different coat
|
||||||
|
of paint. Additionally, their reliance on centralized builds has been used as
|
||||||
|
justification for them to not pursue reproducibility at all which makes them a
|
||||||
|
non-starter for security focused use cases.
|
||||||
|
|
||||||
|
Arch has very fast updates as a rolling release distro, and package definitions
|
||||||
|
are signed and often reproducible, but they change from one minute to the next,
|
||||||
|
still resulting in the challenge of having to come up with a solution to pin
|
||||||
|
and archive sets of dependencies that work well together for software that's
|
||||||
|
built using it and requires determinism.
|
||||||
|
|
||||||
|
Nix is almost entirely reproducible by design and allows for lean and minimal
|
||||||
|
output artifacts. It is also a big leap forward in having good separation of
|
||||||
|
concerns between privileged immutable and unprivileged mutable spaces, however
|
||||||
|
like Alpine there is no maintainer-level signing in order to reduce the
|
||||||
|
friction for hobbyist that wants to contribute.
|
||||||
|
|
||||||
|
Guix is reproducible by design as well, borrowing a lot from Nix. It also does
|
||||||
|
maintainer-level signing like Debian. It comes the closest to the solution we
|
||||||
|
need, but it only provides single signed package contributions, and a `glibc`
|
||||||
|
base with a large dependency tree, with a significant footprint of tooling to
|
||||||
|
review and understand to form confidence in it. This is still too much overhead
|
||||||
|
we simply don't want or need for use cases like container builds of software,
|
||||||
|
lean embedded operating systems, or any sensitive system where we want the
|
||||||
|
utmost level of supply chain security assurance.
|
||||||
|
|
||||||
|
For those whose goal is to build their own software packages deterministically
|
||||||
|
with high portability, maintainability, and maximally easy supply chain
|
||||||
|
auditability, none of these solutions hit the mark.
|
||||||
|
|
||||||
|
On reflecting on these issues, we concluded we want the `musl`-based
|
||||||
|
container-ideal minimalism of Alpine, the obsessive determinism and full-source
|
||||||
|
supply chain goals of Guix, and a step beyond the single-signature packages of
|
||||||
|
Debian, Fedora, and Arch. We also concluded that we want a fully verifiable
|
||||||
|
bootstrapped toolchain, consisting of a compiler and accompanying libraries
|
||||||
|
required for building most modern software.
|
||||||
|
|
||||||
|
You may know where this is going. Here is where we made the totally reasonable
|
||||||
|
and not-at-all-crazy choice to effectively create…
|
||||||
|
|
||||||
|
## Yet *Another* Linux Distribution
|
||||||
|
Let’s take a look at some of the features we care about most compared to make
|
||||||
|
it more clear why nothing else hit the mark for us.
|
||||||
|
|
||||||
|
A comparison of `stagex` to other distros in some of the areas we care about:
|
||||||
|
|
||||||
|
| Distro | Containerized | Signatures | Libc | Bootstrapped | Reproducible | Rust Deps |
|
||||||
|
|--------|---------------|------------|-------|--------------|--------------|-----------|
|
||||||
|
| Stagex | Native | 2+ Human | Musl | Yes | Yes | 4 |
|
||||||
|
| Guix | No | 1 Human | Glibc | Yes | Yes | 4 |
|
||||||
|
| Nix | No | 1 Bot | Glibc | Partial | Mostly | 4 |
|
||||||
|
| Debian | Adapted | 1 Human | Glibc | No | Partial | 232 |
|
||||||
|
| Arch | Adapted | 1 Human | Glibc | No | Partial | 262 |
|
||||||
|
| Fedora | Adapted | 1 Bot | Glibc | No | No | 166 |
|
||||||
|
| Alpine | Adapted | None | Musl | No | No | 32 |
|
||||||
|
|
||||||
|
We are leaving out hundreds of distros here, but at the risk of starting a holy
|
||||||
|
war, we felt it was useful to compare a few popular options for contrast to the
|
||||||
|
goals of the minimal container-first, security-first, deterministic distro we
|
||||||
|
put together.
|
||||||
|
|
||||||
|
We are not the first to go down this particular road road. The Talos Linux
|
||||||
|
project built their own tiny containerized toolchain from gcc to golang as the
|
||||||
|
base to build their own minimal immutable k8s distro.
|
||||||
|
|
||||||
|
Getting all the way to bootstrapping rust, however, is a much bigger chunk of
|
||||||
|
pain as we learned…
|
||||||
|
|
||||||
|
## The Oxidation Problem - Bootstrapping Rust
|
||||||
|
Getting from gcc all the way to golang was mostly pain-free, thanks to Google
|
||||||
|
documenting this path well and providing all the tooling to do it. One only
|
||||||
|
needs 3 versions of golang to get all the way back to GCC.
|
||||||
|
|
||||||
|
Bootstrapping Rust is a bit of an ordeal. People love Rust for its memory
|
||||||
|
safety and strictness, however we have noticed supply chain integrity is not
|
||||||
|
an area where it excels. This is mostly because Rust changes so much from one
|
||||||
|
release to the next, that a given version of Rust can only ever be built with
|
||||||
|
its immediate predecessor.
|
||||||
|
|
||||||
|
If one follows the chicken-and-egg problem far enough the realization dawns
|
||||||
|
that in most distros the chicken comes first. Most included a non-reproducible
|
||||||
|
“seed” Rust binary presumably compiled by some member of the Rust team, then
|
||||||
|
use that to build the next version, and then carry on from there. This means
|
||||||
|
even some of the distros that _say_ their Rust builds are reproducible have a
|
||||||
|
pretty big asterisk. We won’t call anyone out - you know who you are.
|
||||||
|
|
||||||
|
Granted, even if you were to build all the way up from the OCaml roots of Rust
|
||||||
|
(if you can find that code and then get it to build), you would still require a
|
||||||
|
trusted OCaml compiler. Software supply chains are hard, and we always end up
|
||||||
|
back at the famous Trusting Trust Problem.
|
||||||
|
|
||||||
|
There have been some amazing efforts by the Guix team to bootstrap GCC and the
|
||||||
|
entire package chain after it with a tiny human-auditable blob of x86 assembly
|
||||||
|
via the GNU Mes project. That is probably in the cards for our stack as well,
|
||||||
|
however for the short term we wanted to at least go as low in the stack as GCC
|
||||||
|
like we do with go as a start which is already a sizable effort. Thankfully,
|
||||||
|
John Hodge (mutabah), a brilliant (crazy?) member of the open source community,
|
||||||
|
created “mrustc” which implements a minimal semi-modern rust 1.54 compiler in
|
||||||
|
C++ largely from transpiled Rust code. It is missing a lot of critical features
|
||||||
|
that make it unsuitable for direct use, but it _does_ support enough features
|
||||||
|
to compile official Rust 1.55 sources, which can compile Rust 1.56 and so on.
|
||||||
|
This is the path Guix and Nix both went down, and we are taking their lead
|
||||||
|
here.
|
||||||
|
|
||||||
|
Mrustc at the time lacked support for musl libc which threw a wrench in things,
|
||||||
|
but after a fair bit of experimentation we were able to patch in support musl
|
||||||
|
and get it upstream.
|
||||||
|
|
||||||
|
The result is we now have the first deterministic `musl` based rust compiler
|
||||||
|
bootstrapped from 256 bytes of assembly, and you can reproduce our builds right
|
||||||
|
now from any OS that can run Docker 26.
|
||||||
|
|
||||||
|
## Determinism and Real World Applications
|
||||||
|
To demonstrate how determinism can be used to prevent real world attacks in
|
||||||
|
practical terms let's consider a major breach which could have been prevented.
|
||||||
|
|
||||||
|
SolarWinds experienced a major security breach in which Russian threat actors
|
||||||
|
were able to compromise their infrastructure and piggyback on their software to
|
||||||
|
distribute malware to their entire client base. The attackers achieved this by
|
||||||
|
injecting malicious code into SolarWinds products, such as the Orion Platform,
|
||||||
|
which was then downloaded by the end users. This seems like a very difficult
|
||||||
|
thing to protect from, but there is a surprisingly simple solution. If
|
||||||
|
SolarWinds leveraged deterministic builds of their software, they would have
|
||||||
|
been able to detect that the binaries of the software they are delivering to
|
||||||
|
their clients have been tampered.
|
||||||
|
|
||||||
|
To achieve this, there are a few ways they could have gone about this, but
|
||||||
|
without getting too deep into implementation details, it would have sufficed to
|
||||||
|
have multiple runners in different isolated environments, or even on different
|
||||||
|
cloud platforms, which would reproduce the deterministic build and compare the
|
||||||
|
resulting hashes in order to verify the binaries have not been tampered. If any
|
||||||
|
of the systems built the software and got a different hash - that would be a
|
||||||
|
clear signal that further investigations should be made which would have likely
|
||||||
|
lead to the detection of the intruder. Without this approach, SolarWinds was
|
||||||
|
completely unaware of their systems being infiltrated for months, and during
|
||||||
|
this period large quantities of end user data was exfiltrated, along with their
|
||||||
|
tooling. Considering SolarWinds is a cybersecurity software and services
|
||||||
|
provider, the tools stolen from them were then likely used to further develop
|
||||||
|
and weaponize the attacker's capabilities.
|
||||||
|
|
||||||
|
## Future Work
|
||||||
|
These initial efforts were predominately sponsored with financial and
|
||||||
|
engineering time contributions from Distrust, Mysten Labs, and Turnkey, who all
|
||||||
|
share threat models and container-driven workflows Stagex is designed to
|
||||||
|
support.
|
||||||
|
|
||||||
|
While we all have a vested interest to help maintain it, we all felt it
|
||||||
|
important this project stand on its own and belong to the community and are
|
||||||
|
immensely appreciative to a number of volunteers that have very quickly dived
|
||||||
|
in and started making significant contributions and improvements.
|
||||||
|
|
||||||
|
As of writing this, Stagex has 100+ packages covering some of the core software
|
||||||
|
you may be using regularly, all built using the deterministically built
|
||||||
|
toolchain, and of course the software itself also built deterministically. Some
|
||||||
|
of the packages include `rust`, `go`, `nodejs`, `python3.8`, `curl`, `bash`,
|
||||||
|
`git`, `tofu` and many more.
|
||||||
|
|
||||||
|
We would like to support building with `buildah` and `podman` for build-tooling
|
||||||
|
diversity. We would also love help from the open source community to see GCC
|
||||||
|
bootstrapped all the way down to x86_assembly via Mes. This may require using
|
||||||
|
multiple seed distro containers to work in parallel to ensure we don’t have a
|
||||||
|
single provenance source for that layer.
|
||||||
|
|
||||||
|
We are also actively on and have made some progress towards the addition of
|
||||||
|
core packages required to use this distribution as a minimal Linux OS.
|
||||||
|
|
||||||
|
If you have need for high trust in your own build system, please reach out and
|
||||||
|
we would love to find a way to collaborate.
|
||||||
|
|
||||||
|
## References
|
||||||
|
* [Bootstraping rust](https://guix.gnu.org/en/blog/2018/bootstrapping-rust/)
|
||||||
|
* [Full source bootstrappin](https://guix.gnu.org/en/blog/2023/the-full-source-bootstrap-building-from-source-all-the-way-down/)
|
||||||
|
* [Running the "Reflections on Trusting Trust" Compiler](https://research.swtch.com/nih)
|
||||||
|
* [Reflections on Trusting Trust](https://www.cs.cmu.edu/~rdriley/487/papers/Thompson_1984_ReflectionsonTrustingTrust.pdf)
|
|
@ -62,7 +62,7 @@ h4,
|
||||||
h5,
|
h5,
|
||||||
h6 {
|
h6 {
|
||||||
margin: 0px;
|
margin: 0px;
|
||||||
margin-top: 12px;
|
margin-top: 0px;
|
||||||
margin-bottom: 12px;
|
margin-bottom: 12px;
|
||||||
font-weight: bold;
|
font-weight: bold;
|
||||||
color: var(--text-color);
|
color: var(--text-color);
|
||||||
|
@ -103,23 +103,26 @@ a:hover {
|
||||||
}
|
}
|
||||||
|
|
||||||
p {
|
p {
|
||||||
|
/*
|
||||||
word-wrap: break-word;
|
word-wrap: break-word;
|
||||||
word-break: break-word;
|
word-break: break-word;
|
||||||
white-space: pre-wrap;
|
white-space: pre-wrap;
|
||||||
margin-bottom: 15px;
|
*/
|
||||||
|
margin-top: 16px;
|
||||||
|
margin-bottom: 16px;
|
||||||
}
|
}
|
||||||
|
|
||||||
footer {
|
footer {
|
||||||
color: var(--text-color);
|
color: var(--text-color);
|
||||||
border-top: var(--border);
|
border-top: var(--border);
|
||||||
margin-top: 0;
|
margin-top: 24px;
|
||||||
padding-top: 10px;
|
padding-top: 12px;
|
||||||
text-align: right;
|
text-align: right;
|
||||||
}
|
}
|
||||||
|
|
||||||
header {
|
header {
|
||||||
margin-top: 50px;
|
margin-top: 24px;
|
||||||
margin-bottom: 50px;
|
margin-bottom: 24px;
|
||||||
}
|
}
|
||||||
|
|
||||||
header p {
|
header p {
|
||||||
|
@ -147,10 +150,6 @@ hr {
|
||||||
text-decoration: none;
|
text-decoration: none;
|
||||||
}
|
}
|
||||||
|
|
||||||
.header-page-links {
|
|
||||||
margin-right: 10%;
|
|
||||||
}
|
|
||||||
|
|
||||||
.header-page-links li:before {
|
.header-page-links li:before {
|
||||||
content: ''
|
content: ''
|
||||||
}
|
}
|
||||||
|
@ -167,7 +166,7 @@ hr {
|
||||||
}
|
}
|
||||||
|
|
||||||
.right-menu {
|
.right-menu {
|
||||||
width: 70%;
|
width: 74%;
|
||||||
display: flex;
|
display: flex;
|
||||||
justify-content: flex-end;
|
justify-content: flex-end;
|
||||||
align-items: center;
|
align-items: center;
|
||||||
|
@ -450,7 +449,7 @@ textarea {
|
||||||
.flex-container {
|
.flex-container {
|
||||||
display: flex;
|
display: flex;
|
||||||
justify-content: space-between;
|
justify-content: space-between;
|
||||||
align-items: center;
|
align-items: flex-start;
|
||||||
}
|
}
|
||||||
|
|
||||||
.flex-container-inner {
|
.flex-container-inner {
|
||||||
|
@ -458,8 +457,13 @@ textarea {
|
||||||
}
|
}
|
||||||
|
|
||||||
section {
|
section {
|
||||||
padding-top: 100px;
|
margin-top: 24px;
|
||||||
padding-bottom: 100px;
|
margin-bottom: 24px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.extra-spacing {
|
||||||
|
margin-top: 70px;
|
||||||
|
margin-bottom: 70px;
|
||||||
}
|
}
|
||||||
|
|
||||||
.companies {
|
.companies {
|
||||||
|
@ -891,6 +895,19 @@ pre {
|
||||||
}
|
}
|
||||||
/** end carousel */
|
/** end carousel */
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Blog
|
||||||
|
*/
|
||||||
|
.post img {
|
||||||
|
max-width: 100%;
|
||||||
|
}
|
||||||
|
|
||||||
|
#lp-post-img {
|
||||||
|
max-width: 100%;
|
||||||
|
}
|
||||||
|
|
||||||
|
/** end blog */
|
||||||
|
|
||||||
*,
|
*,
|
||||||
*::before,
|
*::before,
|
||||||
*::after {
|
*::after {
|
||||||
|
|
Binary file not shown.
After Width: | Height: | Size: 6.3 KiB |
Binary file not shown.
After Width: | Height: | Size: 2.0 MiB |
|
@ -10,13 +10,15 @@ collapsibleButton.addEventListener("click", function () {
|
||||||
});
|
});
|
||||||
|
|
||||||
document.addEventListener('DOMContentLoaded', function () {
|
document.addEventListener('DOMContentLoaded', function () {
|
||||||
fetch('../assets/js/carousel-items.json')
|
if (window.location.pathname === "/index.html") {
|
||||||
|
fetch('/assets/js/carousel-items.json')
|
||||||
anton marked this conversation as resolved
Outdated
danny
commented
Absolute path Absolute path
|
|||||||
.then(response => response.json())
|
.then(response => response.json())
|
||||||
.then(data => {
|
.then(data => {
|
||||||
createCarouselItems(data);
|
createCarouselItems(data);
|
||||||
initializeCarousel();
|
initializeCarousel();
|
||||||
})
|
})
|
||||||
.catch(error => console.error('Error loading JSON:', error));
|
.catch(error => console.error('Error loading JSON:', error));
|
||||||
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
function createCarouselItems(items) {
|
function createCarouselItems(items) {
|
||||||
|
|
|
@ -0,0 +1,18 @@
|
||||||
|
---
|
||||||
|
layout: page
|
||||||
|
title: Blog
|
||||||
|
permalink: /blog.html
|
||||||
|
---
|
||||||
|
<div class="posts">
|
||||||
|
{% for post in site.posts %}
|
||||||
|
<article class="post">
|
||||||
|
<h1><a href="{{ post.url }}" title="{{ post.title }}">{{ post.title }}</a></h1>
|
||||||
anton marked this conversation as resolved
Outdated
danny
commented
I'd probably include the title in the link as well
I'd probably include the title in the link as well
```
<a ... title="{{ post.title}}>...</a>
```
|
|||||||
|
|
||||||
|
<div class="entry">
|
||||||
|
{{ post.excerpt }}
|
||||||
|
</div>
|
||||||
|
<h4>Written on {{ post.date | date: "%B %e, %Y" }}</h4>
|
||||||
|
<a href="{{ post.url }}" class="read-more">Read More</a>
|
||||||
anton marked this conversation as resolved
Outdated
danny
commented
Generally I'd avoid using the baseurl. This makes local development more difficult and prevents have multiple domains with the same content (eg. deploying as a Tor Hidden Service) Generally I'd avoid using the baseurl. This makes local development more difficult and prevents have multiple domains with the same content (eg. deploying as a Tor Hidden Service)
|
|||||||
|
</article>
|
||||||
|
{% endfor %}
|
||||||
|
</div>
|
Loading…
Reference in New Issue
Doesn't this normally generate files/links in the format
blog/:title/index.html
?