Merge branch 'add-container-sigstore'

This commit is contained in:
Linus Färnstrand committed 2022-11-30 14:46:09 +01:00
commit 62371bb6c4
5 files changed
+188

No files matched your search

@@ -11,6 +11,10 @@ on:
- ios/MullvadVPN.xcodeproj/project.xcworkspace/xcshareddata/swiftpm/Package.resolved
- android/gradle/verification-metadata.xml
- android/gradle/wrapper/gradle-wrapper.properties
- building/build-and-publish.sh
- building/mullvad-app-container-signing.asc
- building/linux-container-image-tag.txt
- building/android-container-image-tag.txt
workflow_dispatch:
jobs:
verify-signatures:
View File
File renamed without changes.
+68
View File
@@ -0,0 +1,68 @@
# Mullvad VPN app build containers
Substitute `${repo}` with the actual absolute path to this repository
## Building and publishing a container image
These instructions describe how to set up the trusted machine that builds, signs and publishes
the container images to ghcr.io.
If you `sudo` into a `build` account that do the builds, you need to set the permissions on the tty,
so podman can ask for the passphrase for the gpg key:
```
realuser@server $ sudo chown build:build $(tty)
realuser@server $ sudo -u build -i
```
Configure podman to store signatures when building and pushing images. `~/.config/containers/registries.d/mullvad.yaml`:
```yml
docker:
ghcr.io/mullvad:
sigstore-staging: file://${repo}/building/sigstore
```
Build and publish the container image. Tag it with the github hash of the current commit
```
git checkout -b update-build-container
./build-and-publish.sh (linux|android)
git push # And create a PR
```
## Pulling, verifying and using build images
These instructions describe how anyone can pull the images and verify them with GPG before using them.
Copy the Mullvad app container signing GPG key to somewhere outside the repository (so a `git pull` can't overwrite it with a malicious key):
```
cp ${repo}/building/mullvad-app-container-signing.asc /path/to/mullvad-app-container-signing.asc
```
Configure a strict policy for podman when pulling from `ghcr.io/mullvad`. `~/.config/containers/policy.json`:
```json
{
"default": [{ "type": "insecureAcceptAnything" }],
"transports": {
"docker": {
"ghcr.io/mullvad": [
{
"type": "signedBy",
"keyType": "GPGKeys",
"keyPath": "/path/to/mullvad-app-container-signing.asc"
}
]
}
}
}
```
Configure podman to fetch image signatures from the in-repo sigstore directory. `~/.config/containers/registries.d/mullvad.yaml`:
```yml
docker:
ghcr.io/mullvad:
sigstore: file://${repo}/building/sigstore
```
+95
View File
@@ -0,0 +1,95 @@
#!/usr/bin/env bash
# This script will build, sign and publish the Mullvad VPN app build image(s)
# for either linux or android, depending on the first argument.
# Please see `README.md` for setup instructions *before* running this script
set -eu
CONTAINER_SIGNING_KEY_FINGERPRINT=1E551687D67F5FD820BEF2C4D7C17F87A0D3D215
REGISTRY_HOST="ghcr.io"
REGISTRY_ORG="mullvad"
SCRIPT_DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd )"
REPO_DIR="$( cd "$SCRIPT_DIR/.." && pwd )"
cd "$REPO_DIR"
source "$REPO_DIR/scripts/utils/log"
tag="$(git rev-parse --short HEAD)"
case ${1-:""} in
linux)
container_name="mullvadvpn-app-build"
containerfile_path="$SCRIPT_DIR/Dockerfile"
container_context_dir="$REPO_DIR"
container_image_tag_path="$SCRIPT_DIR/linux-container-image-tag.txt"
;;
android)
container_name="mullvadvpn-app-build-android"
containerfile_path="$REPO_DIR/android/docker/Dockerfile"
container_context_dir="$REPO_DIR/android/docker/"
container_image_tag_path="$SCRIPT_DIR/android-container-image-tag.txt"
;;
*)
log_error "Invalid platform. Specify 'linux' or 'android' as first argument"
exit 1
esac
full_container_name="$REGISTRY_HOST/$REGISTRY_ORG/$container_name"
log_header "Building $full_container_name tagged as '$tag' and 'latest'"
podman build -f "$containerfile_path" "$container_context_dir" --no-cache \
-t "$full_container_name:$tag" \
-t "$full_container_name:latest"
# Temporary directory to store image digest and signature in.
# This is a hack since two consecutive `podman push` seems
# to overwrite the signatures. We want to keep the signature
# for both the 'latest' and '$tag' tags.
tmp_signature_dir=$(mktemp -d)
function delete_tmp_signature_dir {
rm -rf "$tmp_signature_dir"
}
trap 'delete_tmp_signature_dir' EXIT
log_header "Pushing $full_container_name:latest"
podman push "$full_container_name:latest" \
--sign-by $CONTAINER_SIGNING_KEY_FINGERPRINT \
--digestfile "$tmp_signature_dir/digest_latest"
digest=$(cat "$tmp_signature_dir/digest_latest")
log_success "Pushed image with digest $digest"
# Backup the signature so we can restore it after the second podman push later
signature_dir="$SCRIPT_DIR/sigstore/$REGISTRY_ORG/$container_name@${digest/:/=}"
if [[ -f "$signature_dir/signature-2" ]]; then
log_error "Did not expect $signature_dir/signature-2 to exist"
exit 1
fi
cp "$signature_dir/signature-1" "$tmp_signature_dir/signature-2"
log_header "Pushing $full_container_name:$tag"
podman push "$full_container_name:$tag" \
--sign-by $CONTAINER_SIGNING_KEY_FINGERPRINT \
--digestfile "$tmp_signature_dir/digest_$tag"
if ! cmp -s "$tmp_signature_dir/digest_latest" "$tmp_signature_dir/digest_$tag"; then
log_error "Digests differ between 'latest' and '$tag' pushes"
exit 1
fi
cp "$tmp_signature_dir/signature-2" "$signature_dir/"
log_info "Storing container tag to $container_image_tag_path"
echo "$tag" > "$container_image_tag_path"
log_header "Commiting signatures and new tag name to git"
git add "$container_image_tag_path" "$signature_dir"
GPG_TTY=$(tty) git commit -S -m "Updating build container for $1 to $tag"
log_success "***********************"
log_success ""
log_success "Done building and pushing $full_container_name with tags '$tag' and 'latest'"
log_success "Make sure to push the changes to git"
log_success ""
log_success "***********************"
@@ -0,0 +1,21 @@
-----BEGIN PGP PUBLIC KEY BLOCK-----
mDMEY2pmvhYJKwYBBAHaRw8BAQdAOOJocdP7MXSesmmMuA7JXxo0ZVV7aiT1ZFxo
oGKmAcS0NU11bGx2YWQgVlBOIGFwcCAoQ29udGFpbmVyIHNpZ25pbmcpIDxhcHBA
bXVsbHZhZC5uZXQ+iIoEExYKADICGwMCF4AWIQQeVRaH1n9f2CC+8sTXwX+HoNPS
FQUCY4X7/AILCQIVCgUWAgMBAAIeBQAKCRDXwX+HoNPSFRSUAPwIcRuvdzVqufOj
UsbK+qEz9WTqR2QMSGU2LPtkFJyygAEAzhaAFgklONznxpPx0BWI7/hCkYmg2siI
/KfdA3wkkgWJAjMEEAEIAB0WIQShGYcC/D4KCamuW3XVodTyZt6N3wUCY4X68wAK
CRDVodTyZt6N39SuD/9JkAAT06imUiB+bKs6BbdRFPnztAxcQPJztbAmIdch2Nly
6gQyxnrbf0voTBcFs0idRyzYcCgliq+7SqHBgOHtGnOgNH1IDNkEnU2lF4kioGnY
w+6hETBb5KH/ywze+p1fEe8+Id9l5mfnZJwvciSpMKc3CQKMSGzPgPSdTjgN4TtF
U6ckwd3QAVMl1lOp6enznnLdtjnWlQU/qFI97YY7r7IdkOhVeI5oENMBPJWjlEZr
9wHBedm0ZatplW16myikJZJ/VCGU0HLRNz+Ki6FEvV4VcxLKSlCkBwdk3mjpb++r
CKqgyEZOH47icK3blAbZvYZVHSl4P5BMW67YLUAp627PpWllyJDKt5Tt+gbGJ6Q3
Jwaw6/eDObEVArV/bnNnk3T07IcDotlcm0HUIUJeVKLuBQOsyo6zyRW6iCzwbgHN
Bt8N99DQE2d9nySkzGDGZOmHjRLMF/q7NPbzdI0bwoE3D8S8w1VSKVqmGbkfR8W8
a7ZibDR3W7x6ofi9owFd9XEM/SQGDU99FxvLLHUy//2Ox/iPxdUWygzWchneDaFL
MnGJ5GEgsfz7zdzBjXcYxU3jEdEHzlkiRcdqM8mjTM+1xmOT3ed30sf04uHHYzu6
Gm/EaXoAwZGtr/HZ8teR6yEr+R57JrICOVOLHYbjSprJmOWBcskMefpiwK9EUA==
=0W2k
-----END PGP PUBLIC KEY BLOCK-----