diff --git a/test/e2e/12_sync.bats b/test/e2e/12_sync.bats index f276f33485..f60041f37d 100644 --- a/test/e2e/12_sync.bats +++ b/test/e2e/12_sync.bats @@ -48,7 +48,6 @@ function setup() { function teardown() { # 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 783a0c9124..7af9891577 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) @@ -68,7 +68,9 @@ function setup() { function teardown() { # Teardown the created port-forward to gitsrv and restore Git settings. 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 0000000000..4213964de8 --- /dev/null +++ b/test/e2e/20_commit_verification.bats @@ -0,0 +1,106 @@ +#!/usr/bin/env bats + +load lib/defer +load lib/env +load lib/gpg +load lib/install +load lib/poll + +tmp_gnupghome="" + +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" + + git_port_forward_pid="${git_srv_result[1]}" + defer kill "$git_port_forward_pid" + + # Test that the resources from https://github.com/fluxcd/flux-get-started are deployed + poll_until_true 'namespace demo' 'kubectl describe ns/demo' + defer kubectl delete namespace "$DEMO_NAMESPACE" + + # 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" + + 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, + # allowing external access + install_git_srv flux-git-deploy git_srv_result 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() { + # 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" +} diff --git a/test/e2e/fixtures/gitsrv-gpg.yaml b/test/e2e/fixtures/gitsrv-gpg.yaml new file mode 100644 index 0000000000..f75320a8f5 --- /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.0 + 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 eced1a1040..aed5ae3592 100644 --- a/test/e2e/fixtures/gitsrv.yaml +++ b/test/e2e/fixtures/gitsrv.yaml @@ -16,13 +16,15 @@ spec: name: gitsrv spec: containers: - - image: stefanprodan/gitsrv:0.0.12 + - image: stefanprodan/gitsrv:0.1.0 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: "" ports: - containerPort: 22 name: ssh diff --git a/test/e2e/fixtures/known_hosts b/test/e2e/fixtures/known_hosts index 27da08378c..dd575725ac 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 AAAAB3NzaC1yc2EAAAADAQABAAABAQCxSccSZ6jNybRRvuNl9Rv4+HNqZ93rPsjRZko5E2kFfd5BMSflISpRK5owVO+YmeggEY3n86hX4CB/dpxYL62ur9QtkYQICL2fmgc40eE6XshsFSuS44PXmv4IrcHkHaqXl7bjbDon8UHLlRPI2ZFPHnvxa1TEth9i0L14tT4NkTbUNQlyAubM1Jxkph64c21zVSbGlaeflTZFbr2+qi0VfC44pxOWy2WMeS+KbApPScQF7LSNhRDXG/mVylOkc4kZfe1N15WOjKGGJiawFCP7/IjbQBoPaPFIAqU++pJ/IuH/Rv5FAZuc+zH1Vw2UtEU3z9STR30DUdqLSW1oEgYr +gitsrv ecdsa-sha2-nistp256 AAAAE2VjZHNhLXNoYTItbmlzdHAyNTYAAAAIbmlzdHAyNTYAAABBBO0Frzlxfern1gNWgnbNK4jDLBcMSuueBuj3n/P2KbHIng5vZocuVlA60YaCwN7bLyWplG/kA8zMVeLI3+Vl5JU= +gitsrv ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIIT2f8tK1sXJBRlwyhUpam6dkQmiBxBnMJcKLE1xvap+ diff --git a/test/e2e/lib/install.bash b/test/e2e/lib/install.bash index 1994eb68d0..4c0ac13f2e 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