|
|
|
@@ -20,19 +20,34 @@ style conventions are in separate documents:
|
|
|
|
|
`last_modified: YYYY-MM-DD` in the YAML front matter so it can be kept in sync
|
|
|
|
|
with the authoritative source as policies evolve.
|
|
|
|
|
|
|
|
|
|
- **ALL external references must be pinned by cryptographic hash.** This
|
|
|
|
|
includes Docker base images, Go modules, npm packages, GitHub Actions, and
|
|
|
|
|
anything else fetched from a remote source. Version tags (`@v4`, `@latest`,
|
|
|
|
|
`:3.21`, etc.) are server-mutable and therefore remote code execution
|
|
|
|
|
vulnerabilities. The ONLY acceptable way to reference an external dependency
|
|
|
|
|
is by its content hash (Docker `@sha256:...`, Go module hash in `go.sum`, npm
|
|
|
|
|
integrity hash in lockfile, GitHub Actions `@<commit-sha>`). No exceptions.
|
|
|
|
|
This also means never `curl | bash` to install tools like pyenv, nvm, rustup,
|
|
|
|
|
etc. Instead, download a specific release archive from GitHub, verify its hash
|
|
|
|
|
(hardcoded in the Dockerfile or script), and only then install. Unverified
|
|
|
|
|
install scripts are arbitrary remote code execution. This is the single most
|
|
|
|
|
important rule in this document. Double-check every external reference in
|
|
|
|
|
every file before committing. There are zero exceptions to this rule.
|
|
|
|
|
- **External references must be pinned by cryptographic hash.** This includes
|
|
|
|
|
Docker base images, Go modules, npm packages, GitHub Actions, and anything
|
|
|
|
|
else fetched from a remote source. Version tags (`@v4`, `@latest`, `:3.21`,
|
|
|
|
|
etc.) are server-mutable and therefore remote code execution vulnerabilities.
|
|
|
|
|
Reference an external dependency by its content hash (Docker `@sha256:...`, Go
|
|
|
|
|
module hash in `go.sum`, npm integrity hash in lockfile, GitHub Actions
|
|
|
|
|
`@<commit-sha>`). This also means never `curl | bash` to install tools like
|
|
|
|
|
pyenv, nvm, rustup, etc. Instead, download a specific release archive from
|
|
|
|
|
GitHub, verify its hash (hardcoded in the Dockerfile or script), and only then
|
|
|
|
|
install. Unverified install scripts are arbitrary remote code execution. This
|
|
|
|
|
is the single most important rule in this document. Double-check every
|
|
|
|
|
external reference in every file before committing.
|
|
|
|
|
|
|
|
|
|
There is one exception: the package index of the pinned base image's own
|
|
|
|
|
distribution. The distribution is trusted, so these commands may use that
|
|
|
|
|
index with no version and no hash:
|
|
|
|
|
- `apt-get update`, which pulls the index
|
|
|
|
|
- `apt-get install`
|
|
|
|
|
- `apk add`
|
|
|
|
|
|
|
|
|
|
These are not trusted, so everything from them stays pinned by hash:
|
|
|
|
|
- Docker Hub
|
|
|
|
|
- PyPI
|
|
|
|
|
- npm
|
|
|
|
|
- `go get`
|
|
|
|
|
|
|
|
|
|
A package source that a `Dockerfile` adds itself is not the distribution's
|
|
|
|
|
own, so the exception does not cover it.
|
|
|
|
|
|
|
|
|
|
- Every repo with software must have a root `Makefile` with these targets:
|
|
|
|
|
`make bootstrap`, `make setup`, `make test`, `make lint`, `make fmt` (writes),
|
|
|
|
@@ -259,6 +274,8 @@ style conventions are in separate documents:
|
|
|
|
|
# run unless lint and test passed.
|
|
|
|
|
# golang:1.x-alpine, YYYY-MM-DD
|
|
|
|
|
FROM golang@sha256:... AS builder
|
|
|
|
|
# git comes from the base image's own distribution package index, which
|
|
|
|
|
# is trusted, so it needs no version and no hash.
|
|
|
|
|
RUN apk add --no-cache git
|
|
|
|
|
WORKDIR /src
|
|
|
|
|
COPY go.mod go.sum ./
|
|
|
|
@@ -394,11 +411,10 @@ style conventions are in separate documents:
|
|
|
|
|
`Pipfile.lock`. It installs no Python there: the tests use the base
|
|
|
|
|
image's Python, which the image's hash pins. If it installs anything else
|
|
|
|
|
there, the step goes after `ARG CACHEBUST`.
|
|
|
|
|
- Every external reference must be pinned by hash, so `script/bootstrap`
|
|
|
|
|
installs pipenv and its dependencies by hash. It does so with
|
|
|
|
|
`pip install --require-hashes -r` and a requirements file in `script/`
|
|
|
|
|
that lists each of them with `==` and its `--hash`. pip refuses to install
|
|
|
|
|
a dependency the file does not list.
|
|
|
|
|
- PyPI is not trusted, so `script/bootstrap` installs pipenv and its
|
|
|
|
|
dependencies by hash. It does so with `pip install --require-hashes -r`
|
|
|
|
|
and a requirements file in `script/` that lists each of them with `==` and
|
|
|
|
|
its `--hash`. pip refuses to install a dependency the file does not list.
|
|
|
|
|
- It then runs `pipenv install --deploy`, with `--dev` when the tests need
|
|
|
|
|
the development packages. `--deploy` installs only what `Pipfile.lock`
|
|
|
|
|
names, checks every package against the lockfile's hashes, and fails when
|
|
|
|
|