Skip to content

Commit a251581

Browse files
authored
Merge pull request #6300 from tonistiigi/git-signature-verification
git: add signature verification to CacheKey and ResolveMetadata
2 parents 202e28f + 81a7983 commit a251581

File tree

203 files changed

+47209
-50
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

203 files changed

+47209
-50
lines changed

Dockerfile

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -414,7 +414,7 @@ COPY --link --from=binaries / /
414414

415415
FROM buildkit-base AS integration-tests-base
416416
ENV BUILDKIT_INTEGRATION_ROOTLESS_IDPAIR="1000:1000"
417-
RUN apk add --no-cache shadow shadow-uidmap sudo vim iptables ip6tables dnsmasq fuse curl git-daemon openssh-client openssl slirp4netns iproute2 \
417+
RUN apk add --no-cache shadow shadow-uidmap sudo vim iptables ip6tables dnsmasq fuse curl git-daemon openssh-client openssl slirp4netns iproute2 gpg gpg-agent \
418418
&& useradd --create-home --home-dir /home/user --uid 1000 -s /bin/sh user \
419419
&& echo "XDG_RUNTIME_DIR=/run/user/1000; export XDG_RUNTIME_DIR" >> /home/user/.profile \
420420
&& mkdir -m 0700 -p /run/user/1000 \
@@ -435,6 +435,9 @@ ENTRYPOINT ["/docker-entrypoint.sh"]
435435
ENV BUILDKIT_INTEGRATION_CONTAINERD_EXTRA="containerd-2.0=/opt/containerd-alt-20/bin,containerd-1.7=/opt/containerd-alt-17/bin"
436436
ENV BUILDKIT_INTEGRATION_SNAPSHOTTER=stargz
437437
ENV BUILDKIT_SETUP_CGROUPV2_ROOT=1
438+
ENV BUILDKIT_TEST_SIGN_FIXTURES=/tmp/buildkit_test_sign_fixtures
439+
RUN --mount=target=/tmp/gen_gpg_test_env.sh,source=hack/fixtures/gen_gpg_test_env.sh sh /tmp/gen_gpg_test_env.sh user1 && sh /tmp/gen_gpg_test_env.sh user2
440+
RUN --mount=target=/tmp/gen_ssh_test_env.sh,source=hack/fixtures/gen_ssh_test_env.sh sh /tmp/gen_ssh_test_env.sh user1 && sh /tmp/gen_ssh_test_env.sh user2
438441
ENV CGO_ENABLED=0
439442
ENV GOTESTSUM_FORMAT=standard-verbose
440443
COPY --link --from=gotestsum /out /usr/bin/

