From 872149470b023dc13ee72de81998c78942adddbd Mon Sep 17 00:00:00 2001 From: Aleksa Sarai Date: Fri, 7 Apr 2023 11:23:22 +1000 Subject: [PATCH 1/5] release: add runc.keyring file and script In order to allow any of the maintainers to cut releases for runc, create a keyring file that distributions can use to verify that releases are signed by one of the maintainers. The format matches the gpg-offline format used by openSUSE packaging, but it can be easily imported with "gpg --import" so any distribution should be able to handle this keyring format wtihout issues. Each key includes the GitHub handle of the associated user. There isn't any way for this information to be automatically verified (outside of using something like keybase.io) but since all changes of this file need to be approved by maintainers this is okay for now. Signed-off-by: Aleksa Sarai --- README.md | 2 ++ runc.keyring | 0 script/keyring_addkey.sh | 37 +++++++++++++++++++++++++++++++++++++ 3 files changed, 39 insertions(+) create mode 100644 runc.keyring create mode 100755 script/keyring_addkey.sh diff --git a/README.md b/README.md index 08ab46ecfd6..b209c7dcd55 100644 --- a/README.md +++ b/README.md @@ -15,6 +15,8 @@ You can find official releases of `runc` on the [release](https://github.com/opencontainers/runc/releases) page. +All releases are signed by one of the keys listed in the [`runc.keyring` file in the root of this repository](runc.keyring). + ## Security The reporting process and disclosure communications are outlined [here](https://github.com/opencontainers/org/blob/master/SECURITY.md). diff --git a/runc.keyring b/runc.keyring new file mode 100644 index 00000000000..e69de29bb2d diff --git a/script/keyring_addkey.sh b/script/keyring_addkey.sh new file mode 100755 index 00000000000..bb319218fb3 --- /dev/null +++ b/script/keyring_addkey.sh @@ -0,0 +1,37 @@ +#!/bin/bash +# Copyright (C) 2023 SUSE LLC. +# Copyright (C) 2023 Open Containers Authors +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +set -Eeuxo pipefail + +root="$(readlink -f "$(dirname "${BASH_SOURCE[0]}")/..")" +keyring_file="$root/runc.keyring" + +function bail() { + echo "$@" >&2 + exit 1 +} + +[[ "$#" -eq 2 ]] || bail "usage: $0 " + +github_handle="${1}" +gpg_keyid="${2}" + +cat >>"$keyring_file" < Date: Fri, 7 Apr 2023 14:31:01 +1000 Subject: [PATCH 2/5] scripts: release: add verification checks for signing keys We need to make sure the release is being signed by a key that is actually listed as a trusted signing key, and we also need to ask the person cutting the release whether the list of trusted keys is acceptable. Also add some verification checks after a release is signed to make sure everything was signed with the correct keys. Signed-off-by: Aleksa Sarai --- script/release_sign.sh | 71 ++++++++++++++++++++++++++++++++++++------ 1 file changed, 61 insertions(+), 10 deletions(-) diff --git a/script/release_sign.sh b/script/release_sign.sh index 8cc224ac6b1..e66a81bc7b2 100755 --- a/script/release_sign.sh +++ b/script/release_sign.sh @@ -1,6 +1,6 @@ #!/bin/bash -# Copyright (C) 2017 SUSE LLC. -# Copyright (C) 2017-2021 Open Containers Authors +# Copyright (C) 2017-2023 SUSE LLC. +# Copyright (C) 2017-2023 Open Containers Authors # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. @@ -14,7 +14,7 @@ # See the License for the specific language governing permissions and # limitations under the License. -set -e +set -Eeuo pipefail project="runc" root="$(readlink -f "$(dirname "${BASH_SOURCE[0]}")/..")" @@ -28,15 +28,21 @@ function usage() { # Log something to stderr. function log() { - echo "[*] $*" >&2 + echo "[*]" "$@" >&2 } # Log something to stderr and then exit with 0. -function bail() { +function quit() { log "$@" exit 0 } +# Log something to stderr and then exit with 1. +function bail() { + log "$@" + exit 1 +} + # Conduct a sanity-check to make sure that GPG provided with the given # arguments can sign something. Inability to sign things is not a fatal error. function gpg_cansign() { @@ -86,17 +92,47 @@ log "signing $project release in '$releasedir'" log " key: ${keyid:-DEFAULT}" log " hash: $hashcmd" -# Make explicit what we're doing. -set -x - # Set up the gpgflags. gpgflags=() [[ "$keyid" ]] && gpgflags=(--default-key "$keyid") -gpg_cansign "${gpgflags[@]}" || bail "Could not find suitable GPG key, skipping signing step." +gpg_cansign "${gpgflags[@]}" || quit "Could not find suitable GPG key, skipping signing step." + +# Make explicit what we're doing. +set -x + +# Check that the keyid is actually in the $project.keyring by signing a piece +# of dummy text then verifying it against the list of keys in that keyring. +tmp_gpgdir="$(mktemp -d --tmpdir "$project-sign-tmpkeyring.XXXXXX")" +trap 'rm -r "$tmp_gpgdir"' EXIT + +tmp_runc_gpgflags=("--no-default-keyring" "--keyring=$tmp_gpgdir/$project.keyring") +gpg "${tmp_runc_gpgflags[@]}" --import <"$root/$project.keyring" + +tmp_seccomp_gpgflags=("--no-default-keyring" "--keyring=$tmp_gpgdir/seccomp.keyring") +gpg "${tmp_seccomp_gpgflags[@]}" --recv-keys 0x47A68FCE37C7D7024FD65E11356CE62C2B524099 +gpg "${tmp_seccomp_gpgflags[@]}" --recv-keys 0x7100AADFAE6E6E940D2E0AD655E45A5AE8CA7C8A + +gpg "${gpgflags[@]}" --clear-sign <<<"[This is test text used for $project release scripts. $(date --rfc-email)]" | + gpg "${tmp_runc_gpgflags[@]}" --verify || bail "Signing key ${keyid:-DEFAULT} is not in trusted $project.keyring list!" + +# Make sure the signer is okay with the list of keys in the keyring (once this +# release is signed, distributions will trust this keyring). +cat >&2 < Date: Wed, 19 Apr 2023 12:29:21 +1000 Subject: [PATCH 3/5] keyring: verify runc.keyring has legitimate maintainer keys These checks ensure that all of the keys in the runc.keyring list are actually the keys of the specified user and that the users themselves are actually maintainers. Signed-off-by: Aleksa Sarai --- .github/workflows/validate.yml | 6 +++ Makefile | 5 +- script/keyring_validate.sh | 98 ++++++++++++++++++++++++++++++++++ 3 files changed, 108 insertions(+), 1 deletion(-) create mode 100755 script/keyring_validate.sh diff --git a/.github/workflows/validate.yml b/.github/workflows/validate.yml index da4ce1ff965..a22676b52fa 100644 --- a/.github/workflows/validate.yml +++ b/.github/workflows/validate.yml @@ -13,6 +13,12 @@ permissions: contents: read jobs: + keyring: + runs-on: ubuntu-22.04 + steps: + - uses: actions/checkout@v3 + - name: check runc.keyring + run: make validate-keyring lint: permissions: diff --git a/Makefile b/Makefile index 870eb7a0015..00c8d71ab68 100644 --- a/Makefile +++ b/Makefile @@ -188,9 +188,12 @@ verify-dependencies: vendor || (echo -e "git status:\n $$(git status -- go.mod go.sum vendor/)\nerror: vendor/, go.mod and/or go.sum not up to date. Run \"make vendor\" to update"; exit 1) \ && echo "all vendor files are up to date." +validate-keyring: + script/keyring_validate.sh + .PHONY: runc all recvtty sd-helper seccompagent static releaseall release \ localrelease dbuild lint man runcimage \ test localtest unittest localunittest integration localintegration \ rootlessintegration localrootlessintegration shell install install-bash \ install-man clean cfmt shfmt localshfmt shellcheck \ - vendor verify-changelog verify-dependencies + vendor verify-changelog verify-dependencies validate-keyring diff --git a/script/keyring_validate.sh b/script/keyring_validate.sh new file mode 100755 index 00000000000..61ed80cc0f4 --- /dev/null +++ b/script/keyring_validate.sh @@ -0,0 +1,98 @@ +#!/bin/bash +# Copyright (C) 2023 SUSE LLC. +# Copyright (C) 2023 Open Containers Authors +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +set -Eeuo pipefail + +project="runc" +root="$(readlink -f "$(dirname "${BASH_SOURCE[0]}")/..")" + +function log() { + echo "[*]" "$@" >&2 +} + +function bail() { + log "$@" + exit 1 +} + +# Temporary GPG keyring for messing around with. +tmp_gpgdir="$(mktemp -d --tmpdir "$project-validate-tmpkeyring.XXXXXX")" +trap 'rm -r "$tmp_gpgdir"' EXIT + +# Get the set of MAINTAINERS. +readarray -t maintainers < <(sed -E 's|.* <.*> \(@?(.*)\)$|\1|' <"$root/MAINTAINERS") +echo "$project maintainers:" +printf " %s\n" "${maintainers[@]}" + +# Create a dummy gpg keyring from the set of MAINTAINERS. +while IFS="" read -r username || [ -n "$username" ]; do + curl -sSL "https://github.com/$username.gpg" | + gpg --no-default-keyring --keyring="$tmp_gpgdir/$username.keyring" --import +done < <(printf '%s\n' "${maintainers[@]}") + +# Make sure all of the keys in the keyring have a github=... comment. +awk <"$root/$project.keyring" ' + /^-----BEGIN PGP PUBLIC KEY BLOCK-----$/ { key_idx++; in_pgp=1; has_comment=0; } + + # PGP comments are never broken up over several lines, and we only have one + # comment entry in our keyring file anyway. + in_pgp && /^Comment:.* github=\w+.*/ { has_comment=1 } + + /^-----END PGP PUBLIC KEY BLOCK-----$/ { + if (!has_comment) { + print "[!] Key", key_idx, "in '$project'.keyring is missing a github= comment." + exit 1 + } + } +' + +# Check that each entry in the kering is actually a maintainer's key. +while IFS="" read -d $'\0' -r block || [ -n "$block" ]; do + username="$(sed -En "s|^Comment:.* github=(\w+).*|\1|p" <<<"$block")" + + # FIXME: This is to work around codespell thinking that f-p-r is a + # misspelling of some other word, and the lack of support for inline + # ignores in codespell. + fprfield="f""p""r" + + # Check the username is actually a maintainer. This is just a sanity check, + # since you can put whatever you like in the Comment field. + [ -f "$tmp_gpgdir/$username.keyring" ] || bail "User $username in runc.keyring is not a maintainer!" + grep "(@$username)$" "$root/MAINTAINERS" >/dev/null || bail "User $username in runc.keyring is not a maintainer!" + + # Check that the key in the block actually matches a known key for that + # maintainer. Note that a block can contain multiple keys, so we need to + # check all of them. Since we have to handle multiple keys anyway, we'll + # also verify all of the subkeys (this is simpler to implement anyway since + # the --with-colons format outputs fingerprints for both primary and + # subkeys in the same way). + # + # Fingerprints have a field 1 of $fprfield and field 10 containing the + # fingerprint. See + # for more details. + while IFS="" read -r key || [ -n "$key" ]; do + gpg --no-default-keyring --keyring="$tmp_gpgdir/$username.keyring" \ + --list-keys --with-colons | grep "$fprfield:::::::::$key:" >/dev/null || + bail "(Sub?)Key $key in $project.keyring is NOT actually one of $username's keys!" + log "Successfully verified $username's (sub?)key $key is legitimate." + done < <(gpg --no-default-keyring \ + --import --import-options=show-only --with-colons <<<"$block" | + grep "^$fprfield:" | cut -d: -f10) +done < <(awk <"$project.keyring" ' + /^-----BEGIN PGP PUBLIC KEY BLOCK-----$/ { in_block=1 } + in_block { print } + /^-----END PGP PUBLIC KEY BLOCK-----$/ { in_block=0; printf("\0"); } +') From 0c9c60aa18239785e9acd037445717cab462c395 Mon Sep 17 00:00:00 2001 From: Aleksa Sarai Date: Fri, 7 Apr 2023 11:34:38 +1000 Subject: [PATCH 4/5] keyring: add Aleksa's signing key keyid 5F36C6C61B5460124A75F5A69E18AA267DDB8DB4 This is the signing key I have used for all previous runc releases. You can also verify that this is the key trusted by openSUSE for all of our releases. Ref: https://keyserver.ubuntu.com/pks/lookup?search=5F36C6C61B5460124A75F5A69E18AA267DDB8DB4&fingerprint=on&op=index Ref: https://build.opensuse.org/package/view_file/openSUSE:Factory/runc/runc.keyring?expand=1&rev=54 Signed-off-by: Aleksa Sarai --- runc.keyring | 71 ++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 71 insertions(+) diff --git a/runc.keyring b/runc.keyring index e69de29bb2d..12cb0bcdf1a 100644 --- a/runc.keyring +++ b/runc.keyring @@ -0,0 +1,71 @@ +pub rsa4096 2016-06-21 [SC] [expires: 2031-06-18] + 5F36C6C61B5460124A75F5A69E18AA267DDB8DB4 +uid [ultimate] Aleksa Sarai +uid [ultimate] Aleksa Sarai +sub rsa4096 2016-06-21 [E] [expires: 2031-06-18] + +-----BEGIN PGP PUBLIC KEY BLOCK----- +Comment: github=cyphar + +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 +=3/jE +-----END PGP PUBLIC KEY BLOCK----- + From 056ec0caa65b57ec0f47233f405fc0e5005d7e06 Mon Sep 17 00:00:00 2001 From: Aleksa Sarai Date: Wed, 19 Apr 2023 12:51:59 +1000 Subject: [PATCH 5/5] keyring: add Aleksa's signing key keyid C9C370B246B09F6DBCFC744C34401015D1D2D386 This is my personal signing key, which I've used to sign the vast majority of my commits on GitHub. While I usually sign releases using my signing key, it doesn't hurt to include this key too. Ref: https://keyserver.ubuntu.com/pks/lookup?search=C9C370B246B09F6DBCFC744C34401015D1D2D386&fingerprint=on&op=index Signed-off-by: Aleksa Sarai --- runc.keyring | 53 ++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 53 insertions(+) diff --git a/runc.keyring b/runc.keyring index 12cb0bcdf1a..f5733cce423 100644 --- a/runc.keyring +++ b/runc.keyring @@ -69,3 +69,56 @@ KWr9ByCKAwVHsaSgVSJE/dse4f1toqeEHHbWk682U4RqOWZR4bA0 =3/jE -----END PGP PUBLIC KEY BLOCK----- +pub ed25519 2019-06-21 [C] + C9C370B246B09F6DBCFC744C34401015D1D2D386 +uid [ultimate] Aleksa Sarai +sub ed25519 2022-09-30 [S] [expires: 2024-09-29] +sub cv25519 2022-09-30 [E] [expires: 2024-09-29] +sub ed25519 2022-09-30 [A] [expires: 2024-09-29] + +-----BEGIN PGP PUBLIC KEY BLOCK----- +Comment: github=cyphar + +mDMEXQxvLxYJKwYBBAHaRw8BAQdArRQoZs9YzYtQIiPA1qdvUT8Q0wbPZyRV65Tz +QNTIZla0IEFsZWtzYSBTYXJhaSA8Y3lwaGFyQGN5cGhhci5jb20+iJAEExYIADgF +CwkIBwIGFQoJCAsCBBYCAwECHgECF4AWIQTJw3CyRrCfbbz8dEw0QBAV0dLThgUC +XQzCHwIbAQAKCRA0QBAV0dLThvUpAP9SwyOijLqEBz1A9pTqRAB0l/r+ABq+iUmH +UjMHO34LZAD/biRuAadaxIYJtmn7nKA55doyN2fQXhjArqypJ1SQywi4MwRdDMJS +FgkrBgEEAdpHDwEBB0B2IGusH7LuDH3hNT6JYM30S7G92FGogA6a9WQzKRlqvIh4 +BCgWCgAgFiEEycNwskawn228/HRMNEAQFdHS04YFAmM2ukUCHQEACgkQNEAQFdHS +04ZTQAEAjAT0fXVJHdRL6UMCxDYsgjG+QyH1mr7gKgbPvB8A5LgBAN4QDqCxIY3b +8+X4Ud3C9yLfkbcsdgctU3fO/jHpKVIIiO8EGBYIACAWIQTJw3CyRrCfbbz8dEw0 +QBAV0dLThgUCXQzCUgIbAgCBCRA0QBAV0dLThnYgBBkWCAAdFiEEsWZunbXxPIMS +y32KnZS5YyG50BIFAl0MwlIACgkQnZS5YyG50BLusQD/aPjX4NhlSYgzNV2x31aw +x5AxTp+18xoQDwaU123grDgA/2B73RiaTO2boRK5UETxx6awdsA51hZubxo4LyxG +SP8IW5gA/2JWrDg+7cSQrS71gHmtqvz0se+D7zmWdcnN8O3LoUZeAQDW3Pkq0cru +YVbsXiTwzenLPUJrjGBAVaoFmYqFUelFDLg4BF0MwmoSCisGAQQBl1UBBQEBB0BL +FI5mD555F7t6dovnw4DW19nkG/g/Vd5Zb/7qhMLWagMBCAeIeAQoFgoAIBYhBMnD +cLJGsJ9tvPx0TDRAEBXR0tOGBQJjNrpFAh0BAAoJEDRAEBXR0tOGgPkA/1Z69M4e +qU3ZM7czYOHKAbNHiRuAqzc6o90WBJLhgFJmAQCcKmpnnnTpbnGoXgkcRSr2y1wk +uId1oVRwfRbN9h94Doh4BBgWCAAgFiEEycNwskawn228/HRMNEAQFdHS04YFAl0M +wmoCGwwACgkQNEAQFdHS04aZWgD/d0gCCB7ytnRB9RBtns9RRrtGXOIrzzWKw+zx +za6Y2zgBANoj7CUeH0MygzZkgMrCmKPNnMxEnHJaTuYZA4yBixkIuDMEXQzCjRYJ +KwYBBAHaRw8BAQdAAiFh7AD1u/UhjVbGJkRflPhjHBKIsAuP4pkI/qjavwaIeAQo +FgoAIBYhBMnDcLJGsJ9tvPx0TDRAEBXR0tOGBQJjNrpFAh0BAAoJEDRAEBXR0tOG +AUgA/2ZDB3tCRBON1WjLBESkHZmNtplYcV03u/oshA/MVCzpAQDGusGcv/rf1ZI9 +o7lcWozXFlQDOM7eoT4avvWOVcsaD4h4BBgWCAAgFiEEycNwskawn228/HRMNEAQ +FdHS04YFAl0Mwo0CGyAACgkQNEAQFdHS04ajxQEAsZf1yDORUVYicREc/7z0U+51 +DJzeAexeJTYM+N+x13EA/0Ex+o7qQ7dZLGDn7x4LSbd39C+++suHsEaE4XwlX6cH +uDMEYza6SxYJKwYBBAHaRw8BAQdAE3s7dZQFuImQX2tWshIdGjeUKZc7rlMcrZ6+ +q25gaH2I9QQYFgoAJhYhBMnDcLJGsJ9tvPx0TDRAEBXR0tOGBQJjNrpLAhsCBQkD +wmcAAIEJEDRAEBXR0tOGdiAEGRYKAB0WIQS2TklVsp+j1GPyqQYol/rSt+lEbwUC +Yza6SwAKCRAol/rSt+lEb9obAQC8ij4yJTU7ZcAtTx2ZMjj8EoruGb3ku6VpRyx1 ++pyQQgD/QgQ7X1G7xtwuVpY0kHYga1yoKLA2ycT8F8PrVtF7pAMWkgD9EWe1E77C +BVd//i3ib+h9ikCeJ+gaxc6aU24ZBcN2tfUBAJmCmYQ0VEbXyvCqkdJEQ4qk5Y9C +2V4w83dj4a5RYKUGuDgEYza6YBIKKwYBBAGXVQEFAQEHQKECW5Y7nUGCka0/WcCM +OerRY95Pm2DQVL76QzvhXD8tAwEIB4h+BBgWCgAmFiEEycNwskawn228/HRMNEAQ +FdHS04YFAmM2umACGwwFCQPCZwAACgkQNEAQFdHS04bkuwEA7AEL+iSPlA8/YILp +0sFMzmtRqTDMqx2BY8K5wEk9fusA/jAhbeJw57bZYvK4MghfUa9tRocyII84UmOA +cgDbPPIFuDMEYza6bhYJKwYBBAHaRw8BAQdAgHXd0yf6MPXJZCZ3TFz8xLymyPsD +TF2SQwwqM4+nYbeIfgQYFgoAJhYhBMnDcLJGsJ9tvPx0TDRAEBXR0tOGBQJjNrpu +AhsgBQkDwmcAAAoJEDRAEBXR0tOGB8UA/0wf8uECKMmXGQ4DNi+ei2E9Ft6GL8qw +UGjwM/EKH2RoAP9HNRRKBjDxs/AZ3pBx1Q8hnHELLo0kXPc+3BG6Pht5BA== +=KN4V +-----END PGP PUBLIC KEY BLOCK----- +