diff --git a/0_check_dependencies.sh b/0_prep_check_dependencies.sh similarity index 100% rename from 0_check_dependencies.sh rename to 0_prep_check_dependencies.sh diff --git a/1_prep_platform_login.sh b/1_prep_platform_login.sh new file mode 100755 index 0000000..8a21ce1 --- /dev/null +++ b/1_prep_platform_login.sh @@ -0,0 +1,9 @@ +#!/usr/bin/env bash +set -euo pipefail + +. utils.sh + +if [[ $PLATFORM == openshift ]]; then + oc login -u $OSHIFT_CLUSTER_ADMIN_USERNAME +fi + diff --git a/2_admin_load_conjur_policies.sh b/2_admin_load_conjur_policies.sh new file mode 100755 index 0000000..67838bf --- /dev/null +++ b/2_admin_load_conjur_policies.sh @@ -0,0 +1,138 @@ +#!/usr/bin/env bash +set -euo pipefail + +. utils.sh + +announce "Generating Conjur policy." + +prepare_conjur_cli_image() { + announce "Pulling and pushing Conjur CLI image." + + docker pull cyberark/conjur-cli:$CONJUR_VERSION-latest + + cli_app_image=$(platform_image conjur-cli) + docker tag cyberark/conjur-cli:$CONJUR_VERSION-latest $cli_app_image + + if ! is_minienv; then + docker push $cli_app_image + fi +} + +deploy_conjur_cli() { + announce "Deploying Conjur CLI pod." + + if is_minienv; then + IMAGE_PULL_POLICY='Never' + else + IMAGE_PULL_POLICY='Always' + fi + if [ "$CONJUR_OSS_HELM_INSTALLED" = "true" ]; then + service_account='conjur-oss' + else + service_account='conjur-cluster' + fi + + cli_app_image=$(platform_image conjur-cli) + sed -e "s#{{ CONJUR_SERVICE_ACCOUNT }}#$service_account#g" ./$PLATFORM/conjur-cli.yml | + sed -e "s#{{ DOCKER_IMAGE }}#$cli_app_image#g" | + sed -e "s#{{ IMAGE_PULL_POLICY }}#$IMAGE_PULL_POLICY#g" | + $cli create -f - + + conjur_cli_pod=$(get_conjur_cli_pod_name) + wait_for_it 300 "$cli get pod $conjur_cli_pod -o jsonpath='{.status.phase}'| grep -q Running" +} + +ensure_conjur_cli_initialized() { + announce "Ensure that Conjur CLI pod has a connection with Conjur initialized." + + if [[ "$CONJUR_OSS_HELM_INSTALLED" == "true" ]]; then + conjur_service='conjur-oss' + else + conjur_service='conjur-master' + fi + conjur_url=${CONJUR_APPLIANCE_URL:-https://$conjur_service.$CONJUR_NAMESPACE_NAME.svc.cluster.local} + + $cli exec $1 -- bash -c "yes yes | conjur init -a $CONJUR_ACCOUNT -u $conjur_url" + $cli exec $1 -- conjur authn login -u admin -p $CONJUR_ADMIN_PASSWORD +} + +pushd policy + mkdir -p ./generated + + # NOTE: generated files are prefixed with the test app namespace to allow for parallel CI + + if [[ "$PLATFORM" == "openshift" ]]; then + is_openshift=true + is_kubernetes=false + else + is_openshift=false + is_kubernetes=true + fi + + sed "s#{{ AUTHENTICATOR_ID }}#$AUTHENTICATOR_ID#g" ./templates/cluster-authn-svc-def.template.yml > ./generated/$TEST_APP_NAMESPACE_NAME.cluster-authn-svc.yml + + sed "s#{{ AUTHENTICATOR_ID }}#$AUTHENTICATOR_ID#g" ./templates/project-authn-def.template.yml | + sed "s#{{ IS_OPENSHIFT }}#$is_openshift#g" | + sed "s#{{ IS_KUBERNETES }}#$is_kubernetes#g" | + sed "s#{{ TEST_APP_NAMESPACE_NAME }}#$TEST_APP_NAMESPACE_NAME#g" > ./generated/$TEST_APP_NAMESPACE_NAME.project-authn.yml + + sed "s#{{ AUTHENTICATOR_ID }}#$AUTHENTICATOR_ID#g" ./templates/app-identity-def.template.yml | + sed "s#{{ TEST_APP_NAMESPACE_NAME }}#$TEST_APP_NAMESPACE_NAME#g" > ./generated/$TEST_APP_NAMESPACE_NAME.app-identity.yml + + sed "s#{{ AUTHENTICATOR_ID }}#$AUTHENTICATOR_ID#g" ./templates/authn-any-policy-branch.template.yml | + sed "s#{{ IS_OPENSHIFT }}#$is_openshift#g" | + sed "s#{{ TEST_APP_NAMESPACE_NAME }}#$TEST_APP_NAMESPACE_NAME#g" > ./generated/$TEST_APP_NAMESPACE_NAME.authn-any-policy-branch.yml +popd + +# Create the random database password +password=$(openssl rand -hex 12) + +set_namespace "$CONJUR_NAMESPACE_NAME" + + +announce "Finding or creating a Conjur CLI pod" +conjur_cli_pod=$(get_conjur_cli_pod_name) +if [ -z "$conjur_cli_pod" ]; then + prepare_conjur_cli_image + deploy_conjur_cli + conjur_cli_pod=$(get_conjur_cli_pod_name) +fi +ensure_conjur_cli_initialized $conjur_cli_pod + +announce "Loading Conjur policy." + +$cli exec $conjur_cli_pod -- rm -rf /policy +$cli cp ./policy $conjur_cli_pod:/policy + +$cli exec $conjur_cli_pod -- \ + bash -c " + conjur_appliance_url=${CONJUR_APPLIANCE_URL:-https://conjur-oss.$CONJUR_NAMESPACE_NAME.svc.cluster.local} + CONJUR_ACCOUNT=${CONJUR_ACCOUNT} \ + CONJUR_ADMIN_PASSWORD=${CONJUR_ADMIN_PASSWORD} \ + DB_PASSWORD=${password} \ + TEST_APP_NAMESPACE_NAME=${TEST_APP_NAMESPACE_NAME} \ + TEST_APP_DATABASE=${TEST_APP_DATABASE} \ + /policy/load_policies.sh + " + +$cli exec $conjur_cli_pod -- rm -rf ./policy + +echo "Conjur policy loaded." + +set_namespace "$TEST_APP_NAMESPACE_NAME" + +# Set DB password in Kubernetes manifests +# NOTE: generated files are prefixed with the test app namespace to allow for parallel CI +pushd kubernetes + sed "s#{{ TEST_APP_DB_PASSWORD }}#$password#g" ./postgres.template.yml > ./tmp.${TEST_APP_NAMESPACE_NAME}.postgres.yml + sed "s#{{ TEST_APP_DB_PASSWORD }}#$password#g" ./mysql.template.yml > ./tmp.${TEST_APP_NAMESPACE_NAME}.mysql.yml +popd + +# Set DB password in OC manifests +# NOTE: generated files are prefixed with the test app namespace to allow for parallel CI +pushd openshift + sed "s#{{ TEST_APP_DB_PASSWORD }}#$password#g" ./postgres.template.yml > ./tmp.${TEST_APP_NAMESPACE_NAME}.postgres.yml + sed "s#{{ TEST_APP_DB_PASSWORD }}#$password#g" ./mysql.template.yml > ./tmp.${TEST_APP_NAMESPACE_NAME}.mysql.yml +popd + +announce "Added DB password value: $password" diff --git a/2_load_conjur_policies.sh b/2_load_conjur_policies.sh deleted file mode 100755 index 25648f7..0000000 --- a/2_load_conjur_policies.sh +++ /dev/null @@ -1,79 +0,0 @@ -#!/usr/bin/env bash -set -euo pipefail - -. utils.sh - -announce "Generating Conjur policy." - -pushd policy - mkdir -p ./generated - - # NOTE: generated files are prefixed with the test app namespace to allow for parallel CI - - if [[ "$PLATFORM" == "openshift" ]]; then - is_openshift=true - is_kubernetes=false - else - is_openshift=false - is_kubernetes=true - fi - - sed "s#{{ AUTHENTICATOR_ID }}#$AUTHENTICATOR_ID#g" ./templates/cluster-authn-svc-def.template.yml > ./generated/$TEST_APP_NAMESPACE_NAME.cluster-authn-svc.yml - - sed "s#{{ AUTHENTICATOR_ID }}#$AUTHENTICATOR_ID#g" ./templates/project-authn-def.template.yml | - sed "s#{{ IS_OPENSHIFT }}#$is_openshift#g" | - sed "s#{{ IS_KUBERNETES }}#$is_kubernetes#g" | - sed "s#{{ TEST_APP_NAMESPACE_NAME }}#$TEST_APP_NAMESPACE_NAME#g" > ./generated/$TEST_APP_NAMESPACE_NAME.project-authn.yml - - sed "s#{{ AUTHENTICATOR_ID }}#$AUTHENTICATOR_ID#g" ./templates/app-identity-def.template.yml | - sed "s#{{ TEST_APP_NAMESPACE_NAME }}#$TEST_APP_NAMESPACE_NAME#g" > ./generated/$TEST_APP_NAMESPACE_NAME.app-identity.yml - - sed "s#{{ AUTHENTICATOR_ID }}#$AUTHENTICATOR_ID#g" ./templates/authn-any-policy-branch.template.yml | - sed "s#{{ IS_OPENSHIFT }}#$is_openshift#g" | - sed "s#{{ TEST_APP_NAMESPACE_NAME }}#$TEST_APP_NAMESPACE_NAME#g" > ./generated/$TEST_APP_NAMESPACE_NAME.authn-any-policy-branch.yml -popd - -# Create the random database password -password=$(openssl rand -hex 12) - -if [[ "${DEPLOY_MASTER_CLUSTER}" == "true" ]]; then - - announce "Loading Conjur policy." - - set_namespace "$CONJUR_NAMESPACE_NAME" - conjur_cli_pod=$(get_conjur_cli_pod_name) - - $cli exec $conjur_cli_pod -- rm -rf /policy - $cli cp ./policy $conjur_cli_pod:/policy - - $cli exec $conjur_cli_pod -- \ - bash -c " - CONJUR_ADMIN_PASSWORD=${CONJUR_ADMIN_PASSWORD} \ - DB_PASSWORD=${password} \ - TEST_APP_NAMESPACE_NAME=${TEST_APP_NAMESPACE_NAME} \ - TEST_APP_DATABASE=${TEST_APP_DATABASE} \ - /policy/load_policies.sh - " - - $cli exec $conjur_cli_pod -- rm -rf ./policy - - echo "Conjur policy loaded." - - set_namespace "$TEST_APP_NAMESPACE_NAME" -fi - -# Set DB password in Kubernetes manifests -# NOTE: generated files are prefixed with the test app namespace to allow for parallel CI -pushd kubernetes - sed "s#{{ TEST_APP_DB_PASSWORD }}#$password#g" ./postgres.template.yml > ./tmp.${TEST_APP_NAMESPACE_NAME}.postgres.yml - sed "s#{{ TEST_APP_DB_PASSWORD }}#$password#g" ./mysql.template.yml > ./tmp.${TEST_APP_NAMESPACE_NAME}.mysql.yml -popd - -# Set DB password in OC manifests -# NOTE: generated files are prefixed with the test app namespace to allow for parallel CI -pushd openshift - sed "s#{{ TEST_APP_DB_PASSWORD }}#$password#g" ./postgres.template.yml > ./tmp.${TEST_APP_NAMESPACE_NAME}.postgres.yml - sed "s#{{ TEST_APP_DB_PASSWORD }}#$password#g" ./mysql.template.yml > ./tmp.${TEST_APP_NAMESPACE_NAME}.mysql.yml -popd - -announce "Added DB password value: $password" diff --git a/3_admin_init_conjur_cert_authority.sh b/3_admin_init_conjur_cert_authority.sh new file mode 100755 index 0000000..a168e3b --- /dev/null +++ b/3_admin_init_conjur_cert_authority.sh @@ -0,0 +1,18 @@ +#!/usr/bin/env bash +set -euo pipefail + +. utils.sh + +announce "Initializing Conjur certificate authority." + +set_namespace $CONJUR_NAMESPACE_NAME + +conjur_master=$(get_master_pod_name) + +if [[ "$CONJUR_OSS_HELM_INSTALLED" == "true" ]]; then + $cli exec $conjur_master -c conjur-oss -- bash -c "CONJUR_ACCOUNT=$CONJUR_ACCOUNT rake authn_k8s:ca_init['conjur/authn-k8s/$AUTHENTICATOR_ID']" +else + $cli exec $conjur_master -- chpst -u conjur conjur-plugin-service possum rake authn_k8s:ca_init["conjur/authn-k8s/$AUTHENTICATOR_ID"] +fi + +echo "Certificate authority initialized." diff --git a/3_init_conjur_cert_authority.sh b/3_init_conjur_cert_authority.sh deleted file mode 100755 index 2fe814f..0000000 --- a/3_init_conjur_cert_authority.sh +++ /dev/null @@ -1,14 +0,0 @@ -#!/usr/bin/env bash -set -euo pipefail - -. utils.sh - -announce "Initializing Conjur certificate authority." - -set_namespace $CONJUR_NAMESPACE_NAME - -conjur_master=$(get_master_pod_name) - -$cli exec $conjur_master -- chpst -u conjur conjur-plugin-service possum rake authn_k8s:ca_init["conjur/authn-k8s/$AUTHENTICATOR_ID"] - -echo "Certificate authority initialized." diff --git a/1_create_test_app_namespace.sh b/4_app_create_namespace.sh similarity index 65% rename from 1_create_test_app_namespace.sh rename to 4_app_create_namespace.sh index e8a01ba..3a16b24 100755 --- a/1_create_test_app_namespace.sh +++ b/4_app_create_namespace.sh @@ -5,10 +5,6 @@ set -euo pipefail announce "Creating Test App namespace." -if [[ $PLATFORM == openshift ]]; then - oc login -u $OSHIFT_CLUSTER_ADMIN_USERNAME -fi - set_namespace default if has_namespace "$TEST_APP_NAMESPACE_NAME"; then @@ -26,11 +22,16 @@ else set_namespace $TEST_APP_NAMESPACE_NAME fi -$cli delete --ignore-not-found rolebinding test-app-conjur-authenticator-role-binding-$CONJUR_NAMESPACE_NAME +# A Conjur OSS cluster that was deployed via cyberark/conjur-oss-helm-chart +# includes a ClusterRoleBinding (that has cluster-wide scope), so there is no +# need to create a RoleBinding for this namespace. +if [[ $CONJUR_OSS_HELM_INSTALLED != true ]]; then + $cli delete --ignore-not-found rolebinding test-app-conjur-authenticator-role-binding-$CONJUR_NAMESPACE_NAME -sed "s#{{ TEST_APP_NAMESPACE_NAME }}#$TEST_APP_NAMESPACE_NAME#g" ./$PLATFORM/test-app-conjur-authenticator-role-binding.yml | - sed "s#{{ CONJUR_NAMESPACE_NAME }}#$CONJUR_NAMESPACE_NAME#g" | - $cli create -f - + sed "s#{{ TEST_APP_NAMESPACE_NAME }}#$TEST_APP_NAMESPACE_NAME#g" ./$PLATFORM/test-app-conjur-authenticator-role-binding.yml | + sed "s#{{ CONJUR_NAMESPACE_NAME }}#$CONJUR_NAMESPACE_NAME#g" | + $cli create -f - +fi if [[ $PLATFORM == openshift ]]; then # add permissions for Conjur admin user diff --git a/4_store_conjur_cert.sh b/4_store_conjur_cert.sh deleted file mode 100755 index aaf370a..0000000 --- a/4_store_conjur_cert.sh +++ /dev/null @@ -1,30 +0,0 @@ -#!/usr/bin/env bash -set -euo pipefail - -. utils.sh - -announce "Storing Conjur cert for test app configuration." - -set_namespace $CONJUR_NAMESPACE_NAME - -echo "Retrieving Conjur certificate." - -if $cli get pods --selector role=follower --no-headers; then - follower_pod_name=$($cli get pods --selector role=follower --no-headers | awk '{ print $1 }' | head -1) - ssl_cert=$($cli exec $follower_pod_name -- cat /opt/conjur/etc/ssl/conjur.pem) -else - echo "Regular follower not found. Trying to assume a decomposed follower..." - follower_pod_name=$($cli get pods --selector role=decomposed-follower --no-headers | awk '{ print $1 }' | head -1) - ssl_cert=$($cli exec -c "nginx" $follower_pod_name -- cat /opt/conjur/etc/ssl/cert/tls.crt) -fi - -set_namespace $TEST_APP_NAMESPACE_NAME - -echo "Storing non-secret conjur cert as test app configuration data" - -$cli delete --ignore-not-found=true configmap $TEST_APP_NAMESPACE_NAME - -# Store the Conjur cert in a ConfigMap. -$cli create configmap $TEST_APP_NAMESPACE_NAME --from-file=ssl-certificate=<(echo "$ssl_cert") - -echo "Conjur cert stored." diff --git a/5_app_store_conjur_cert.sh b/5_app_store_conjur_cert.sh new file mode 100755 index 0000000..a04c6f0 --- /dev/null +++ b/5_app_store_conjur_cert.sh @@ -0,0 +1,35 @@ +#!/usr/bin/env bash +set -euo pipefail + +. utils.sh + +announce "Storing Conjur cert for test app configuration." + +set_namespace $CONJUR_NAMESPACE_NAME + +echo "Retrieving Conjur certificate." + +if [[ "$CONJUR_OSS_HELM_INSTALLED" == "true" ]]; then + master_pod_name=$(get_master_pod_name) + ssl_cert=$($cli exec -c "conjur-oss-nginx" $master_pod_name -- cat /opt/conjur/etc/ssl/cert/tls.crt) +else + if $cli get pods --selector role=follower --no-headers; then + follower_pod_name=$($cli get pods --selector role=follower --no-headers | awk '{ print $1 }' | head -1) + ssl_cert=$($cli exec $follower_pod_name -- cat /opt/conjur/etc/ssl/conjur.pem) + else + echo "Regular follower not found. Trying to assume a decomposed follower..." + follower_pod_name=$($cli get pods --selector role=decomposed-follower --no-headers | awk '{ print $1 }' | head -1) + ssl_cert=$($cli exec -c "nginx" $follower_pod_name -- cat /opt/conjur/etc/ssl/cert/tls.crt) + fi +fi + +set_namespace $TEST_APP_NAMESPACE_NAME + +echo "Storing non-secret conjur cert as test app configuration data" + +$cli delete --ignore-not-found=true configmap $TEST_APP_NAMESPACE_NAME + +# Store the Conjur cert in a ConfigMap. +$cli create configmap $TEST_APP_NAMESPACE_NAME --from-file=ssl-certificate=<(echo "$ssl_cert") + +echo "Conjur cert stored." diff --git a/5_build_and_push_containers.sh b/6_app_build_and_push_containers.sh similarity index 100% rename from 5_build_and_push_containers.sh rename to 6_app_build_and_push_containers.sh diff --git a/6_deploy_test_app.sh b/7_app_deploy.sh similarity index 88% rename from 6_deploy_test_app.sh rename to 7_app_deploy.sh index 4b4c06e..d0071d1 100755 --- a/6_deploy_test_app.sh +++ b/7_app_deploy.sh @@ -65,11 +65,24 @@ init_connection_specs() { secretless_image="cyberark/secretless-broker" fi - conjur_follower_name=${CONJUR_FOLLOWER_NAME:-conjur-follower} - conjur_appliance_url=https://$conjur_follower_name.$CONJUR_NAMESPACE_NAME.svc.cluster.local/api - conjur_authenticator_url=https://$conjur_follower_name.$CONJUR_NAMESPACE_NAME.svc.cluster.local/api/authn-k8s/$URLENCODED_AUTHN_ID + if [[ "$CONJUR_OSS_HELM_INSTALLED" == "true" ]]; then + conjur_appliance_url=${CONJUR_APPLIANCE_URL:-https://conjur-oss.$CONJUR_NAMESPACE_NAME.svc.cluster.local} + else + conjur_follower_name=${CONJUR_FOLLOWER_NAME:-conjur-follower} + conjur_appliance_url=https://$conjur_follower_name.$CONJUR_NAMESPACE_NAME.svc.cluster.local/api + fi + conjur_authenticator_url="$conjur_appliance_url/authn-k8s/$URLENCODED_AUTHN_ID" - conjur_authn_login_prefix=host/conjur/authn-k8s/$AUTHENTICATOR_ID/apps/$TEST_APP_NAMESPACE_NAME/$CONJUR_AUTHN_LOGIN_RESOURCE + if [[ "$ANNOTATION_BASED_AUTHN" == "true" ]]; then + # For annotation-based Kubernetes authentication, the host ID to be used + # for authenticating is an application name. + conjur_authn_login_prefix=host/conjur/authn-k8s/$AUTHENTICATOR_ID/apps + else + # For host-ID-based Kubernetes authentication, the host ID to be used + # for authenticating is in the form: + # // + conjur_authn_login_prefix=host/conjur/authn-k8s/$AUTHENTICATOR_ID/apps/$TEST_APP_NAMESPACE_NAME/$CONJUR_AUTHN_LOGIN_RESOURCE + fi } ########################### @@ -145,6 +158,7 @@ deploy_sidecar_app() { sed "s#{{ TEST_APP_NAMESPACE_NAME }}#$TEST_APP_NAMESPACE_NAME#g" | sed "s#{{ AUTHENTICATOR_ID }}#$AUTHENTICATOR_ID#g" | sed "s#{{ CONFIG_MAP_NAME }}#$TEST_APP_NAMESPACE_NAME#g" | + sed "s#{{ SERVICE_TYPE }}#$(app_service_type)#g" | $cli create -f - if [[ "$PLATFORM" == "openshift" ]]; then @@ -180,6 +194,7 @@ deploy_init_container_app() { sed "s#{{ TEST_APP_NAMESPACE_NAME }}#$TEST_APP_NAMESPACE_NAME#g" | sed "s#{{ AUTHENTICATOR_ID }}#$AUTHENTICATOR_ID#g" | sed "s#{{ CONFIG_MAP_NAME }}#$TEST_APP_NAMESPACE_NAME#g" | + sed "s#{{ SERVICE_TYPE }}#$(app_service_type)#g" | $cli create -f - if [[ "$PLATFORM" == "openshift" ]]; then @@ -217,6 +232,7 @@ deploy_init_container_app_with_host_outside_apps() { sed "s#{{ TEST_APP_NAMESPACE_NAME }}#$TEST_APP_NAMESPACE_NAME#g" | sed "s#{{ AUTHENTICATOR_ID }}#$AUTHENTICATOR_ID#g" | sed "s#{{ CONFIG_MAP_NAME }}#$TEST_APP_NAMESPACE_NAME#g" | + sed "s#{{ SERVICE_TYPE }}#$(app_service_type)#g" | $cli create -f - if [[ "$PLATFORM" == "openshift" ]]; then @@ -267,6 +283,7 @@ deploy_secretless_app() { sed "s#{{ CONFIG_MAP_NAME }}#$TEST_APP_NAMESPACE_NAME#g" | sed "s#{{ CONJUR_ACCOUNT }}#$CONJUR_ACCOUNT#g" | sed "s#{{ CONJUR_APPLIANCE_URL }}#$conjur_appliance_url#g" | + sed "s#{{ SERVICE_TYPE }}#$(app_service_type)#g" | $cli create -f - if [[ "$PLATFORM" == "openshift" ]]; then diff --git a/7_verify_authentication.sh b/8_app_verify_authentication.sh similarity index 68% rename from 7_verify_authentication.sh rename to 8_app_verify_authentication.sh index 71bcbb7..d7eb87c 100755 --- a/7_verify_authentication.sh +++ b/8_app_verify_authentication.sh @@ -3,11 +3,16 @@ set -euo pipefail . utils.sh +init_bash_lib RETRIES=150 # Seconds RETRY_WAIT=2 +# Dump some kubernetes resources and Conjur authentication policy if this +# script exits prematurely +DETAILED_DUMP_ON_EXIT=true + function finish { readonly PIDS=( "SIDECAR_PORT_FORWARD_PID" @@ -16,6 +21,11 @@ function finish { "SECRETLESS_PORT_FORWARD_PID" ) + if [[ "$DETAILED_DUMP_ON_EXIT" == "true" ]]; then + dump_kubernetes_resources + dump_authentication_policy + fi + set +u echo -e "\n\nStopping all port-forwarding" @@ -73,22 +83,34 @@ if [[ "$PLATFORM" == "openshift" ]]; then secretless_url="localhost:8083" init_url_with_host_outside_apps="localhost:8084" else - echo "Waiting for services to become available" - check_services(){ - [[ -n "$(service_ip "test-app-summon-init")" ]] && - [[ -n "$(service_ip "test-app-with-host-outside-apps-branch-summon-init")" ]] && - [[ -n "$(service_ip "test-app-summon-sidecar")" ]] && - [[ -n "$(service_ip "test-app-secretless")" ]] - } - bl_retry_constant "${RETRIES}" "${RETRY_WAIT}" check_services - - init_url=$(service_ip test-app-summon-init):8080 - init_url_with_host_outside_apps=$(service_ip test-app-with-host-outside-apps-branch-summon-init):8080 - sidecar_url=$(service_ip test-app-summon-sidecar):8080 - secretless_url=$(service_ip test-app-secretless):8080 + if [[ "$TEST_APP_NODEPORT_SVCS" == "false" ]]; then + echo "Waiting for external IPs to become available" + check_services(){ + [[ -n "$(external_ip "test-app-summon-init")" ]] && + [[ -n "$(external_ip "test-app-with-host-outside-apps-branch-summon-init")" ]] && + [[ -n "$(external_ip "test-app-summon-sidecar")" ]] && + [[ -n "$(external_ip "test-app-secretless")" ]] + } + bl_retry_constant "${RETRIES}" "${RETRY_WAIT}" check_services + + init_url=$(external_ip test-app-summon-init):8080 + init_url_with_host_outside_apps=$(external_ip test-app-with-host-outside-apps-branch-summon-init):8080 + sidecar_url=$(external_ip test-app-summon-sidecar):8080 + secretless_url=$(external_ip test-app-secretless):8080 + else + # Else assume NodePort service type. Use a URL of the form + # : + # The IP address of any node in the cluster will work for NodePort access. + node_ip="$($cli get nodes -o jsonpath='{.items[0].status.addresses[0].address}')" + init_url="$node_ip:$(get_nodeport test-app-summon-init)" + init_url_with_host_outside_apps="$node_ip:$(get_nodeport test-app-with-host-outside-apps-branch-summon-init)" + sidecar_url="$node_ip:$(get_nodeport test-app-summon-sidecar)" + secretless_url="$node_ip:$(get_nodeport test-app-secretless)" + fi fi echo "Waiting for urls to be ready" + check_urls(){ ( curl -sS --connect-timeout 3 "$init_url" && @@ -135,3 +157,5 @@ curl "$sidecar_url"/pets echo -e "\n\nQuerying secretless app\n" curl "$secretless_url"/pets + +DETAILED_DUMP_ON_EXIT=false diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index bf9bda8..58376f8 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -39,3 +39,7 @@ you may find useful. - Run the `./start` script in this repo as usual, and the demo apps will be deployed with your local builds of the authenticator and Secretless. + +- The `ANNOTATION_BASED_AUTHN` environment variable enables you to toggle whether + your deployment uses annotation-configured host identities or if the authentication + type is defined in the identity path. diff --git a/Jenkinsfile b/Jenkinsfile index 5747aca..556e68f 100644 --- a/Jenkinsfile +++ b/Jenkinsfile @@ -13,61 +13,75 @@ pipeline { } stages { - // Postgres Tests - stage('Deploy Demos Postgres') { + // Postgres Tests with Host-ID-based Authn + stage('Deploy Demos Postgres with Host-ID-based Authn') { parallel { - stage('GKE, v5 Conjur, Postgres') { + stage('GKE, v5 Conjur, Postgres, Host-ID-based Authn') { steps { - sh 'cd ci && summon --environment gke ./test gke postgres' + sh 'cd ci && summon --environment gke ./test gke postgres host-id-based' } } - stage('OpenShift v3.9, v5 Conjur, Postgres') { + stage('OpenShift v3.9, v5 Conjur, Postgres, Host-ID-based Authn') { steps { - sh 'cd ci && summon --environment oc ./test oc postgres' + sh 'cd ci && summon --environment oc ./test oc postgres host-id-based' } } - stage('OpenShift v3.10, v5 Conjur, Postgres') { + stage('OpenShift v3.10, v5 Conjur, Postgres, Host-ID-based Authn') { steps { - sh 'cd ci && summon --environment oc310 ./test oc postgres' + sh 'cd ci && summon --environment oc310 ./test oc postgres host-id-based' } } - stage('OpenShift v3.11, v5 Conjur, Postgres') { + stage('OpenShift v3.11, v5 Conjur, Postgres, Host-ID-based Authn') { steps { - sh 'cd ci && summon --environment oc311 ./test oc postgres' + sh 'cd ci && summon --environment oc311 ./test oc postgres host-id-based' } } } } -// MySQL Tests + // Postgres Tests with Annotation-based Authn + stage('Deploy Demos Postgres with Annotation-based Authn') { + parallel { + stage('GKE, v5 Conjur, Postgres, Annotation--based Authn') { + steps { + sh 'cd ci && summon --environment gke ./test gke postgres annotation-based' + } + } + + // TODO: Add OpenShift Annotation-based authentication tests + } + } + + // MySQL Tests stage('Deploy Demos MySQL') { parallel { - stage('GKE, v5 Conjur, MySQL') { + stage('GKE, v5 Conjur, MySQL, Host-ID-based Authn') { steps { - sh 'cd ci && summon --environment gke ./test gke mysql' + sh 'cd ci && summon --environment gke ./test gke mysql host-id-based' } } - stage('OpenShift v3.9, v5 Conjur, MySQL') { + stage('OpenShift v3.9, v5 Conjur, MySQL, Host-ID-based Authn') { steps { - sh 'cd ci && summon --environment oc ./test oc mysql' + sh 'cd ci && summon --environment oc ./test oc mysql host-id-based' } } - stage('OpenShift v3.10, v5 Conjur, MySQL') { + stage('OpenShift v3.10, v5 Conjur, MySQL, Host-ID-based Authn') { steps { - sh 'cd ci && summon --environment oc310 ./test oc mysql' + sh 'cd ci && summon --environment oc310 ./test oc mysql host-id-based' } } - stage('OpenShift v3.11, v5 Conjur, MySQL') { + stage('OpenShift v3.11, v5 Conjur, MySQL, Host-ID-based Authn') { steps { - sh 'cd ci && summon --environment oc311 ./test oc mysql' + sh 'cd ci && summon --environment oc311 ./test oc mysql host-id-based' } } + } } } diff --git a/README.md b/README.md index 515527f..eb57211 100644 --- a/README.md +++ b/README.md @@ -1,184 +1,144 @@ # kubernetes-conjur-demo -This repo demonstrates an app retrieving secrets from a Conjur cluster running -in Kubernetes or OpenShift. The numbered scripts perform the same steps that a -user has to go through when setting up their own applications. +This repo demonstrates an app retrieving secrets from Conjur or a Dynamic Access +Provider (DAP) follower running in Kubernetes or OpenShift. -**Note:** These demo scripts have only been tested with the following products: - - Dynamic Access Provider v10+. Older versions of Conjur Enterprise v4 and Conjur OSS are not supported. - - cyberark/conjur-authn-k8s-client v0.11+ +**Note:** These demo scripts have been tested with the following products: + - Dynamic Access Provider v11+ or Conjur OSS v1.5+. + - Older versions of Conjur Enterprise v4 are not supported. + - cyberark/conjur-authn-k8s-client v0.18+ - cyberark/secretless-broker v1.0+ -# Setup +## Demo Workflow -### Platform +This demo works with both Conjur OSS and DAP. You can tailor the specific +steps that the demo scripts perform using environment variable settings, +based on your specific needs (e.g. do you want the scripts to load policy +into Conjur master, or will you be doing that independently) and whether +you are using Conjur OSS or DAP. -If you are working with OpenShift, you will need to begin by setting: +The steps, or workflow, that the scripts perform can be categorized into +three phases (the `Security Admin Steps` phase being optional): -``` -export PLATFORM=openshift -``` +- Demo Preparation: + - Check for required environment settings + - Log into the OpenShift platform, if using OpenShift -Otherwise, this variable will default to `kubernetes`. +- Security Admin Steps (Optional): + - Create a Conjur CLI deployment for demo to use, if not already present + - Load Conjur policies for the application into Conjur master + - Initialize the Conjur master's certificate authority -### Deploying Conjur +- Demo Application Deployment: + - Create a demo application namespace + - Create a RoleBinding to allow the Conjur Kubernetes authenticator + to access resources in the demo application namespace + - Retrieve the Conjur CA certificate and store it in a ConfigMap + - Build demo application containers and push them to a registry + - Deploy a few instances of the [pet store](https://github.com/conjurdemos/pet-store-demo/) + demo application (including its database) set up to run with: + - [Secretless Broker](https://github.com/cyberark/secretless-broker) sidecar + to manage the database connection + - [Conjur Kubernetes Authenticator Client](https://github.com/cyberark/conjur-authn-k8s-client) + sidecar to provide the Conjur access token, and Summon to inject the database + credentials into the app environment + - [Conjur Kubernetes Authenticator Client](https://github.com/cyberark/conjur-authn-k8s-client) + init container to provide the Conjur access token, and Summon to inject the database + credentials into the app environment + - Verify that demo applications can be accessed and are retrieving + secrets from Conjur, and print a summary -Before running this demo you will need to [set up a Conjur cluster](https://github.com/cyberark/kubernetes-conjur-deploy) -in your Kubernetes environment. It is recommended that you **set up a separate -Conjur cluster** purely for the purpose of running this demo as it loads Conjur -policy that you would not want to be present in your production environment. +You may choose to skip the `Security Admin Steps` for example if you plan on +loading Conjur policy separately from these scripts. -### Script Configuration +## The Pet Store App -You will need to provide a name for the kubernetes namespace in which your test app -will be deployed AND the database type to deploy with the app: +The pet store demo app is based on the `cyberark/demo-app` Docker image. It can +be deployed with a PostgreSQL or MySQL database and the DB credentials are stored +in Conjur. -``` -export TEST_APP_NAMESPACE_NAME=test-app -export TEST_APP_DATABASE=mysql -``` -As found at boostrap.env +## Requirements -You will also need to set several environment variables to match the values used -when configuring your Conjur deployment. Note that if you may already have these -variables set if you're using the same shell to run the demo: +This demo works with both Conjur OSS and DAP, but the requirements vary depending +on which you are using. -``` -export CONJUR_NAMESPACE_NAME= -export DOCKER_REGISTRY_URL= -export DOCKER_REGISTRY_PATH=/ -export CONJUR_ACCOUNT= -export CONJUR_ADMIN_PASSWORD= -export AUTHENTICATOR_ID= -``` +To run this demo, you must load policy. You may want to **set up a separate +Conjur cluster** purely for the purpose of running this demo since you may not want +to load demo policy in your production environment. -If you would like your applications to use a deployment name as an -authentication identity when authenticating with Kubernetes (as opposed to -using service account name), then set the following: +There are a couple of options available for deploying a Conjur cluster: -``` -export CONJUR_AUTHN_LOGIN_RESOURCE=deployment -``` -Otherwise, this variable will default to `service_account`, and the service -account name will be used when authenticating your application with -Kubernetes. - -Also, if using a private Docker registry: +- You can deploy a demo Conjur DAP cluster, including a Conjur master node + and several Conjur follower nodes using the + [Kubernetes Conjur deploy scripts](https://github.com/cyberark/kubernetes-conjur-deploy). + See the [demo guide to deploying a master cluster](https://github.com/cyberark/kubernetes-conjur-deploy/blob/master/CONTRIBUTING.md#deploying-conjur-master-and-followers-test-and-demo-only) + for more information. +- You can deploy a Conjur OSS cluster using the + [Conjur OSS Helm Chart](https://github.com/cyberark/conjur-oss-helm-chart). -``` -export DOCKER_USERNAME= -export DOCKER_PASSWORD= -export DOCKER_EMAIL= -``` +### Requirements for Conjur OSS -# Usage +Supported platforms: +- Kubernetes v1.16+ -Before getting started, you will need to prepare Conjur. This includes: -- Initializing Conjur's Kubernetes authenticator certificate authority -- Loading the Conjur policies that add host identities, application secrets, - and entitlements +- To run this demo with Conjur OSS, you must have deployed Conjur OSS to your + Kubernetes cluster using the [helm chart](https://github.com/cyberark/conjur-oss-helm-chart). +- You must have credentials for a Conjur user that can load policy -## Initializing the authenticator CA +### Requirements for Dynamic Access Provider -In order to use Conjur's Kubernetes authenticator, Conjur must be configured to -act as a certificate authority so that it can create a client certificate to -establish mutual TLS with authenticator clients. +Supported platforms: +- Kubernetes v1.16+ +- OpenShift 3.11 -To initialize the authenticator certificate authority in your Conjur cluster, -exec into the Conjur master and run: +To run this demo with DAP, you must have deployed a DAP follower to your +Kubernetes cluster following the [documentation](https://docs.cyberark.com/Product-Doc/OnlineHelp/AAM-DAP/Latest/en/Content/Integrations/ConjurDeployFollowers.htm). -``` -chpst -u conjur \ - conjur-plugin-service possum \ - rake authn_k8s:ca_init["conjur/authn-k8s/"] -```` -where you replace `` with the authenticator ID your application -will be using. - -*Note: if you have been following the [Conjur documentation](https://docs.conjur.org/Latest/en/Content/Integrations/Kubernetes_deployConjur.htm), +*Note: if you have been following the [DAP documentation](https://docs.conjur.org/Latest/en/Content/Integrations/Kubernetes_deployConjur.htm), you may have completed this step while you were already logged into the Conjur master. If not, you will need to do so now.* - -## Loading the Conjur policies - -To generate the Conjur policies, you can run `./2_load_conjur_policies.sh`. Running -this script will also auto-generate a random database password that you will have to -load into your Conjur variables, and it will echo this password to the screen as +## Usage instructions + +To run this demo via the command line, ensure you are logged in to the correct +cluster. Make sure you have followed the instructions in the +[requirements](#requirements) section so that your Conjur environment is prepared. + +Set the following variables in your local environment: + +| Environment Variable | Definition | Mandatory | Default | Example | +|--|--|--|--|--| +| `AUTHENTICATOR_ID` | The Conjur Kubernetes authenticator ID to use in Conjur policy (refer to the [documentation on enabling Conjur authenticators](https://docs.cyberark.com/Product-Doc/OnlineHelp/AAM-DAP/Latest/en/Content/Integrations/Kubernetes_deployApplicationCluster.htm?tocpath=Integrations%7COpenShift%252C%20Kubernetes%7C_____5)). | Yes | - | `my-authn-id` | +| `CONFIGURE_CONJUR_MASTER` | Boolean to determine if security admin steps described above (initialize Conjur CA, configure Conjur policy) should be performed by the scripts. NOTE: This setting only applies when running the scripts with DAP. When running with Conjur OSS (i.e. when `CONJUR_OSS_HELM_INSTALLED` is set to `true`), then security admin steps are performed regardless of this setting. | No | `false` | `true` | +| `CONJUR_ACCOUNT` | The account your Conjur / DAP cluster is configured to use. | Yes | - | `myConjurAccount` | +| `CONJUR_ADMIN_PASSWORD` | The `admin` user password that was created when you created the account on your Conjur / DAP cluster. | Yes | - | | +| `CONJUR_AUTHN_LOGIN_RESOURCE` | Type of Kubernetes resource to use as Conjur [application identity](https://docs.cyberark.com/Product-Doc/OnlineHelp/AAM-DAP/Latest/en/Content/Integrations/Kubernetes_AppIdentity.htm). | No | `service_account` | `deployment` | +| `CONJUR_NAMESPACE_NAME` | The namespace to which Conjur was deployed. | Yes | - | `conjur-namespace` | +| `CONJUR_OSS_HELM_INSTALLED` | Set to `true` if you are using Conjur OSS. | No | `false` | `true` | +| `DOCKER_REGISTRY_URL` | Set to the Docker registry to use for your platform for pushing/pulling application images that get built by the script. Examples are `docker.io` for DockerHub or `us.gcr.io` for GKE. | Yes | - | `us.gcr.io` | +| `DOCKER_REGISTRY_PATH` | Set to the Docker organization to use for your platform for pushing/pulling application images that get built by the script. | Yes | - | `myorganization` | +| `PLATFORM` | Set this variable to `kubernetes` or `openshift`, depending on which type of cluster you will be running the demo in. | No | `kubernetes` | `openshift` | +| `TEST_APP_DATABASE` | The type of database to run with the pet store app. Supported values are `mysql`, `mssql`, and `postgres`. | Yes | - | `mysql` | +| `TEST_APP_NAMESPACE_NAME` | The Kubernetes namespace in which your test app will be deployed. The demo scripts create this namespace for you if necessary. | Yes | - | `demo-namespace` | +| `TEST_APP_NODEPORT_SVCS` | Boolean to determine whether to use NodePort type service instead of LoadBalancer services. When running MiniKube or Kubernetes-in-Docker, you may want to set this to `true`. | No | `false` | `true` | + +The demo scripts determine whether to use the `kubectl` or `oc` CLI +based on your `PLATFORM` environment variable configuration. + +**Note**: if you are using a private Docker registry, you will also need to set: ``` -Added DB password value: 4664ab5bb33cee15336868ed +export DOCKER_USERNAME= +export DOCKER_PASSWORD= +export DOCKER_EMAIL= ``` -Once you've run this script and generated the policy files, you can run a Conjur CLI container and load the -policies in your Conjur master. Make sure that you correctly pass the DB -password to the Docker container as demonstrated below, and update the command -below with the URL of your Conjur master instance. -``` -# replace the password value with your DB's password -$ db_password=4664ab5bb33cee15336868ed -$ docker run \ - --rm -it \ - -v $PWD/policy:/policy \ - -e DB_PASSWORD=$db_password \ - -e CONJUR_APPLIANCE_URL= \ - -e CONJUR_ACCOUNT=$CONJUR_ACCOUNT \ - -e CONJUR_AUTHN_LOGIN="admin" \ - -e CONJUR_ADMIN_PASSWORD=$CONJUR_ADMIN_PASSWORD \ - -e TEST_APP_DATABASE=$TEST_APP_DATABASE \ - -e TEST_APP_NAMESPACE_NAME=$TEST_APP_NAMESPACE_NAME \ - cyberark/conjur-cli:5 - -root@0b86d4e8d4e7:/# ./policy/load_policies.sh - -SHA1 Fingerprint=C4:95:D4:F2:5C:06:7F:79:E5:0D:BF:AD:92:3C:40:28:32:F8:66:C4 - -Please verify this certificate on the appliance using command: - openssl x509 -fingerprint -noout -in ~conjur/etc/ssl/conjur.pem - -Trust this certificate (yes/no): yes -Wrote certificate to /root/conjur-example.pem -Wrote configuration to /root/.conjurrc -Logged in -Loaded policy 'root' -... -Loading secret values for test-summon-init-app -Value added -Value added -Value added -Loading secret values for test-summon-sidecar-app -Value added -Value added -Value added -Loading secret values for test-secretless-app -Value added -Value added -Value added - -root@0b86d4e8d4e7:/# exit -``` +Once you have: +- Reviewed the [requirements](#requirements) to ensure your Conjur / DAP server is set up correctly +- Logged into your Kubernetes cluster via the local command line +- Set your local environment as defined above -After loading the policies, run `./start` to execute the numbered scripts, -which will step through the process of deploying test apps. - -#### Optional master cluster in Kubernetes (*Test and Demo Only*) -If you're running the scripts in this repo after deploying a Conjur cluster to -Kubernetes using the scripts in [`kubernetes-conjur-deploy`](https://github.com/cyberark/kubernetes-conjur-deploy) -with `DEPLOY_MASTER_CLUSTER=true` set, you can just run `./start` to deploy your -demo apps. - -## Demo Applications -The test app is based on the `cyberark/demo-app` Docker image -([GitHub repo](https://github.com/conjurdemos/pet-store-demo)). It can be deployed -with a PostgreSQL or MySQL database and the DB credentials are stored in Conjur. -The app uses Summon at runtime to retrieve the credentials it needs to connect -with the DB, and it authenticates to Conjur using the access token provided by -the authenticator sidecar. - -There are three iterations of this app that are deployed: -- App with sidecar authenticator client (to provide continuously refreshed Conjur access tokens) -- App with init container authenticator client (to provide a one-time Conjur access token on start) -- Secretless app with [Secretless Broker](https://github.com/cyberark/secretless-broker) - deployed as a sidecar, managing the credential retrieval / injection for the app +Run `./start` from the root directory of this repository to execute the numbered +scripts and step through the process of deploying test apps. ## Contributing diff --git a/bootstrap.env b/bootstrap.env index 6069eb7..e7a6b04 100644 --- a/bootstrap.env +++ b/bootstrap.env @@ -3,3 +3,18 @@ export TEST_APP_NAMESPACE_NAME=[choose the namespace to deploy your apps to] export TEST_APP_DATABASE=[choose the database to deploy your apps with (mysql|postgres) ] export CONJUR_ACCOUNT=[Conjur account] export CONJUR_ADMIN_PASSWORD=[password of Conjur admin user] +export ANNOTATION_BASED_AUTHN=[true or false, defaults to false] +export CONJUR_OSS_HELM_INSTALLED=[true or false, defaults to false] +export TEST_APP_NODEPORT_SVCS=[true or false, defaults to false] + +# Set these explicitly if not using the kubernetes-conjur-deploy scripts. +export CONJUR_NAMESPACE_NAME=[namespace where Conjur is deployed] +export AUTHENTICATOR_ID=[authenticator ID] +export DOCKER_REGISTRY_URL=[set to Docker registry domain] +export DOCKER_REGISTRY_PATH=[set to Docker organization] + +# Set these if using a private Dockerhub account +export DOCKER_USERNAME=[Docker username] +export DOCKER_PASSWORD=[Docker password] +export DOCKER_EMAIL=[Docker email] + diff --git a/ci/test b/ci/test index 19bee85..0c4127f 100755 --- a/ci/test +++ b/ci/test @@ -1,7 +1,7 @@ #!/usr/bin/env bash # Usage: -# ./test [platform] [database] +# ./test [platform] [database] [authn-mode] # # Note: This script expects several environment variables to be # defined and exported, some of which are sensitive/secret values. @@ -12,6 +12,7 @@ # # platform: gke or oc # database: postgres or mysql +# authn-mode: annotation-based or host-id-based set -euo pipefail IFS=$'\n\t' @@ -39,15 +40,16 @@ trap finish EXIT function printUsage() { echo "---" echo "Usage:" - echo "./test [platform] [database]" + echo "./test [platform] [database] [authn-mode]" echo "" echo "Note: This script expects several environment variables to be defined and exported, some of which are sensitive/secret values. It is for this that we recommend to always call this script using summon." echo "" echo "Recommended Usage:" - echo "summon --environment [platform] ./test [platform] [database]" + echo "summon --environment [platform] ./test [platform] [database] [authn-mode]" echo "" echo "platform: gke or oc" echo "database: postgres or mysql" + echo "authn-mode: annotation-based or host-id-based" exit 1 } @@ -89,6 +91,7 @@ function prepareTestEnvironment() { export CONJUR_NAMESPACE_NAME=conjur-5-$UNIQUE_TEST_ID-test export AUTHENTICATOR_ID=conjur-5-$UNIQUE_TEST_ID-test export TEST_APP_NAMESPACE_NAME=test-app-5-$UNIQUE_TEST_ID + export CONFIGURE_CONJUR_MASTER=true export DEPLOY_MASTER_CLUSTER=true @@ -129,6 +132,7 @@ function deleteRegistryImage() { function runDockerCommand() { docker run --rm \ -i \ + -e ANNOTATION_BASED_AUTHN \ -e CONJUR_APPLIANCE_IMAGE \ -e CONJUR_NAMESPACE_NAME \ -e CONJUR_ACCOUNT \ @@ -136,6 +140,7 @@ function runDockerCommand() { -e AUTHENTICATOR_ID \ -e TEST_APP_NAMESPACE_NAME \ -e TEST_APP_DATABASE \ + -e CONFIGURE_CONJUR_MASTER \ -e PLATFORM \ -e TEST_PLATFORM \ -e DOCKER_REGISTRY_URL \ @@ -175,7 +180,9 @@ function announce() { # Check that the argument values are valid function checkArguments() { if [[ "$TEST_PLATFORM" != "gke" && "$TEST_PLATFORM" != "oc" ]]; then - echo "The only valid platform values are 'gke' and 'oc'" + echo "The only valid platform values are 'gke' and 'oc'" + elif [[ "$TEST_AUTHN_MODE" != "annotation-based" && "$TEST_AUTHN_MODE" != "host-id-based" ]]; then + echo "The only valid authentication modes are 'annotation-based' and 'host-id-based'" else return 0 fi @@ -184,16 +191,22 @@ function checkArguments() { } # Parse input arguments -if [[ $# -ne 2 ]]; then +if [[ $# -ne 3 ]]; then echo "Invalid number of arguments." printUsage fi TEST_PLATFORM="$1" TEST_APP_DATABASE="$2" +TEST_AUTHN_MODE="$3" export TEST_PLATFORM export TEST_APP_DATABASE +if [[ "$TEST_AUTHN_MODE" == "annotation-based" ]]; then + export ANNOTATION_BASED_AUTHN=true +else + export ANNOTATION_BASED_AUTHN=false +fi # sensible default for OPENSHIFT_URL port if [[ -n "${OPENSHIFT_URL}" ]] && [[ "${OPENSHIFT_URL}" != *: ]]; then diff --git a/kubernetes/conjur-cli.yml b/kubernetes/conjur-cli.yml new file mode 100644 index 0000000..891f107 --- /dev/null +++ b/kubernetes/conjur-cli.yml @@ -0,0 +1,27 @@ +--- +apiVersion: apps/v1 +kind: Deployment +metadata: + name: conjur-cli + labels: + app: conjur-cli +spec: + replicas: 1 + selector: + matchLabels: + app: conjur-cli + template: + metadata: + name: conjur-cli + labels: + app: conjur-cli + spec: + serviceAccountName: {{ CONJUR_SERVICE_ACCOUNT }} + containers: + - name: conjur-cli + image: {{ DOCKER_IMAGE }} + imagePullPolicy: {{ IMAGE_PULL_POLICY }} + command: ["sleep"] + args: ["infinity"] + imagePullSecrets: + - name: dockerpullsecret diff --git a/kubernetes/test-app-secretless.yml b/kubernetes/test-app-secretless.yml index 235cac9..5f4bcdd 100644 --- a/kubernetes/test-app-secretless.yml +++ b/kubernetes/test-app-secretless.yml @@ -11,7 +11,7 @@ spec: targetPort: 8080 selector: app: test-app-secretless - type: LoadBalancer + type: {{ SERVICE_TYPE }} --- apiVersion: v1 kind: ServiceAccount diff --git a/kubernetes/test-app-summon-init.yml b/kubernetes/test-app-summon-init.yml index e7d7f72..bdb0220 100644 --- a/kubernetes/test-app-summon-init.yml +++ b/kubernetes/test-app-summon-init.yml @@ -11,7 +11,7 @@ spec: targetPort: 8080 selector: app: test-app-summon-init - type: LoadBalancer + type: {{ SERVICE_TYPE }} --- apiVersion: v1 kind: ServiceAccount diff --git a/kubernetes/test-app-summon-sidecar.yml b/kubernetes/test-app-summon-sidecar.yml index 14655f1..6940198 100644 --- a/kubernetes/test-app-summon-sidecar.yml +++ b/kubernetes/test-app-summon-sidecar.yml @@ -11,7 +11,7 @@ spec: targetPort: 8080 selector: app: test-app-summon-sidecar - type: LoadBalancer + type: {{ SERVICE_TYPE }} --- apiVersion: v1 kind: ServiceAccount diff --git a/kubernetes/test-app-with-host-outside-apps-branch-summon-init.yml b/kubernetes/test-app-with-host-outside-apps-branch-summon-init.yml index fa1820d..681a709 100644 --- a/kubernetes/test-app-with-host-outside-apps-branch-summon-init.yml +++ b/kubernetes/test-app-with-host-outside-apps-branch-summon-init.yml @@ -12,7 +12,7 @@ spec: targetPort: 8080 selector: app: test-app-with-host-outside-apps-branch-summon-init - type: LoadBalancer + type: {{ SERVICE_TYPE }} --- apiVersion: v1 kind: ServiceAccount diff --git a/openshift/conjur-cli.yml b/openshift/conjur-cli.yml new file mode 100644 index 0000000..891f107 --- /dev/null +++ b/openshift/conjur-cli.yml @@ -0,0 +1,27 @@ +--- +apiVersion: apps/v1 +kind: Deployment +metadata: + name: conjur-cli + labels: + app: conjur-cli +spec: + replicas: 1 + selector: + matchLabels: + app: conjur-cli + template: + metadata: + name: conjur-cli + labels: + app: conjur-cli + spec: + serviceAccountName: {{ CONJUR_SERVICE_ACCOUNT }} + containers: + - name: conjur-cli + image: {{ DOCKER_IMAGE }} + imagePullPolicy: {{ IMAGE_PULL_POLICY }} + command: ["sleep"] + args: ["infinity"] + imagePullSecrets: + - name: dockerpullsecret diff --git a/openshift/test-app-secretless.yml b/openshift/test-app-secretless.yml index 5d5f893..140d016 100644 --- a/openshift/test-app-secretless.yml +++ b/openshift/test-app-secretless.yml @@ -12,7 +12,7 @@ spec: targetPort: 8080 selector: app: test-app-secretless - type: LoadBalancer + type: {{ SERVICE_TYPE }} --- apiVersion: v1 kind: ServiceAccount diff --git a/openshift/test-app-summon-init.yml b/openshift/test-app-summon-init.yml index 4b3ea33..dbe30e6 100644 --- a/openshift/test-app-summon-init.yml +++ b/openshift/test-app-summon-init.yml @@ -12,7 +12,7 @@ spec: targetPort: 8080 selector: app: test-app-summon-init - type: LoadBalancer + type: {{ SERVICE_TYPE }} --- apiVersion: v1 kind: ServiceAccount diff --git a/openshift/test-app-summon-sidecar.yml b/openshift/test-app-summon-sidecar.yml index 590cb6c..a9647c1 100644 --- a/openshift/test-app-summon-sidecar.yml +++ b/openshift/test-app-summon-sidecar.yml @@ -12,7 +12,7 @@ spec: targetPort: 8080 selector: app: test-app-summon-sidecar - type: LoadBalancer + type: {{ SERVICE_TYPE }} --- apiVersion: v1 kind: ServiceAccount diff --git a/openshift/test-app-with-host-outside-apps-branch-summon-init.yml b/openshift/test-app-with-host-outside-apps-branch-summon-init.yml index 3144ffc..fd0800c 100644 --- a/openshift/test-app-with-host-outside-apps-branch-summon-init.yml +++ b/openshift/test-app-with-host-outside-apps-branch-summon-init.yml @@ -12,7 +12,7 @@ spec: targetPort: 8080 selector: app: test-app-with-host-outside-apps-branch-summon-init - type: LoadBalancer + type: {{ SERVICE_TYPE }} --- apiVersion: v1 kind: ServiceAccount diff --git a/policy/templates/project-authn-def.template.yml b/policy/templates/project-authn-def.template.yml index 9c37ed1..d31d7f0 100644 --- a/policy/templates/project-authn-def.template.yml +++ b/policy/templates/project-authn-def.template.yml @@ -10,6 +10,59 @@ annotations: description: Layer of authenticator identities permitted to call authn svc - &hosts + # Annotation-based authentication (host ID is an application name, and + # permitted application identities are listed as annotations) + - !host + id: test-app-summon-sidecar + annotations: + authn-k8s/namespace: {{ TEST_APP_NAMESPACE_NAME }} + authn-k8s/service-account: test-app-summon-sidecar + authn-k8s/deployment: test-app-summon-sidecar + authn-k8s/authentication-container-name: authenticator + kubernetes: "{{ IS_KUBERNETES }}" + - !host + id: test-app-summon-init + annotations: + authn-k8s/namespace: {{ TEST_APP_NAMESPACE_NAME }} + authn-k8s/service-account: test-app-summon-init + authn-k8s/deployment: test-app-summon-init + authn-k8s/authentication-container-name: authenticator + kubernetes: "{{ IS_KUBERNETES }}" + - !host + id: test-app-secretless + annotations: + authn-k8s/namespace: {{ TEST_APP_NAMESPACE_NAME }} + authn-k8s/service-account: test-app-secretless + authn-k8s/deployment: test-app-secretless + authn-k8s/authentication-container-name: secretless + kubernetes: "{{ IS_KUBERNETES }}" + + - !host + id: oc-test-app-summon-sidecar + annotations: + authn-k8s/namespace: {{ TEST_APP_NAMESPACE_NAME }} + authn-k8s/service-account: oc-test-app-summon-sidecar + authn-k8s/deployment-config: test-app-summon-sidecar + authn-k8s/authentication-container-name: authenticator + openshift: "{{ IS_OPENSHIFT }}" + - !host + id: oc-test-app-summon-init + annotations: + authn-k8s/namespace: {{ TEST_APP_NAMESPACE_NAME }} + authn-k8s/service-account: oc-test-app-summon-init + authn-k8s/deployment-config: test-app-summon-init + authn-k8s/authentication-container-name: authenticator + openshift: "{{ IS_OPENSHIFT }}" + - !host + id: oc-test-app-secretless + annotations: + authn-k8s/namespace: {{ TEST_APP_NAMESPACE_NAME }} + authn-k8s/service-account: oc-test-app-secretless + authn-k8s/deployment-config: test-app-secretless + authn-k8s/authentication-container-name: secretless + openshift: "{{ IS_OPENSHIFT }}" + + # Host-ID based authentication (application identity in the host itself) - !host id: {{ TEST_APP_NAMESPACE_NAME }}/*/* annotations: diff --git a/set_env_vars.sh b/set_env_vars.sh index 3800f69..36564ff 100755 --- a/set_env_vars.sh +++ b/set_env_vars.sh @@ -1,15 +1,24 @@ #!/usr/bin/env bash -set -euo pipefail - # Set the default values of environment variables used by the scripts PLATFORM="${PLATFORM:-kubernetes}" # default to kubernetes if env var not set CONJUR_AUTHN_LOGIN_RESOURCE="${CONJUR_AUTHN_LOGIN_RESOURCE:-service_account}" # default to service_account +CONJUR_VERSION="${CONJUR_VERSION:-5}" + MINIKUBE="${MINIKUBE:-false}" MINISHIFT="${MINISHIFT:-false}" LOCAL_AUTHENTICATOR="${LOCAL_AUTHENTICATOR:-false}" + +# Some older workflows that use this script repo may depend upon +# the the use of 'DEPLOY_MASTER_CLUSTER' environment variable rather than +# the newer (and more accurately named) 'CONFIGURE_CONJUR_MASTER'. DEPLOY_MASTER_CLUSTER="${DEPLOY_MASTER_CLUSTER:-false}" +CONFIGURE_CONJUR_MASTER="${CONFIGURE_CONJUR_MASTER:-$DEPLOY_MASTER_CLUSTER}" + +ANNOTATION_BASED_AUTHN="${ANNOTATION_BASED_AUTHN:-false}" +CONJUR_OSS_HELM_INSTALLED="${CONJUR_OSS_HELM_INSTALLED:-false}" +TEST_APP_NODEPORT_SVCS="${TEST_APP_NODEPORT_SVCS:-false}" DOCKER_EMAIL="${DOCKER_EMAIL:-}" diff --git a/start b/start index 1a50b27..d96b547 100755 --- a/start +++ b/start @@ -5,20 +5,22 @@ set -xeuo pipefail . utils.sh init_bash_lib -./0_check_dependencies.sh +./0_prep_check_dependencies.sh ./stop -./1_create_test_app_namespace.sh +./1_prep_platform_login.sh -if [[ "${DEPLOY_MASTER_CLUSTER}" = "true" ]]; then +if [[ "${CONFIGURE_CONJUR_MASTER}" == "true" || "${CONJUR_OSS_HELM_INSTALLED}" == "true" ]]; then # Only automatically run these scripts for dev/demo envs deploying a master # cluster directly to k8s/oc - ./2_load_conjur_policies.sh - ./3_init_conjur_cert_authority.sh + ./2_admin_load_conjur_policies.sh + ./3_admin_init_conjur_cert_authority.sh fi -./4_store_conjur_cert.sh -./5_build_and_push_containers.sh -./6_deploy_test_app.sh -./7_verify_authentication.sh +./4_app_create_namespace.sh +./5_app_store_conjur_cert.sh +./6_app_build_and_push_containers.sh +./7_app_deploy.sh +./8_app_verify_authentication.sh + diff --git a/utils.sh b/utils.sh index ac4d179..9605454 100755 --- a/utils.sh +++ b/utils.sh @@ -82,13 +82,34 @@ get_pod_name() { echo "$pod_name" } +get_pods() { + $cli get pods --selector "$1" --no-headers | awk '{ print $1 }' +} + +get_nodeport(){ + svc_name="$1" + echo "$(kubectl get svc $svc_name -o jsonpath='{.spec.ports[0].nodePort}')" +} + +app_service_type() { + if [[ "$TEST_APP_NODEPORT_SVCS" == "true" ]]; then + echo "NodePort" + else + echo "LoadBalancer" + fi +} + get_master_pod_name() { - pod_list=$($cli get pods --selector app=conjur-node,role=master --no-headers | awk '{ print $1 }') + if [ "$CONJUR_OSS_HELM_INSTALLED" = "true" ]; then + pod_list=$(get_pods "app=conjur-oss") + else + pod_list=$(get_pods "app=conjur-node,role=master") + fi echo $pod_list | awk '{print $1}' } get_conjur_cli_pod_name() { - pod_list=$($cli get pods --selector app=conjur-cli --no-headers | awk '{ print $1 }') + pod_list=$($cli get pods -n "$CONJUR_NAMESPACE_NAME" --selector app=conjur-cli --no-headers | awk '{ print $1 }') echo $pod_list | awk '{print $1}' } @@ -139,7 +160,7 @@ function wait_for_it() { echo "Waiting for '$@' up to $timeout s" for i in $(seq $times_to_run); do - eval $@ > /dev/null && echo 'Success!' && return true + eval $@ > /dev/null && echo 'Success!' && return 0 echo -n . sleep $spacer done @@ -176,11 +197,10 @@ function is_minienv() { fi } -function service_ip() { +function external_ip() { local service=$1 - echo "$($cli describe service $service | grep 'LoadBalancer Ingress' | - awk '{ print $3 }')" + echo "$($cli get svc $service -o jsonpath='{.status.loadBalancer.ingress[0].ip}')" } function deployment_status() { @@ -197,19 +217,49 @@ function pods_ready() { } function urlencode() { - # urlencode - - # Run as a subshell so that we can indiscriminately set LC_COLLATE - ( - LC_COLLATE=C - - local length="${#1}" - for (( i = 0; i < length; i++ )); do - local c="${1:i:1}" - case $c in - [a-zA-Z0-9.~_-]) printf "$c" ;; - *) printf '%%%02X' "'$c" ;; - esac - done - ) + # urlencode + + # Run as a subshell so that we can indiscriminately set LC_COLLATE + ( + LC_COLLATE=C + + local length="${#1}" + for (( i = 0; i < length; i++ )); do + local c="${1:i:1}" + case $c in + [a-zA-Z0-9.~_-]) printf "$c" ;; + *) printf '%%%02X' "'$c" ;; + esac + done + ) +} + +function dump_kubernetes_resources() { + echo "Status of pods in namespace $TEST_APP_NAMESPACE_NAME:" + $cli get -n $TEST_APP_NAMESPACE_NAME pods + echo "Display pods in namespace $TEST_APP_NAMESPACE_NAME:" + $cli get -n $TEST_APP_NAMESPACE_NAME pods -o yaml + echo "Services:in namespace $TEST_APP_NAMESPACE_NAME:" + $cli get -n $TEST_APP_NAMESPACE_NAME svc + echo "ServiceAccounts:in namespace $TEST_APP_NAMESPACE_NAME:" + $cli get -n $TEST_APP_NAMESPACE_NAME serviceaccounts + echo "Deployments in namespace $TEST_APP_NAMESPACE_NAME:" + $cli get -n $TEST_APP_NAMESPACE_NAME deployments + if [[ "$PLATFORM" == "openshift" ]]; then + echo "DeploymentConfigs in namespace $TEST_APP_NAMESPACE_NAME:" + $cli get -n $TEST_APP_NAMESPACE_NAME deploymentconfigs + fi + echo "Roles in namespace $TEST_APP_NAMESPACE_NAME:" + $cli get -n $TEST_APP_NAMESPACE_NAME roles + echo "RoleBindings in namespace $TEST_APP_NAMESPACE_NAME:" + $cli get -n $TEST_APP_NAMESPACE_NAME rolebindings + echo "ClusterRoles in the cluster:" + $cli get clusterroles + echo "ClusterRoleBindings in the cluster:" + $cli get clusterrolebindings +} + +function dump_authentication_policy { + announce "Authentication policy:" + cat policy/generated/$TEST_APP_NAMESPACE_NAME.project-authn.yml }