mirror of
https://github.com/linuxkit/linuxkit.git
synced 2025-07-19 09:16:29 +00:00
scripts: Add a script to push and sign manifests
Also adjust the 'linuxkit/alpine' script to follow the same pattern. The new version of the script extract username/password from the credential helper (or docker) and build and 'expect' script to feed the info to 'notary'. They can be invoked by: DOCKER_CONTENT_TRUST_REPOSITORY_PASSPHRASE="phrase" ./push-manifest.sh ... Signed-off-by: Rolf Neugebauer <rolf.neugebauer@docker.com>
This commit is contained in:
parent
dc91e84223
commit
6d4162343a
108
scripts/push-manifest.sh
Executable file
108
scripts/push-manifest.sh
Executable file
@ -0,0 +1,108 @@
|
|||||||
|
#! /bin/sh
|
||||||
|
|
||||||
|
set -e
|
||||||
|
|
||||||
|
# This script pushes a multiarch manifest for packages and signs it.
|
||||||
|
#
|
||||||
|
# The TARGET must be of the form <org>/<image>:<tag> and this is what
|
||||||
|
# the manifest is pushed to. It assumes that there is are images of
|
||||||
|
# the form <org>/<image>:<tag>-<arch> already on hub.
|
||||||
|
#
|
||||||
|
# If TRUST is not set, the manifest will not be signed.
|
||||||
|
#
|
||||||
|
# For signing, DOCKER_CONTENT_TRUST_REPOSITORY_PASSPHRASE must be set.
|
||||||
|
|
||||||
|
# This should all be replaced with 'docker manifest' once it lands.
|
||||||
|
|
||||||
|
TARGET=$1
|
||||||
|
TRUST=$2
|
||||||
|
|
||||||
|
REPO=$(echo "$TARGET" | cut -d':' -f1)
|
||||||
|
TAG=$(echo "$TARGET" | cut -d':' -f2)
|
||||||
|
|
||||||
|
# Work out credentials. On macOS they are needed for manifest-tool and
|
||||||
|
# we need them for notary on all platforms.
|
||||||
|
case $(uname -s) in
|
||||||
|
Darwin)
|
||||||
|
CRED=$(echo "https://index.docker.io/v1/" | /Applications/Docker.app/Contents/Resources/bin/docker-credential-osxkeychain.bin get)
|
||||||
|
USER=$(echo "$CRED" | jq -r '.Username')
|
||||||
|
PASS=$(echo "$CRED" | jq -r '.Secret')
|
||||||
|
MT_ARGS="--username $USER --password $PASS"
|
||||||
|
;;
|
||||||
|
Linux)
|
||||||
|
CRED=$(cat ~/.docker/config.json | jq -r '.auths."https://index.docker.io/v1/".auth' | base64 -d -)
|
||||||
|
USER=$(echo $CRED | cut -d ':' -f 1)
|
||||||
|
PASS=$(echo $CRED | cut -d ':' -f 2-)
|
||||||
|
# manifest-tool can use docker credentials directly
|
||||||
|
MT_ARGS=
|
||||||
|
;;
|
||||||
|
*)
|
||||||
|
echo "Unsupported platform"
|
||||||
|
exit 1
|
||||||
|
;;
|
||||||
|
esac
|
||||||
|
|
||||||
|
# Push manifest list
|
||||||
|
OUT=$(manifest-tool $MT_ARGS push from-args \
|
||||||
|
--ignore-missing \
|
||||||
|
--platforms linux/amd64,linux/arm64 \
|
||||||
|
--template "$TARGET"-ARCH \
|
||||||
|
--target "$TARGET")
|
||||||
|
|
||||||
|
echo "$OUT"
|
||||||
|
if [ -z "$TRUST" ]; then
|
||||||
|
echo "Not signing $TARGET"
|
||||||
|
exit 0
|
||||||
|
fi
|
||||||
|
|
||||||
|
# Extract sha256 and length from the manifest-tool output
|
||||||
|
SHA256=$(echo "$OUT" | cut -d' ' -f2 | cut -d':' -f2)
|
||||||
|
LEN=$(echo "$OUT" | cut -d' ' -f3)
|
||||||
|
|
||||||
|
# Notary requires a PTY for username/password so use expect for that.
|
||||||
|
export NOTARY_DELEGATION_PASSPHRASE="$DOCKER_CONTENT_TRUST_REPOSITORY_PASSPHRASE"
|
||||||
|
NOTARY_CMD="notary -s https://notary.docker.io -d $HOME/.docker/trust addhash \
|
||||||
|
-p docker.io/$REPO $TAG $LEN --sha256 $SHA256 \
|
||||||
|
-r targets/releases"
|
||||||
|
|
||||||
|
echo '
|
||||||
|
spawn '"$NOTARY_CMD"'
|
||||||
|
set pid [exp_pid]
|
||||||
|
set timeout 60
|
||||||
|
expect {
|
||||||
|
timeout {
|
||||||
|
puts "Expected username prompt"
|
||||||
|
exec kill -9 $pid
|
||||||
|
exit 1
|
||||||
|
}
|
||||||
|
"username: " {
|
||||||
|
send "'"$USER"'\n"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
expect {
|
||||||
|
timeout {
|
||||||
|
puts "Expected password prompt"
|
||||||
|
exec kill -9 $pid
|
||||||
|
exit 1
|
||||||
|
}
|
||||||
|
"password: " {
|
||||||
|
send "'"$PASS"'\n"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
expect {
|
||||||
|
timeout {
|
||||||
|
puts "Expected password prompt"
|
||||||
|
exec kill -9 $pid
|
||||||
|
exit 1
|
||||||
|
}
|
||||||
|
eof {
|
||||||
|
}
|
||||||
|
}
|
||||||
|
set waitval [wait -i $spawn_id]
|
||||||
|
set exval [lindex $waitval 3]
|
||||||
|
exit $exval
|
||||||
|
' | expect -f -
|
||||||
|
|
||||||
|
echo
|
||||||
|
echo "New signed multi-arch image: $REPO:$TAG"
|
||||||
|
echo
|
@ -1,4 +1,5 @@
|
|||||||
#! /bin/sh
|
#! /bin/sh
|
||||||
|
set -e
|
||||||
|
|
||||||
# This script creates a multiarch manifest for the 'linuxkit/alpine'
|
# This script creates a multiarch manifest for the 'linuxkit/alpine'
|
||||||
# image, pushes and signs it. The manifest is pushed with the tag of
|
# image, pushes and signs it. The manifest is pushed with the tag of
|
||||||
@ -9,6 +10,8 @@
|
|||||||
# This script is specific to 'linuxkit/alpine'. For normal packages we
|
# This script is specific to 'linuxkit/alpine'. For normal packages we
|
||||||
# use a different scheme.
|
# use a different scheme.
|
||||||
#
|
#
|
||||||
|
# For signing, DOCKER_CONTENT_TRUST_REPOSITORY_PASSPHRASE must be set.
|
||||||
|
#
|
||||||
# This should all be replaced with 'docker manifest' once it lands.
|
# This should all be replaced with 'docker manifest' once it lands.
|
||||||
|
|
||||||
ORG=$1
|
ORG=$1
|
||||||
@ -16,12 +19,13 @@ IMAGE=$2
|
|||||||
|
|
||||||
IMG_X86_64=$(head -1 versions.x86_64 | sed 's,[#| ]*,,')
|
IMG_X86_64=$(head -1 versions.x86_64 | sed 's,[#| ]*,,')
|
||||||
IMG_ARM64=$(head -1 versions.aarch64 | sed 's,[#| ]*,,')
|
IMG_ARM64=$(head -1 versions.aarch64 | sed 's,[#| ]*,,')
|
||||||
IMG_MANIFEST=$(echo "$IMG_X86_64" | sed 's,\-.*$,,')
|
# Extract the TAG from the x86_64 name and build the manifest target name
|
||||||
IMG_TAG=$(echo "$IMG_MANIFEST" | sed 's,.*:,,')
|
TAG=$(echo "$IMG_X86_64" | sed 's,\-.*$,,' | cut -d':' -f2)
|
||||||
|
TARGET="$ORG/$IMAGE:$TAG"
|
||||||
|
|
||||||
YAML=$(mktemp)
|
YAML=$(mktemp)
|
||||||
cat <<EOF > "$YAML"
|
cat <<EOF > "$YAML"
|
||||||
image: $IMG_MANIFEST
|
image: $TARGET
|
||||||
manifests:
|
manifests:
|
||||||
- image: $IMG_ARM64
|
- image: $IMG_ARM64
|
||||||
platform:
|
platform:
|
||||||
@ -33,20 +37,21 @@ manifests:
|
|||||||
os: linux
|
os: linux
|
||||||
EOF
|
EOF
|
||||||
|
|
||||||
# work out additional arguments. Specifically, on Darwin the hub
|
# Work out credentials. On macOS they are needed for manifest-tool and
|
||||||
# credentials are stored on the keychain and we need to extract them
|
# we need them for notary on all platforms.
|
||||||
# from there
|
|
||||||
case $(uname -s) in
|
case $(uname -s) in
|
||||||
Darwin)
|
Darwin)
|
||||||
CRED=$(echo "https://index.docker.io/v1/" | /Applications/Docker.app/Contents/Resources/bin/docker-credential-osxkeychain.bin get)
|
CRED=$(echo "https://index.docker.io/v1/" | /Applications/Docker.app/Contents/Resources/bin/docker-credential-osxkeychain.bin get)
|
||||||
USER=$(echo "$CRED" | jq -r '.Username')
|
USER=$(echo "$CRED" | jq -r '.Username')
|
||||||
PASS=$(echo "$CRED" | jq -r '.Secret')
|
PASS=$(echo "$CRED" | jq -r '.Secret')
|
||||||
USERPASS="$USER\n$PASS"
|
|
||||||
MT_ARGS="--username $USER --password $PASS"
|
MT_ARGS="--username $USER --password $PASS"
|
||||||
;;
|
;;
|
||||||
Linux)
|
Linux)
|
||||||
|
CRED=$(cat ~/.docker/config.json | jq -r '.auths."https://index.docker.io/v1/".auth' | base64 -d -)
|
||||||
|
USER=$(echo $CRED | cut -d ':' -f 1)
|
||||||
|
PASS=$(echo $CRED | cut -d ':' -f 2-)
|
||||||
|
# manifest-tool can use docker credentials directly
|
||||||
MT_ARGS=
|
MT_ARGS=
|
||||||
USERPASS=$(cat ~/.docker/config.json | jq -r '.auths."https://index.docker.io/v1/".auth' | base64 -d - | sed 's,:,\\n,')
|
|
||||||
;;
|
;;
|
||||||
*)
|
*)
|
||||||
echo "Unsupported platform"
|
echo "Unsupported platform"
|
||||||
@ -58,14 +63,57 @@ esac
|
|||||||
OUT=$(manifest-tool $MT_ARGS push from-spec "$YAML")
|
OUT=$(manifest-tool $MT_ARGS push from-spec "$YAML")
|
||||||
rm "$YAML"
|
rm "$YAML"
|
||||||
echo "$OUT"
|
echo "$OUT"
|
||||||
|
|
||||||
|
# Extract sha256 and length from the manifest-tool output
|
||||||
SHA256=$(echo "$OUT" | cut -d' ' -f2 | cut -d':' -f2)
|
SHA256=$(echo "$OUT" | cut -d' ' -f2 | cut -d':' -f2)
|
||||||
LEN=$(echo "$OUT" | cut -d' ' -f3)
|
LEN=$(echo "$OUT" | cut -d' ' -f3)
|
||||||
|
|
||||||
# Sign manifest (TODO: Use $USERPASS and pass them into notary)
|
NOTARY_DELEGATION_PASSPHRASE="$DOCKER_CONTENT_TRUST_REPOSITORY_PASSPHRASE"
|
||||||
notary -s https://notary.docker.io \
|
|
||||||
-d ~/.docker/trust addhash \
|
|
||||||
-p docker.io/"$ORG"/"$IMAGE" \
|
|
||||||
"$IMG_TAG" "$LEN" --sha256 "$SHA256" \
|
|
||||||
-r targets/releases
|
|
||||||
|
|
||||||
echo "New multi-arch image: $ORG/$IMAGE:$IMG_TAG"
|
# Notary requires a PTY for username/password so use expect for that.
|
||||||
|
export NOTARY_DELEGATION_PASSPHRASE="$DOCKER_CONTENT_TRUST_REPOSITORY_PASSPHRASE"
|
||||||
|
NOTARY_CMD="notary -s https://notary.docker.io -d $HOME/.docker/trust addhash \
|
||||||
|
-p docker.io/"$ORG"/"$IMAGE" $TAG $LEN --sha256 $SHA256 \
|
||||||
|
-r targets/releases"
|
||||||
|
|
||||||
|
echo '
|
||||||
|
spawn '"$NOTARY_CMD"'
|
||||||
|
set pid [exp_pid]
|
||||||
|
set timeout 60
|
||||||
|
expect {
|
||||||
|
timeout {
|
||||||
|
puts "Expected username prompt"
|
||||||
|
exec kill -9 $pid
|
||||||
|
exit 1
|
||||||
|
}
|
||||||
|
"username: " {
|
||||||
|
send "'"$USER"'\n"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
expect {
|
||||||
|
timeout {
|
||||||
|
puts "Expected password prompt"
|
||||||
|
exec kill -9 $pid
|
||||||
|
exit 1
|
||||||
|
}
|
||||||
|
"password: " {
|
||||||
|
send "'"$PASS"'\n"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
expect {
|
||||||
|
timeout {
|
||||||
|
puts "Expected password prompt"
|
||||||
|
exec kill -9 $pid
|
||||||
|
exit 1
|
||||||
|
}
|
||||||
|
eof {
|
||||||
|
}
|
||||||
|
}
|
||||||
|
set waitval [wait -i $spawn_id]
|
||||||
|
set exval [lindex $waitval 3]
|
||||||
|
exit $exval
|
||||||
|
' | expect -f -
|
||||||
|
|
||||||
|
echo
|
||||||
|
echo "New signed multi-arch image: $REPO:$TAG"
|
||||||
|
echo
|
||||||
|
Loading…
Reference in New Issue
Block a user