diff --git a/test/e2e/12_sync.bats b/test/e2e/12_sync.bats index 99e0cbf38..92aa1290d 100644 --- a/test/e2e/12_sync.bats +++ b/test/e2e/12_sync.bats @@ -84,7 +84,6 @@ function teardown() { rm -rf "$clone_dir" # Teardown the created port-forward to gitsrv and restore Git settings. kill "$git_port_forward_pid" - unset GIT_SSH_COMMAND # Uninstall Flux and the global resources it installs. uninstall_flux_with_fluxctl # Removing the namespace also takes care of removing gitsrv. diff --git a/test/e2e/20_commit_signing.bats b/test/e2e/20_commit_signing.bats index 783a0c912..b00c428ec 100644 --- a/test/e2e/20_commit_signing.bats +++ b/test/e2e/20_commit_signing.bats @@ -6,6 +6,7 @@ load lib/gpg load lib/install load lib/poll +tmp_gnupghome="" git_port_forward_pid="" function setup() { @@ -22,7 +23,6 @@ function setup() { # 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) @@ -66,9 +66,11 @@ function setup() { } function teardown() { - # Teardown the created port-forward to gitsrv and restore Git settings. + # Teardown the created port-forward to gitsrv. kill "$git_port_forward_pid" - unset GIT_SSH_COMMAND + # Kill the agent and remove temporary GNUPGHOME + gpgconf --kill gpg-agent + rm -rf "$tmp_gnupghome" # Uninstall Flux and the global resources it installs. uninstall_flux_gpg # Removing the namespace also takes care of removing Flux and gitsrv. diff --git a/test/e2e/20_commit_verification.bats b/test/e2e/20_commit_verification.bats new file mode 100644 index 000000000..c353c608e --- /dev/null +++ b/test/e2e/20_commit_verification.bats @@ -0,0 +1,111 @@ +#!/usr/bin/env bats + +load lib/env +load lib/gpg +load lib/install +load lib/poll + +tmp_gnupghome="" +git_port_forward_pid="" +clone_dir="" + +function setup() { + kubectl create namespace "${FLUX_NAMESPACE}" + + # Create a temporary GNUPGHOME + tmp_gnupghome=$(mktemp -d) + export GNUPGHOME="$tmp_gnupghome" +} + +@test "Commits are verified" { + # Create a new GPG key and secret + gpg_key=$(create_gpg_key) + create_secret_from_gpg_key "$gpg_key" + + # Install the git server with signed init commit, + # allowing external access + install_git_srv flux-git-deploy git_srv_result true + + # Install Flux with the GPG key, and commit verification enabled + install_flux_gpg "$gpg_key" true + + # shellcheck disable=SC2154 + git_ssh_cmd="${git_srv_result[0]}" + export GIT_SSH_COMMAND="$git_ssh_cmd" + + # shellcheck disable=SC2030 + git_port_forward_pid="${git_srv_result[1]}" + + # Test that the resources from https://github.com/fluxcd/flux-get-started are deployed + poll_until_true 'namespace demo' 'kubectl describe ns/demo' + + # Clone the repo + # shellcheck disable=SC2030 + clone_dir="$(mktemp -d)" + git clone -b master ssh://git@localhost/git-server/repos/cluster.git "$clone_dir" + cd "$clone_dir" + + local sync_tag="flux-sync" + local org_head_hash + org_head_hash=$(git rev-list -n 1 HEAD) + sync_tag_hash=$(git rev-list -n 1 "$sync_tag") + + [ "$sync_tag_hash" = "$org_head_hash" ] + run git verify-commit "$sync_tag_hash" + [ "$status" -eq 0 ] + + # Add an unsigned change + sed -i'.bak' 's%stefanprodan/podinfo:.*%stefanprodan/podinfo:3.1.5%' "${clone_dir}/workloads/podinfo-dep.yaml" + git -c 'user.email=foo@bar.com' -c 'user.name=Foo' commit -am "Bump podinfo" + git push + + # Delete tag + git push --delete origin "$sync_tag" + + # Sync should warn, and put the tag back at the latest verified commit + run fluxctl --k8s-fwd-ns "${FLUX_NAMESPACE}" sync + [ "$status" -eq 0 ] + [[ "$output" == *"Warning: The branch HEAD in the git repo is not verified"* ]] + + git pull -f --tags + sync_tag_hash=$(git rev-list -n 1 "$sync_tag") + [ "$sync_tag_hash" = "$org_head_hash" ] +} + +@test "Does not commit on top of invalid commit" { + # Create a new GPG key and secret + gpg_key=$(create_gpg_key) + create_secret_from_gpg_key "$gpg_key" + + # Install the git server with _unsigned_ init commit + install_git_srv flux-git-deploy "" false + + # Install Flux with the GPG key, and commit verification enabled + install_flux_gpg "$gpg_key" true + + # Wait for Flux to report that it sees an invalid commit + poll_until_true 'invalid GPG signature log' "kubectl logs -n ${FLUX_NAMESPACE} deploy/flux-gpg | grep -e 'found invalid GPG signature for commit'" + + # Attempt to lock a resource, and confirm it returns an error. + run fluxctl --k8s-fwd-ns "${FLUX_NAMESPACE}" lock --workload demo:deployment/podinfo + [ "$status" -eq 1 ] + [[ "$output" == *"Error: HEAD revision is unsigned"* ]] +} + +function teardown() { + # shellcheck disable=SC2031 + rm -rf "$clone_dir" + # (Maybe) teardown the created port-forward to gitsrv. + # shellcheck disable=SC2031 + kill "$git_port_forward_pid" || true + # Kill the agent and remove temporary GNUPGHOME + gpgconf --kill gpg-agent + rm -rf "$tmp_gnupghome" + # Although the namespace delete below takes care of removing most Flux + # elements, the global resources will not be removed without this. + uninstall_flux_gpg + # Removing the namespace also takes care of removing Flux and gitsrv. + kubectl delete namespace "$FLUX_NAMESPACE" + # (Maybe) remove the demo namespace + kubectl delete namespace "$DEMO_NAMESPACE" &> /dev/null || true +} diff --git a/test/e2e/fixtures/gitsrv-gpg.yaml b/test/e2e/fixtures/gitsrv-gpg.yaml new file mode 100644 index 000000000..aa665a599 --- /dev/null +++ b/test/e2e/fixtures/gitsrv-gpg.yaml @@ -0,0 +1,63 @@ +--- +apiVersion: apps/v1 +kind: Deployment +metadata: + labels: + name: gitsrv + name: gitsrv +spec: + replicas: 1 + selector: + matchLabels: + name: gitsrv + template: + metadata: + labels: + name: gitsrv + spec: + containers: + - image: stefanprodan/gitsrv:0.1.3 + name: git + env: + - name: REPO + value: "cluster.git" + - name: TAR_URL + value: "https://github.com/fluxcd/flux-get-started/archive/master.tar.gz" + - name: GPG_KEYFILE + value: /git-server/gpg/flux.asc + ports: + - containerPort: 22 + name: ssh + protocol: TCP + volumeMounts: + - mountPath: /git-server/gpg + name: git-gpg-keys + - mountPath: /git-server/repos + name: git-server-data + - mountPath: /git-server/keys + name: flux-git-deploy + volumes: + - name: flux-git-deploy + secret: + secretName: $GIT_SECRET_NAME + - name: git-server-data + emptyDir: {} + - name: git-gpg-keys + secret: + secretName: $GPG_SECRET_NAME +--- +apiVersion: v1 +kind: Service +metadata: + labels: + name: gitsrv + name: gitsrv +spec: + ports: + - name: ssh + port: 22 + protocol: TCP + targetPort: ssh + selector: + name: gitsrv + type: ClusterIP diff --git a/test/e2e/fixtures/gitsrv.yaml b/test/e2e/fixtures/gitsrv.yaml index eced1a104..d8730b814 100644 --- a/test/e2e/fixtures/gitsrv.yaml +++ b/test/e2e/fixtures/gitsrv.yaml @@ -16,7 +16,7 @@ spec: name: gitsrv spec: containers: - - image: stefanprodan/gitsrv:0.0.12 + - image: stefanprodan/gitsrv:0.1.3 name: git env: - name: REPO diff --git a/test/e2e/fixtures/known_hosts b/test/e2e/fixtures/known_hosts index 27da08378..60ecc5939 100644 --- a/test/e2e/fixtures/known_hosts +++ b/test/e2e/fixtures/known_hosts @@ -1,4 +1,4 @@ # generated with "ssh-keyscan gitsrv" -gitsrv ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABAQC2WoJ2k+WA54pdxw5EGhg9CQBHKDVjHzNNlgRfTGrQBpgQT3/HEBi6BGi2ZmS6o6W9EJfzYzl3PvC+JY6BqcdM8XqbDazC1rkGtlycHd+dFT/TmWvBqJ2Oh+oJNL7IgpjBPJJMdAEc9nzUTTYa7V2A9SeaAyQJKGaftZhHEXTxkxxbWP2an7bzyw9QNCiF/ogQ79DPsp7ly4v4KgeGLSm9AoT/HO5+kJwXX3yQ1hKrFZyhzhaYiwzdApc3iUJtUEz1lKVX+63+WN6qhkbCUjlhfOGyT3qk18sMU6raqKt8uuQeR9f4/xkMXGWQuULhjGwOkju+8Dma8GvnhKKwHf5V -gitsrv ecdsa-sha2-nistp256 AAAAE2VjZHNhLXNoYTItbmlzdHAyNTYAAAAIbmlzdHAyNTYAAABBBFhuyD3SzMaTye/OX51Jb3fgZDxhGnXgJQ6oFvSSwqDGDm4fcueHE979xEPolNe9hn6jGg/2DS3xkU8boPKv8mo= -gitsrv ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIAbLc9veRHa/l/kK6hmRWMA+QoWd8vLtLHbm4v6wj8XU +gitsrv ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABAQC3qgBx5WLHbB+frq8d+iomxrdQPlWcj7NsJSiEz8vYOaRQsQDMtWHHYRt+zBVIH9Q96urBHDZa+B72DsInkO7JxflLVXLenwhNu8u9a0VbbleYnBYWfoNYWv+0tQpilOIasNjA+aLAWsVVjEAPB8RM77QocXnUbthI898f5EbQ1jXLBMPfbY0VRHimqo0EST71q0/PzfQTf/3tWdd8/cqIFfErOp8IEdnAQmJlhlaAMuI6tDAOCGWjSL/JUMQVIvkObWu2a33fm35OD5q+NyCBquM1a11i/M78oKq0xR8l02OcOKtCdPf09cUBwY8yiRRDIa2PVEpmzHcE5YMXY8IL +gitsrv ecdsa-sha2-nistp256 AAAAE2VjZHNhLXNoYTItbmlzdHAyNTYAAAAIbmlzdHAyNTYAAABBBB+7/Q4mchJWXQoc4LCA9RVMcyj673QDHV98D1ZTGeu7iEz7g/mK/V2thcpgD+rsHBh6u5nYwMd9ja3e7YquX2I= +gitsrv ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIC/1fXvsyIQmxhcWIhl3VBYylabjKb2669sPODnK0Zbt diff --git a/test/e2e/lib/install.bash b/test/e2e/lib/install.bash index 1994eb68d..4c0ac13f2 100755 --- a/test/e2e/lib/install.bash +++ b/test/e2e/lib/install.bash @@ -83,7 +83,8 @@ flux_gpg_helm_template="helm template --name flux-gpg function install_flux_gpg() { local key_id=${1} - local gpg_secret_name=${2:-flux-gpg-signing-key} + local git_verify=${2:-false} + local gpg_secret_name=${3:-flux-gpg-signing-key} if [ -z "$key_id" ]; then echo "no key ID provided" >&2 @@ -95,6 +96,7 @@ function install_flux_gpg() { --set-string git.config.data="${GITCONFIG}" \ --set-string ssh.known_hosts="${KNOWN_HOSTS}" \ --set-string git.signingKey="$key_id" \ + --set-string git.verifySignatures="$git_verify" \ --set-string gpgKeys.secretName="$gpg_secret_name" \ "${FLUX_ROOT_DIR}/chart/flux" | kubectl --namespace "${FLUX_NAMESPACE}" apply -f - >&3 @@ -110,22 +112,35 @@ function uninstall_flux_gpg() { } function install_git_srv() { - local secret_name=${1:-flux-git-deploy} + local git_secret_name=${1:-flux-git-deploy} local external_access_result_var=${2} + local gpg_enable=${3:-false} + local gpg_secret_name=${4:-flux-gpg-signing-key} local gen_dir gen_dir=$(mktemp -d) ssh-keygen -t rsa -N "" -f "$gen_dir/id_rsa" defer rm -rf "$gen_dir" - kubectl create secret generic "$secret_name" \ + kubectl create secret generic "$git_secret_name" \ --namespace="${FLUX_NAMESPACE}" \ --from-file="${FIXTURES_DIR}/known_hosts" \ --from-file="$gen_dir/id_rsa" \ --from-file=identity="$gen_dir/id_rsa" \ --from-file="$gen_dir/id_rsa.pub" - sed "s/\$GIT_SECRET_NAME/$secret_name/" < "${E2E_DIR}/fixtures/gitsrv.yaml" | kubectl apply -n "${FLUX_NAMESPACE}" -f - - # wait for the git server to be ready + local template="${E2E_DIR}/fixtures/gitsrv.yaml" + if [ "$gpg_enable" == "true" ]; then + template="${E2E_DIR}/fixtures/gitsrv-gpg.yaml" + fi + + ( + export GIT_SECRET_NAME=$git_secret_name + export GPG_SECRET_NAME=$gpg_secret_name + + envsubst < "$template" | kubectl apply -n "${FLUX_NAMESPACE}" -f - >&3 + ) + + # Wait for the git server to be ready kubectl -n "${FLUX_NAMESPACE}" rollout status deployment/gitsrv if [ -n "$external_access_result_var" ]; then