diff --git a/test/e2e/12_sync.bats b/test/e2e/12_sync.bats index ece1933c6..8cd94307e 100644 --- a/test/e2e/12_sync.bats +++ b/test/e2e/12_sync.bats @@ -5,7 +5,6 @@ load lib/install load lib/poll load lib/defer -git_ssh_cmd="" git_port_forward_pid="" function setup() { @@ -14,20 +13,20 @@ function setup() { install_git_srv flux-git-deploy git_srv_result # shellcheck disable=SC2154 git_ssh_cmd="${git_srv_result[0]}" + export GIT_SSH_COMMAND="$git_ssh_cmd" # shellcheck disable=SC2154 git_port_forward_pid="${git_srv_result[1]}" install_flux_with_fluxctl } @test "Basic sync test" { - # wait until flux deploys the workloads + # Wait until flux deploys the workloads poll_until_true 'workload podinfo' 'kubectl -n demo describe deployment/podinfo' # Clone the repo and check the sync tag local clone_dir clone_dir="$(mktemp -d)" defer rm -rf "$clone_dir" - export GIT_SSH_COMMAND="$git_ssh_cmd" git clone -b master ssh://git@localhost/git-server/repos/cluster.git "$clone_dir" cd "$clone_dir" local sync_tag_hash @@ -48,6 +47,7 @@ function setup() { function teardown() { kill "$git_port_forward_pid" + unset GIT_SSH_COMMAND # Removing the namespace also takes care of removing Flux and gitsrv. kubectl delete namespace "$FLUX_NAMESPACE" # Only remove the demo workloads after Flux, so that they cannot be recreated. diff --git a/test/e2e/20_commit_signing.bats b/test/e2e/20_commit_signing.bats new file mode 100644 index 000000000..8f97af778 --- /dev/null +++ b/test/e2e/20_commit_signing.bats @@ -0,0 +1,75 @@ +#!/usr/bin/env bats + +load lib/defer +load lib/env +load lib/gpg +load lib/install +load lib/poll + +git_port_forward_pid="" + +function setup() { + kubectl create namespace "${FLUX_NAMESPACE}" &> /dev/null + + # Install the git server, allowing external access + install_git_srv flux-git-deploy git_srv_result + # shellcheck disable=SC2154 + git_ssh_cmd="${git_srv_result[0]}" + export GIT_SSH_COMMAND="$git_ssh_cmd" + # shellcheck disable=SC2154 + git_port_forward_pid="${git_srv_result[1]}" + + # Create a temporary GNUPGHOME + tmp_gnupghome=$(mktemp -d) + export GNUPGHOME="$tmp_gnupghome" + defer rm -rf "$tmp_gnupghome" + + # Install Flux, with a new GPG key and signing enabled + 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' + + # Clone the repo + local clone_dir + clone_dir="$(mktemp -d)" + defer rm -rf "$clone_dir" + git clone -b master ssh://git@localhost/git-server/repos/cluster.git "$clone_dir" + cd "$clone_dir" + + # Test that the tag has been signed, this errors if this isn't the case + git pull -f --tags + git verify-tag --raw flux-sync >&3 +} + +@test "Git commits are signed" { + # Ensure 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 + + # Clone the repo + local clone_dir + clone_dir="$(mktemp -d)" + defer rm -rf "$clone_dir" + git clone -b master ssh://git@localhost/git-server/repos/cluster.git "$clone_dir" + cd "$clone_dir" + + # Test that the commit has been signed, this errors if this isn't the case + git verify-commit --raw HEAD >&3 +} + +function teardown() { + kill "$git_port_forward_pid" + unset GIT_SSH_COMMAND + # Removing the namespace also takes care of removing Flux and gitsrv. + kubectl delete namespace "$FLUX_NAMESPACE" + # Only remove the demo workloads after Flux, so that they cannot be recreated. + kubectl delete namespace "$DEMO_NAMESPACE" +} diff --git a/test/e2e/lib/gpg.bash b/test/e2e/lib/gpg.bash new file mode 100644 index 000000000..46479e847 --- /dev/null +++ b/test/e2e/lib/gpg.bash @@ -0,0 +1,50 @@ +#!/usr/bin/env bash + +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 3d59a0f14..1994eb68d 100755 --- a/test/e2e/lib/install.bash +++ b/test/e2e/lib/install.bash @@ -71,6 +71,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 install_git_srv() { local secret_name=${1:-flux-git-deploy} local external_access_result_var=${2}