client/client_test.go

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -12164,7 +12164,7 @@ func testGitResolveSourceMetadata(t *testing.T, sb integration.Sandbox) {
1216412164

1216512165
commit, err := commitObj.ToCommit()
1216612166
require.NoError(t, err)
12167-
require.Equal(t, "msg\n", commit.Message)
12167+
require.Equal(t, "msg", commit.Message)
1216812168
require.Equal(t, "test", commit.Author.Name)
1216912169
require.Equal(t, "test@example.com", commit.Author.Email)
1217012170
require.Equal(t, "test", commit.Committer.Name)
@@ -12179,7 +12179,7 @@ func testGitResolveSourceMetadata(t *testing.T, sb integration.Sandbox) {
1217912179

1218012180
tag, err := tagObj.ToTag()
1218112181
require.NoError(t, err)
12182-
require.Equal(t, "v0.1release\n", tag.Message)
12182+
require.Equal(t, "v0.1release", tag.Message)
1218312183
require.Equal(t, "v0.1", tag.Tag)
1218412184
require.Equal(t, "test", tag.Tagger.Name)
1218512185
require.Equal(t, "test@example.com", tag.Tagger.Email)

go.mod

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@ require (
88
github.com/Azure/azure-sdk-for-go/sdk/storage/azblob v1.5.0
99
github.com/Microsoft/go-winio v0.6.2
1010
github.com/Microsoft/hcsshim v0.13.0
11+
github.com/ProtonMail/go-crypto v1.3.0
1112
github.com/agext/levenshtein v1.2.3
1213
github.com/armon/circbuf v0.0.0-20190214190532-5111143e8da2
1314
github.com/aws/aws-sdk-go-v2 v1.30.3
@@ -43,6 +44,7 @@ require (
4344
github.com/hashicorp/go-cleanhttp v0.5.2
4445
github.com/hashicorp/go-immutable-radix/v2 v2.1.0
4546
github.com/hashicorp/golang-lru/v2 v2.0.7
47+
github.com/hiddeco/sshsig v0.2.0
4648
github.com/in-toto/in-toto-golang v0.9.0
4749
github.com/klauspost/compress v1.18.0
4850
github.com/mitchellh/hashstructure/v2 v2.0.2
@@ -131,6 +133,7 @@ require (
131133
github.com/aws/smithy-go v1.20.3 // indirect
132134
github.com/beorn7/perks v1.0.1 // indirect
133135
github.com/cenkalti/backoff/v4 v4.3.0 // indirect
136+
github.com/cloudflare/circl v1.6.0 // indirect
134137
github.com/containerd/cgroups/v3 v3.0.5 // indirect
135138
github.com/containerd/errdefs/pkg v0.3.0 // indirect
136139
github.com/containerd/fifo v1.1.0 // indirect

go.sum

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,8 @@ github.com/Microsoft/go-winio v0.6.2 h1:F2VQgta7ecxGYO8k3ZZz3RS8fVIXVxONVUPlNERo
2323
github.com/Microsoft/go-winio v0.6.2/go.mod h1:yd8OoFMLzJbo9gZq8j5qaps8bJ9aShtEA8Ipt1oGCvU=
2424
github.com/Microsoft/hcsshim v0.13.0 h1:/BcXOiS6Qi7N9XqUcv27vkIuVOkBEcWstd2pMlWSeaA=
2525
github.com/Microsoft/hcsshim v0.13.0/go.mod h1:9KWJ/8DgU+QzYGupX4tzMhRQE8h6w90lH6HAaclpEok=
26+
github.com/ProtonMail/go-crypto v1.3.0 h1:ILq8+Sf5If5DCpHQp4PbZdS1J7HDFRXz/+xKBiRGFrw=
27+
github.com/ProtonMail/go-crypto v1.3.0/go.mod h1:9whxjD8Rbs29b4XWbB8irEcE8KHMqaR2e7GWU1R+/PE=
2628
github.com/agext/levenshtein v1.2.3 h1:YB2fHEn0UJagG8T1rrWknE3ZQzWM06O8AMAatNn7lmo=
2729
github.com/agext/levenshtein v1.2.3/go.mod h1:JEDfjyjHDjOF/1e4FlBE/PkbqA9OfWu2ki2W0IB5558=
2830
github.com/alecthomas/template v0.0.0-20160405071501-a0175ee3bccc/go.mod h1:LOuyumcjzFXgccqObfd/Ljyb9UuFJ6TxHnclSeseNhc=
@@ -84,6 +86,8 @@ github.com/chzyer/logex v1.1.10/go.mod h1:+Ywpsq7O8HXn0nuIou7OrIPyXbp3wmkHB+jjWR
8486
github.com/chzyer/readline v0.0.0-20180603132655-2972be24d48e/go.mod h1:nSuG5e5PlCu98SY8svDHJxuZscDgtXS6KTTbou5AhLI=
8587
github.com/chzyer/test v0.0.0-20180213035817-a1ea475d72b1/go.mod h1:Q3SI9o4m/ZMnBNeIyt5eFwwo7qiLfzFZmjNmxjkiQlU=
8688
github.com/client9/misspell v0.3.4/go.mod h1:qj6jICC3Q7zFZvVWo7KLAzC3yx5G7kyvSDkc90ppPyw=
89+
github.com/cloudflare/circl v1.6.0 h1:cr5JKic4HI+LkINy2lg3W2jF8sHCVTBncJr5gIIq7qk=
90+
github.com/cloudflare/circl v1.6.0/go.mod h1:uddAzsPgqdMAYatqJ0lsjX1oECcQLIlRpzZh3pJrofs=
8791
github.com/cncf/udpa/go v0.0.0-20191209042840-269d4d468f6f/go.mod h1:M8M6+tZqaGXZJjfX53e64911xZQV5JYwmTeXPW+k8Sc=
8892
github.com/codahale/rfc6979 v0.0.0-20141003034818-6a90f24967eb h1:EDmT6Q9Zs+SbUoc7Ik9EfrFqcylYqgPZ9ANSbTAntnE=
8993
github.com/codahale/rfc6979 v0.0.0-20141003034818-6a90f24967eb/go.mod h1:ZjrT6AXHbDs86ZSdt/osfBi5qfexBrKUdONk989Wnk4=
@@ -240,6 +244,8 @@ github.com/hashicorp/go-uuid v1.0.3 h1:2gKiV6YVmrJ1i2CKKa9obLvRieoRGviZFL26PcT/C
240244
github.com/hashicorp/go-uuid v1.0.3/go.mod h1:6SBZvOh/SIDV7/2o3Jml5SYk/TvGqwFJ/bN7x4byOro=
241245
github.com/hashicorp/golang-lru/v2 v2.0.7 h1:a+bsQ5rvGLjzHuww6tVxozPZFVghXaHOwFs4luLUK2k=
242246
github.com/hashicorp/golang-lru/v2 v2.0.7/go.mod h1:QeFd9opnmA6QUJc5vARoKUSoFhyfM2/ZepoAG6RGpeM=
247+
github.com/hiddeco/sshsig v0.2.0 h1:gMWllgKCITXdydVkDL+Zro0PU96QI55LwUwebSwNTSw=
248+
github.com/hiddeco/sshsig v0.2.0/go.mod h1:nJc98aGgiH6Yql2doqH4CTBVHexQA40Q+hMMLHP4EqE=
243249
github.com/ianlancetaylor/demangle v0.0.0-20210905161508-09a460cdf81d/go.mod h1:aYm2/VgdVmcIU8iMfdMvDMsRAQjcfZSKFby6HOFvi/w=
244250
github.com/in-toto/in-toto-golang v0.9.0 h1:tHny7ac4KgtsfrG6ybU8gVOZux2H8jN05AXJ9EBM1XU=
245251
github.com/in-toto/in-toto-golang v0.9.0/go.mod h1:xsBVrVsHNsB61++S6Dy2vWosKhuA3lUTQd+eF9HdeMo=

hack/fixtures/gen_gpg_test_env.sh

Lines changed: 75 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,75 @@
1+
#!/usr/bin/env sh
2+
3+
set -e
4+
5+
# require BUILDKIT_TEST_SIGN_FIXTURES to be set
6+
if [ -z "$BUILDKIT_TEST_SIGN_FIXTURES" ]; then
7+
echo "BUILDKIT_TEST_SIGN_FIXTURES is not set"
8+
exit 1
9+
fi
10+
11+
# require username parameter
12+
if [ -z "$1" ]; then
13+
echo "Usage: $0 <username>"
14+
echo "Example: $0 user1"
15+
exit 1
16+
fi
17+
18+
USERNAME="$1"
19+
20+
set -x
21+
22+
# make GNUPGHOME global (not per-user), point into sign fixtures
23+
export GNUPGHOME="$BUILDKIT_TEST_SIGN_FIXTURES/gnupg"
24+
25+
mkdir -p "$GNUPGHOME"
26+
27+
cd "$BUILDKIT_TEST_SIGN_FIXTURES"
28+
29+
cat >"${USERNAME}.gpg.conf" <<'EOF'
30+
%no-protection
31+
Key-Type: RSA
32+
Key-Length: 2048
33+
Key-Usage: cert
34+
Name-Real: __NAME_REAL__
35+
Name-Email: __NAME_EMAIL__
36+
Expire-Date: 0
37+
%commit
38+
EOF
39+
# replace placeholders in the generated conf
40+
sed -i'' "s|__NAME_REAL__|${USERNAME} Test User|g" "${USERNAME}.gpg.conf"
41+
sed -i'' "s|__NAME_EMAIL__|${USERNAME}@example.com|g" "${USERNAME}.gpg.conf"
42+
43+
gpg --batch --no-tty --generate-key --pinentry-mode loopback "${USERNAME}.gpg.conf"
44+
45+
FP="$(gpg --list-keys --with-colons "${USERNAME}@example.com" | awk -F: '/^fpr:/ {print $10; exit}')"
46+
47+
gpg --no-tty --pinentry-mode loopback --passphrase test --quick-add-key "$FP" rsa2048 sign 1y
48+
49+
gpg --list-secret-keys --with-subkey-fingerprint
50+
51+
# create a single global git-gpg wrapper that uses the shared GNUPGHOME
52+
cat >"${BUILDKIT_TEST_SIGN_FIXTURES}/git_gpg_sign.sh" <<'EOF'
53+
#!/bin/sh
54+
if [ -z "$BUILDKIT_TEST_SIGN_FIXTURES" ]; then
55+
echo "BUILDKIT_TEST_SIGN_FIXTURES is not set" >&2
56+
exit 1
57+
fi
58+
export GNUPGHOME="$BUILDKIT_TEST_SIGN_FIXTURES/gnupg"
59+
exec gpg --batch --pinentry-mode loopback --passphrase test "$@"
60+
EOF
61+
chmod +x "${BUILDKIT_TEST_SIGN_FIXTURES}/git_gpg_sign.sh"
62+
63+
# create a user-specific gitconfig that points to the single wrapper and key
64+
cat >"${BUILDKIT_TEST_SIGN_FIXTURES}/${USERNAME}.gpg.gitconfig" <<EOF
65+
[gpg]
66+
program = ${BUILDKIT_TEST_SIGN_FIXTURES}/git_gpg_sign.sh
67+
[user]
68+
signingkey = $FP
69+
email = ${USERNAME}@example.com
70+
name = Test Git ${USERNAME}
71+
[commit]
72+
gpgsign = true
73+
EOF
74+
75+
gpg --armor --export "$FP" >"${USERNAME}.gpg.pub"

hack/fixtures/gen_ssh_test_env.sh

Lines changed: 97 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,97 @@
1+
#!/usr/bin/env sh
2+
3+
set -e
4+
5+
# require BUILDKIT_TEST_SIGN_FIXTURES to be set
6+
if [ -z "$BUILDKIT_TEST_SIGN_FIXTURES" ]; then
7+
echo "BUILDKIT_TEST_SIGN_FIXTURES is not set"
8+
exit 1
9+
fi
10+
11+
# require username parameter
12+
if [ -z "$1" ]; then
13+
echo "Usage: $0 <username>"
14+
echo "Example: $0 user1"
15+
exit 1
16+
fi
17+
18+
USERNAME="$1"
19+
20+
set -x
21+
22+
FIXTURES="$BUILDKIT_TEST_SIGN_FIXTURES"
23+
mkdir -p "$FIXTURES"
24+
cd "$FIXTURES"
25+
26+
mkdir -p .ssh
27+
chmod 700 .ssh
28+
KEY_BASE=".ssh/${USERNAME}.id_ed25519"
29+
if [ ! -f "$KEY_BASE" ]; then
30+
ssh-keygen -t ed25519 -C "${USERNAME}@example.com" -f "$KEY_BASE" -N "" -q
31+
fi
32+
33+
# read user's public key
34+
PUBKEY_LINE="$(cat "${KEY_BASE}.pub")"
35+
if [ -z "$PUBKEY_LINE" ]; then
36+
echo "failed to read public key" >&2
37+
exit 1
38+
fi
39+
40+
# create per-user ssh signing wrapper in fixtures root; hardcode username in key path
41+
cat >"${FIXTURES}/${USERNAME}.git_ssh_sign.sh" <<'EOF'
42+
#!/bin/sh
43+
set -eu
44+
unset SSH_AUTH_SOCK || true
45+
base="$(cd "$(dirname "$0")" && pwd)"
46+
47+
# Parse args from Git
48+
buf=""
49+
out=""
50+
args=""
51+
while [ $# -gt 0 ]; do
52+
case "$1" in
53+
-U)
54+
shift
55+
buf="$1"
56+
out="${buf}.sig"
57+
;;
58+
/tmp/.git_signing_key_tmp*)
59+
args="$args -f $base/.ssh/__USER__.id_ed25519"
60+
;;
61+
*)
62+
args="$args $1"
63+
;;
64+
esac
65+
shift
66+
done
67+
68+
# Fallback sanity check
69+
[ -n "$buf" ] || { echo "missing -U buffer" >&2; exit 1; }
70+
71+
# Sign manually without -U
72+
ssh-keygen -Y sign -f "$base/.ssh/__USER__.id_ed25519" -n git "$buf" >/dev/null
73+
74+
# ssh-keygen wrote "$buf.sig"; rename to what Git expects
75+
mv "$buf.sig" "$out"
76+
EOF
77+
78+
# inject username into wrapper
79+
sed -i "s/__USER__/${USERNAME}/g" "${FIXTURES}/${USERNAME}.git_ssh_sign.sh"
80+
chmod +x "${FIXTURES}/${USERNAME}.git_ssh_sign.sh"
81+
82+
# per-user gitconfig pointing to per-user wrapper; no username prefix in signingkey
83+
cat >"${FIXTURES}/${USERNAME}.ssh.gitconfig" <<EOF
84+
[gpg]
85+
format = ssh
86+
[user]
87+
signingkey = ${PUBKEY_LINE}
88+
name = Test Git ${USERNAME}
89+
email = ${USERNAME}@example.com
90+
[commit]
91+
gpgsign = true
92+
[gpg "ssh"]
93+
program = ${FIXTURES}/${USERNAME}.git_ssh_sign.sh
94+
EOF
95+
96+
# export user-labeled public key
97+
cp "${KEY_BASE}.pub" "${USERNAME}.ssh.pub"

source/git/identifier.go

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,15 @@ type GitIdentifier struct {
2121
MountSSHSock string
2222
KnownSSHHosts string
2323
SkipSubmodules bool
24+
25+
VerifySignature *GitSignatureVerifyOptions
26+
}
27+
28+
type GitSignatureVerifyOptions struct {
29+
PubKey []byte
30+
RejectExpiredKeys bool
31+
RequireSignedTag bool // signed tag must be present
32+
IgnoreSignedTag bool // even if signed tag is present, verify signature on commit object
2433
}
2534

2635
func NewGitIdentifier(remoteURL string) (*GitIdentifier, error) {

0 commit comments

Comments
 (0)