From 713c03a86bb20c4a840bed185fd3e57fa64194ed Mon Sep 17 00:00:00 2001 From: Hidde Beydals Date: Mon, 28 Oct 2019 11:49:01 +0100 Subject: [PATCH] e2e: test git gpg commit and tag signing --- test/e2e/12_commit_signing.bats | 64 +++++++++++++++++++++++++++++++++ test/e2e/lib/gpg.bash | 57 +++++++++++++++++++++++++++++ test/e2e/lib/install.bash | 38 ++++++++++++++++++++ 3 files changed, 159 insertions(+) create mode 100644 test/e2e/12_commit_signing.bats create mode 100644 test/e2e/lib/gpg.bash diff --git a/test/e2e/12_commit_signing.bats b/test/e2e/12_commit_signing.bats new file mode 100644 index 0000000000..d00dcb4174 --- /dev/null +++ b/test/e2e/12_commit_signing.bats @@ -0,0 +1,64 @@ +#!/usr/bin/env bats + +load lib/defer +load lib/env +load lib/gpg +load lib/install +load lib/poll + +function setup() { + setup_env + kubectl create namespace "${FLUX_NAMESPACE}" + + generate_ssh_secret + install_git_srv + + gnupghome=$(tmp_gnupghome) + defer rm -rfv "$gnupghome" + + gpg_key=$(create_gpg_key) + create_secret_from_gpg_key "$gpg_key" + install_flux_gpg "$gpg_key" +} + +@test "Git sync tag is signed" { + # Test that a resource from https://github.com/fluxcd/flux-get-started is deployed + # This means the Flux instance _should_ have pushed a signed high-watermark tag + poll_until_true 'namespace demo' 'kubectl describe ns/demo' + + # Test that the tag has been signed, this errors if this isn't the case + kubectl --namespace "${FLUX_NAMESPACE}" exec -it deployment/flux-gpg \ + -- sh -c "cd /tmp/flux-gitclone* && git verify-tag flux-sync" >&3 +} + +@test "Git commits are signed" { + # Assure the resource we are going to lock is deployed + poll_until_true 'workload podinfo' 'kubectl -n demo describe deployment/podinfo' + + # Let Flux push a commit + fluxctl --k8s-fwd-ns "${FLUX_NAMESPACE}" lock --workload demo:deployment/podinfo >&3 + + # Sync right away, this will assure the clone we will look at next is up-to-date + fluxctl --k8s-fwd-ns "${FLUX_NAMESPACE}" sync >&3 + + # Test that the commit has been signed + pod=$(kubectl --namespace "${FLUX_NAMESPACE}" get pods --no-headers -l app=flux -o custom-columns=":metadata.name" | tail -n 1) + + kubectl --namespace "${FLUX_NAMESPACE}" exec -it "$pod" \ + -- sh -c "working=\$(mktemp -d) && \ + git clone --branch master /tmp/flux-gitclone* \$working && \ + cd \$working && \ + git verify-commit HEAD" >&3 +} + +function teardown() { + # For debugging purposes (in case the test fails) + echo '>>> Flux logs' + kubectl -n "${FLUX_NAMESPACE}" describe deployment/flux-gpg + kubectl -n "${FLUX_NAMESPACE}" logs deployment/flux-gpg + + kubectl delete namespace "${DEMO_NAMESPACE}" + # This also takes care of removing the generated secret, + # and the deployed Flux instance + kubectl delete namespace "${FLUX_NAMESPACE}" +} diff --git a/test/e2e/lib/gpg.bash b/test/e2e/lib/gpg.bash new file mode 100644 index 0000000000..774c43177c --- /dev/null +++ b/test/e2e/lib/gpg.bash @@ -0,0 +1,57 @@ +#!/usr/bin/env bash + +function tmp_gnupghome() { + local tmp_home + tmp_home=$(mktemp -d) + export GNUPGHOME="$tmp_home" + echo "$tmp_home" +} + +function create_gpg_key() { + local name=${1:-Flux} + local email=${2:-support@weave.works} + + # https://www.gnupg.org/documentation/manuals/gnupg-devel/Unattended-GPG-key-generation.html + local batchcfg + batchcfg=$(mktemp) + + cat >"$batchcfg" <" + Key-Type: 1 + Key-Length: 2048 + Subkey-Type: 1 + Subkey-Length: 2048 + Name-Real: $name + Name-Email: $email + Expire-Date: 0 + %no-protection + %commit + %echo Done +EOF + + # Generate the key with the written config + gpg --batch --gen-key "$batchcfg" + rm "$batchcfg" + + # Find the ID of the key we just generated + local key_id + key_id=$(gpg --no-tty --list-secret-keys --with-colons "$name" 2>/dev/null \ + | awk -F: '/^sec:/ { print $5 }' | tail -1) + echo "$key_id" +} + +function create_secret_from_gpg_key() { + local key_id="${1}" + local secret_name="${2:-flux-gpg-signing-key}" + + if [ -z "$key_id" ]; then + echo "no key ID provided" >&2 + exit 1 + fi + + # Export key to secret + gpg --export-secret-keys "$key_id" | + kubectl --namespace "${FLUX_NAMESPACE}" \ + create secret generic "$secret_name" \ + --from-file=flux.asc=/dev/stdin +} diff --git a/test/e2e/lib/install.bash b/test/e2e/lib/install.bash index 92d2a00984..74272d6186 100755 --- a/test/e2e/lib/install.bash +++ b/test/e2e/lib/install.bash @@ -68,6 +68,44 @@ function uninstall_flux_with_fluxctl() { $fluxctl_install_cmd --namespace "${FLUX_NAMESPACE}" | kubectl delete -f - } +flux_gpg_helm_template="helm template --name flux-gpg + --set image.repository=docker.io/fluxcd/flux + --set image.tag=latest + --set git.url=ssh://git@gitsrv/git-server/repos/cluster.git + --set git.secretName=flux-git-deploy + --set git.pollInterval=10s + --set git.config.secretName=gitconfig + --set git.config.enabled=true + --set registry.excludeImage=*" + +function install_flux_gpg() { + local key_id=${1} + local gpg_secret_name=${2:-flux-gpg-signing-key} + + if [ -z "$key_id" ]; then + echo "no key ID provided" >&2 + exit 1 + fi + + $flux_gpg_helm_template \ + --namespace "${FLUX_NAMESPACE}" \ + --set-string git.config.data="${GITCONFIG}" \ + --set-string ssh.known_hosts="${KNOWN_HOSTS}" \ + --set-string git.signingKey="$key_id" \ + --set-string gpgKeys.secretName="$gpg_secret_name" \ + "${FLUX_ROOT_DIR}/chart/flux" | + kubectl --namespace "${FLUX_NAMESPACE}" apply -f - >&3 +} + +function uninstall_flux_gpg() { + $flux_gpg_helm_template \ + --namespace "${FLUX_NAMESPACE}" \ + --set-string git.config.data="${GITCONFIG}" \ + --set-string ssh.known_hosts="${KNOWN_HOSTS}" \ + "${FLUX_ROOT_DIR}/chart/flux" | + kubectl --namespace "${FLUX_NAMESPACE}" delete -f - >&3 +} + function generate_ssh_secret() { local secret_name=${1:-flux-git-deploy} local gen_dir