From e5c8fb24935be46ba8615394b43a6d410d98a3c3 Mon Sep 17 00:00:00 2001 From: Archanyhm <48973332+archanyhm@users.noreply.github.com> Date: Mon, 13 Sep 2021 17:53:40 +0200 Subject: [PATCH] Add insecure_skip_tls_verify flag (#20) Added a new optional source config option `insecure_skip_tls_verify` that enables passing the `--insecure-skip-tls-verify` option to `kubectl` instead of `--certificate-authority=`. When `true`, the `certificate_authority` source config is ignored and can be omitted in the source config. Default is `false`. Co-authored-by: Justin Griffin --- README.md | 2 ++ assets/check | 2 +- assets/common | 7 ++++ assets/in | 2 +- assets/out | 2 +- test/check.bats | 25 +++++++++++++ test/common.bats | 35 +++++++++++++++++++ ...source-insecure-skip-tls-verify-false.json | 9 +++++ ...-skip-tls-verify-true-ca_file-omitted.json | 8 +++++ ...e-skip-tls-verify-true-params-kubectl.json | 12 +++++++ ...ure-skip-tls-verify-true-with-version.json | 13 +++++++ ...-source-insecure-skip-tls-verify-true.json | 9 +++++ test/in.bats | 32 +++++++++++++++++ test/out.bats | 18 +++++++++- 14 files changed, 172 insertions(+), 4 deletions(-) create mode 100644 test/fixtures/stdin-source-insecure-skip-tls-verify-false.json create mode 100644 test/fixtures/stdin-source-insecure-skip-tls-verify-true-ca_file-omitted.json create mode 100644 test/fixtures/stdin-source-insecure-skip-tls-verify-true-params-kubectl.json create mode 100644 test/fixtures/stdin-source-insecure-skip-tls-verify-true-with-version.json create mode 100644 test/fixtures/stdin-source-insecure-skip-tls-verify-true.json diff --git a/README.md b/README.md index 981998b..9619550 100644 --- a/README.md +++ b/README.md @@ -16,6 +16,8 @@ with a general purpose `put` for running any `kubectl` command. ... -----END CERTIFICATE----- ``` +* `insecure_skip_tls_verify`: _Optional_. If `true`, ignores `certificate_authority` and skips the validity check of the kubernetes server's certificate. Default is `false`. \ + ⚠️ **Warning**: _Use with caution. This makes the HTTPS connection insecure!_ * `resource_types`: _Optional_. Comma separated list of resource type(s) to retrieve (defaults to just `pod`). ```yaml resource_types: deployment,service,pod diff --git a/assets/check b/assets/check index ea0e105..0da986e 100755 --- a/assets/check +++ b/assets/check @@ -30,7 +30,7 @@ queryForVersions() { namespace_arg="--all-namespaces" fi log "\n--> querying k8s cluster ${blue}'${source_url}'${reset} in namespace ${blue}'$(namespace)'${reset} for ${yellow}'${source_resource_types}'${reset} resources..." - new_versions=$(kubectl --server=$source_url --token=$source_token --certificate-authority=$source_ca_file get $source_resource_types $namespace_arg --sort-by='{.metadata.resourceVersion}' -o json | jq '[.items[]]' ) || exit $1 + new_versions=$(kubectl --server=$source_url --token=$source_token ${certificate_arg} get $source_resource_types $namespace_arg --sort-by='{.metadata.resourceVersion}' -o json | jq '[.items[]]' ) || exit $1 log "$new_versions" } diff --git a/assets/common b/assets/common index 0045698..93aa907 100755 --- a/assets/common +++ b/assets/common @@ -97,6 +97,7 @@ source_ca=$(jq -r '.source.certificate_authority // ""' < $payload) source_resource_types=$(jq -r '.source.resource_types // "pod"' < $payload) source_namespace=$(jq -r '.source.namespace | select(.!=null)' < $payload) source_sensitive=$(jq -r '.source.sensitive | select(.!=null)' < $payload) +source_insecure_skip_tls_verify=$(jq -r '.source.insecure_skip_tls_verify // false' < $payload) # write the ca file out (have to pass a file ref to kubectl) source_ca_file=$(mktemp /tmp/resource-ca_file.XXXXXX) @@ -113,3 +114,9 @@ if isSet params_namespace; then elif isSet source_namespace; then namespace_arg="-n $source_namespace" fi + +if isTrue source_insecure_skip_tls_verify; then + certificate_arg="--insecure-skip-tls-verify" +else + certificate_arg="--certificate-authority=$source_ca_file" +fi diff --git a/assets/in b/assets/in index 4870c4d..86fc8e4 100755 --- a/assets/in +++ b/assets/in @@ -40,7 +40,7 @@ fetchResource() { # fetch the requested resource log -p "\nRetrieving ${cyan}${source_resource_types}${reset} resource ${yellow}'$uid'${reset} at version ${yellow}'$resourceVersion'${reset} from cluster at ${blue}'${source_url}'${reset} in namespace ${blue}'$(namespace)'${reset}..." - kubectl --server=$source_url --token=$source_token --certificate-authority=$source_ca_file get $source_resource_types $namespace_arg --sort-by={.metadata.resourceVersion} -o json \ + kubectl --server=$source_url --token=$source_token ${certificate_arg} get $source_resource_types $namespace_arg --sort-by={.metadata.resourceVersion} -o json \ | jq --arg uid $uid --arg resourceVersion $resourceVersion '.items[] | select((.metadata.uid == $uid and .metadata.resourceVersion == $resourceVersion))' \ > $target_dir/resource.json } diff --git a/assets/out b/assets/out index 191ef9e..749b586 100755 --- a/assets/out +++ b/assets/out @@ -24,7 +24,7 @@ invokeKubectl() { fi log -p "\nInvoking ${cyan}kubectl${reset} with args ${yellow}'${params_kubectl}'${reset} targeting cluster at ${blue}'${source_url}'${reset} in namespace ${blue}'$(namespace)'${reset}..." - kubectl --server=$source_url --token=$source_token --certificate-authority=$source_ca_file ${namespace_arg} ${params_kubectl} + kubectl --server=$source_url --token=$source_token ${certificate_arg} ${namespace_arg} ${params_kubectl} } emitResult() { diff --git a/test/check.bats b/test/check.bats index 84bd49b..86cb6ff 100644 --- a/test/check.bats +++ b/test/check.bats @@ -697,3 +697,28 @@ teardown() { run queryForVersions assert_failure } + +@test "[check] GH-20 uses '--insecure-skip-tls-verify' when 'source.insecure_skip_tls_verify' is 'true'" { + # source the common script + source "$SUT_ASSETS_DIR/common" <<< "$(<$BATS_TEST_DIRNAME/fixtures/stdin-source-insecure-skip-tls-verify-true.json)" + + # stub the log function + log() { :; } + export -f log + + # mock kubectl to expect to be called with '--insecure-skip-tls-verify' + local expected_kubectl_args="--server=$source_url --token=$source_token --insecure-skip-tls-verify \ + get $source_resource_types $expected_namespace_arg --sort-by={.metadata.resourceVersion} -o json" + stub kubectl "$expected_kubectl_args : cat $BATS_TEST_DIRNAME/fixtures/kubectl-response.json" + + # source the sut + source "$SUT_ASSETS_DIR/check" + + # run the test + queryForVersions + + assert_equal $(jq length <<< "$new_versions") 3 + assert_equal "$(jq -r '.[0].metadata.name' <<< "$new_versions")" 'namespace-1' + assert_equal "$(jq -r '.[1].metadata.name' <<< "$new_versions")" 'namespace-2' + assert_equal "$(jq -r '.[2].metadata.name' <<< "$new_versions")" 'namespace-other' +} diff --git a/test/common.bats b/test/common.bats index 75fafe0..e5c75fd 100644 --- a/test/common.bats +++ b/test/common.bats @@ -31,6 +31,12 @@ run_with() { assert_equal $(head -n 1 $source_ca_file) 'a-certificate' } +@test "[common] extracts 'source.insecure_skip_tls_verify' as variable 'source_insecure_skip_tls_verify'" { + run_with "stdin-source-insecure-skip-tls-verify-true" + assert isSet source_insecure_skip_tls_verify + assert_equal "$source_insecure_skip_tls_verify" 'true' +} + @test "[common] extracts 'source.resource_types' as variable 'source_resource_types'" { run_with "stdin-source" assert isSet source_resource_types @@ -84,6 +90,30 @@ run_with() { assert notSet namespace_arg } +@test "[common] creates variable 'certificate_arg' with value of '--certificate-authority='" { + run_with "stdin-source" + assert isSet certificate_arg + assert_equal "$certificate_arg" "--certificate-authority=$source_ca_file" +} + +@test "[common] creates variable 'certificate_arg' with value of '--certificate-authority=' when 'source.insecure_skip_tls_verify' is 'false'" { + run_with "stdin-source-insecure-skip-tls-verify-false" + assert isSet certificate_arg + assert_equal "$certificate_arg" "--certificate-authority=$source_ca_file" +} + +@test "[common] creates variable 'certificate_arg' with value of '--insecure-skip-tls-verify' when 'source.insecure_skip_tls_verify' is 'true' (overrides 'source.certificate_authority')" { + run_with "stdin-source-insecure-skip-tls-verify-true" + assert isSet certificate_arg + assert_equal "$certificate_arg" '--insecure-skip-tls-verify' +} + +@test "[common] creates variable 'certificate_arg' with value of '--insecure-skip-tls-verify' when 'source.insecure_skip_tls_verify' is 'true' and 'source.ca_file' omitted" { + run_with "stdin-source-insecure-skip-tls-verify-true-ca_file-omitted" + assert isSet certificate_arg + assert_equal "$certificate_arg" '--insecure-skip-tls-verify' +} + @test "[common] defaults 'source_url' to empty string" { run_with "stdin-source-empty" assert notSet source_url @@ -103,6 +133,11 @@ run_with() { assert_equal "$(head -n 1 $source_ca_file)" '' } +@test "[common] defaults 'source_insecure_skip_tls_verify' to false" { + run_with "stdin-source-empty" + assert_equal "$source_insecure_skip_tls_verify" 'false' +} + @test "[common] defaults 'source_resource_types' to 'pod'" { run_with "stdin-source-empty" assert isSet source_resource_types diff --git a/test/fixtures/stdin-source-insecure-skip-tls-verify-false.json b/test/fixtures/stdin-source-insecure-skip-tls-verify-false.json new file mode 100644 index 0000000..0028ea5 --- /dev/null +++ b/test/fixtures/stdin-source-insecure-skip-tls-verify-false.json @@ -0,0 +1,9 @@ +{ + "source": { + "url": "https://some-server:8443", + "token": "a-token", + "certificate_authority": "a-certificate", + "insecure_skip_tls_verify": false, + "resource_types": "namespaces" + } +} diff --git a/test/fixtures/stdin-source-insecure-skip-tls-verify-true-ca_file-omitted.json b/test/fixtures/stdin-source-insecure-skip-tls-verify-true-ca_file-omitted.json new file mode 100644 index 0000000..5b885ed --- /dev/null +++ b/test/fixtures/stdin-source-insecure-skip-tls-verify-true-ca_file-omitted.json @@ -0,0 +1,8 @@ +{ + "source": { + "url": "https://some-server:8443", + "token": "a-token", + "insecure_skip_tls_verify": true, + "resource_types": "namespaces" + } +} diff --git a/test/fixtures/stdin-source-insecure-skip-tls-verify-true-params-kubectl.json b/test/fixtures/stdin-source-insecure-skip-tls-verify-true-params-kubectl.json new file mode 100644 index 0000000..d694951 --- /dev/null +++ b/test/fixtures/stdin-source-insecure-skip-tls-verify-true-params-kubectl.json @@ -0,0 +1,12 @@ +{ + "source": { + "url": "https://some-server:8443", + "token": "a-token", + "certificate_authority": "a-certificate", + "insecure_skip_tls_verify": true, + "resource_types": "namespaces" + } , + "params": { + "kubectl": "apply -k overlays/prod" + } +} diff --git a/test/fixtures/stdin-source-insecure-skip-tls-verify-true-with-version.json b/test/fixtures/stdin-source-insecure-skip-tls-verify-true-with-version.json new file mode 100644 index 0000000..445028a --- /dev/null +++ b/test/fixtures/stdin-source-insecure-skip-tls-verify-true-with-version.json @@ -0,0 +1,13 @@ +{ + "source": { + "url": "https://some-server:8443", + "token": "a-token", + "certificate_authority": "a-certificate", + "insecure_skip_tls_verify": true, + "resource_types": "namespaces" + }, + "version": { + "uid": "cee83946-92c3-11e9-a784-3497f601230d", + "resourceVersion": 6988465 + } +} diff --git a/test/fixtures/stdin-source-insecure-skip-tls-verify-true.json b/test/fixtures/stdin-source-insecure-skip-tls-verify-true.json new file mode 100644 index 0000000..dd9a0ce --- /dev/null +++ b/test/fixtures/stdin-source-insecure-skip-tls-verify-true.json @@ -0,0 +1,9 @@ +{ + "source": { + "url": "https://some-server:8443", + "token": "a-token", + "certificate_authority": "a-certificate", + "insecure_skip_tls_verify": true, + "resource_types": "namespaces" + } +} diff --git a/test/in.bats b/test/in.bats index ab0e3dc..dc202ac 100644 --- a/test/in.bats +++ b/test/in.bats @@ -227,3 +227,35 @@ gh1SensitiveTrue() { # should emit the version it was given, back out assert_equal "$(jq -r '.version.something' <<< "$output")" 'else' } + +@test "[in] GH-20 uses '--insecure-skip-tls-verify' when 'source.insecure_skip_tls_verify' is 'true'" { + # source the common script + source "$SUT_ASSETS_DIR/common" <<< "$(<$BATS_TEST_DIRNAME/fixtures/stdin-source-insecure-skip-tls-verify-true.json)" + + # stub the log function + log() { :; } + export -f log + + # mock kubectl to expect to be called with '--insecure-skip-tls-verify' + local expected_kubectl_args="--server=$source_url --token=$source_token --insecure-skip-tls-verify \ + get $source_resource_types --all-namespaces --sort-by={.metadata.resourceVersion} -o json" + stub kubectl "$expected_kubectl_args : cat $BATS_TEST_DIRNAME/fixtures/kubectl-response.json" + + # source the sut + source "$SUT_ASSETS_DIR/in" + + # mock the vars that would be set during 'extractVersion()' + target_dir=$BATS_TMPDIR + uid="8fca7c5f-c513-11e9-a16f-1831bfd00891" + resourceVersion=22577654 + + # run the test + fetchResource + + # then a 'resource.json' file contains the retrieved resource + retrieved_resource="$BATS_TMPDIR/resource.json" + assert [ -e "$retrieved_resource" ] + + # and it contains the full resource content + assert_equal "$(jq -r '.metadata.uid' < "$retrieved_resource")" '8fca7c5f-c513-11e9-a16f-1831bfd00891' +} diff --git a/test/out.bats b/test/out.bats index 6c35a7b..5dcbf15 100644 --- a/test/out.bats +++ b/test/out.bats @@ -107,4 +107,20 @@ source_out() { output=$(emitResult 5>&1) assert_equal "$(jq -r '. | any(.metadata[]; .name == "namespace" and .value == "")' <<< "$output")" 'true' -} \ No newline at end of file +} + +@test "[out] GH-20 invoke kubectl with '--insecure-skip-tls-verify' when 'source.insecure_skip_tls_verify' is 'true'" { + source_out "stdin-source-insecure-skip-tls-verify-true-params-kubectl" + + # mock kubectl to expect our invocation + expected_kubectl_args="--server=$source_url --token=$source_token --insecure-skip-tls-verify apply -k overlays/prod" + stub kubectl "$expected_kubectl_args : echo 'stuff the k8s server sends back'" + + output=$(invokeKubectl) + + # verify kubectl was called correctly + unstub kubectl + + # should emit the output of kubectl + assert_equal "$output" 'stuff the k8s server sends back' +}