#!/usr/bin/env bash # Copyright 2020-2025 the Pinniped contributors. All Rights Reserved. # SPDX-License-Identifier: Apache-2.0 set -euo pipefail # extract_env takes a JSON object representing an client.authentication.k8s.io/v1beta1 # exec credential config (as parameter $1) and pulls out the env var value for the # provided name (as parameter $2). function extract_env_value() { filter=".env[] | select(.name==\"$2\") | .value" echo "$1" | jq -r "$filter" } function print_or_redact_doc() { doc_kind=$(echo "$1" | awk '/^kind: / {print $2}') if [[ -z "$doc_kind" ]]; then echo "warning: " elif [[ $doc_kind == "Secret" || $doc_kind == "secret" ]]; then echo echo "---" echo "" else printf "%s\n" "$1" fi } function print_redacted_manifest() { doc="" while IFS="" read -r line || [ -n "$line" ]; do if [[ $line == "---" ]]; then if [[ -n "$doc" ]]; then print_or_redact_doc "$doc" fi doc="" fi doc=$(printf "%s\n%s" "$doc" "$line") done <"$1" print_or_redact_doc "$doc" } export KUBECONFIG="$PWD/cluster-pool/metadata" # See https://github.com/concourse/registry-image-resource#in-fetch-the-images-rootfs-and-metadata export IMAGE_DIGEST="$(cat ci-build-image/digest)" export IMAGE_REPO="$(cat ci-build-image/repository)" CLUSTER_CAPABILITIES_PATH="$PWD/$CLUSTER_CAPABILITIES_PATH" if [ -n "$CLUSTER_CAPABILITIES" ]; then echo "$CLUSTER_CAPABILITIES" >/tmp/cluster-capabilities.yaml CLUSTER_CAPABILITIES_PATH=/tmp/cluster-capabilities.yaml fi concierge_app_name=${PINNIPED_CONCIERGE_APP_NAME:-"pinniped-concierge"} concierge_namespace=${concierge_app_name} concierge_custom_labels="{myConciergeCustomLabelName: myConciergeCustomLabelValue}" supervisor_app_name=${PINNIPED_SUPERVISOR_APP_NAME:-"pinniped-supervisor"} supervisor_namespace=${supervisor_app_name} supervisor_custom_labels="{mySupervisorCustomLabelName: mySupervisorCustomLabelValue}" discovery_url="${PINNIPED_DISCOVERY_URL:-null}" manifest=/tmp/manifest.yaml test_username="test-username" test_groups="test-group-0,test-group-1" set +o pipefail test_password="$(cat /dev/urandom | env LC_CTYPE=C tr -dc 'a-z0-9' | fold -w 32 | head -n 1)" set -o pipefail if [[ ${#test_password} -ne 32 ]]; then log_error "Could not create random test user password" exit 1 fi test_user_token="${test_username}:${test_password}" # Print for debugging kubectl config current-context kubectl version kubectl cluster-info dex_test_password="${PINNIPED_DEX_TEST_USER_PASSWORD:-$(openssl rand -hex 16)}" ldap_test_password="${PINNIPED_LDAP_TEST_USER_PASSWORD:-$(openssl rand -hex 16)}" # deploy local user authenticator pushd pinniped/deploy/local-user-authenticator >/dev/null echo "Creating install-local-user-authenticator.yaml..." ytt --file . \ --data-value "image_repo=$IMAGE_REPO" \ --data-value "image_digest=${IMAGE_DIGEST:-}" \ --data-value "image_tag=${IMAGE_TAG:-}" >../../../deployment-yamls/install-local-user-authenticator.yaml popd pushd deployment-yamls >/dev/null echo "Deploying local user authenticator to the cluster..." kubectl apply -f install-local-user-authenticator.yaml kubectl wait --for=condition=available --timeout=60s -n local-user-authenticator deployments/local-user-authenticator # Always create a secret. echo "Creating test user '$test_username'..." kubectl create secret generic "$test_username" \ --namespace local-user-authenticator \ --from-literal=groups="$test_groups" \ --from-literal=passwordHash="$(htpasswd -nbBC 10 x "$test_password" | sed -e "s/^x://")" \ --dry-run=client \ --output yaml | kubectl apply -f - # Override the TMC webhook settings to use the local-user-authenticator instead webhook_url="https://local-user-authenticator.local-user-authenticator.svc.cluster.local/authenticate" # Sometimes the local-user-authenticator pod hasn't generated the serving certificate yet, so we poll until it has. set +o pipefail while ! kubectl get secret local-user-authenticator-tls-serving-certificate --namespace local-user-authenticator >/dev/null; do echo "Waiting for local-user-authenticator Secret to be created..." sleep 1 done set -o pipefail webhook_ca_bundle="$(kubectl get secret local-user-authenticator-tls-serving-certificate --namespace local-user-authenticator -o 'jsonpath={.data.caCertificate}')" popd >/dev/null # always deploy dex # # Deploy tools # pushd pinniped/test/deploy/tools >/dev/null test_supervisor_upstream_oidc_callback_url="https://${supervisor_app_name}-clusterip.${supervisor_namespace}.svc.cluster.local/some/path/callback" supervisor_redirect_uris="[ ${test_supervisor_upstream_oidc_callback_url} ]" echo "Deploying Tools to the cluster..." ytt --file . \ --data-value-yaml "supervisor_redirect_uris=${supervisor_redirect_uris}" \ --data-value "pinny_ldap_password=$ldap_test_password" \ --data-value "pinny_bcrypt_passwd_hash=$(htpasswd -nbBC 10 x "$dex_test_password" | sed -e "s/^x://")" \ >"$manifest" echo echo "Full Tools manifest with Secrets redacted..." echo "--------------------------------------------------------------------------------" print_redacted_manifest $manifest echo "--------------------------------------------------------------------------------" echo set -x kapp deploy --yes --app tools --diff-changes --file "$manifest" { set +x; } 2>/dev/null dex_ca_bundle="$(kubectl get secrets -n tools certs -o go-template='{{index .data "ca.pem" | base64decode}}' | base64)" pinniped_test_tools_namespace="tools" test_cli_oidc_callback_url="http://127.0.0.1:48095/callback" test_cli_oidc_client_id="pinniped-cli" test_cli_oidc_issuer_ca_bundle="${dex_ca_bundle}" test_cli_oidc_issuer="https://dex.tools.svc.cluster.local/dex" test_cli_oidc_password="${dex_test_password}" test_cli_oidc_username="pinny@example.com" test_proxy="http://127.0.0.1:12346" test_supervisor_upstream_oidc_client_id="pinniped-supervisor" test_supervisor_upstream_oidc_client_secret="pinniped-supervisor-secret" test_supervisor_upstream_oidc_additional_scopes="offline_access,email" test_supervisor_upstream_oidc_username_claim="email" test_supervisor_upstream_oidc_groups_claim="groups" test_supervisor_upstream_oidc_issuer_ca_bundle="${dex_ca_bundle}" test_supervisor_upstream_oidc_issuer="https://dex.tools.svc.cluster.local/dex" test_supervisor_upstream_oidc_password="${dex_test_password}" test_supervisor_upstream_oidc_username="pinny@example.com" test_supervisor_upstream_oidc_groups="" # Dex's local user store does not let us configure groups. pinniped_test_ldap_host="ldap.tools.svc.cluster.local" pinniped_test_ldap_starttls_only_host="ldapstarttls.tools.svc.cluster.local" pinniped_test_ldap_ldaps_ca_bundle="${dex_ca_bundle}" pinniped_test_ldap_bind_account_username="cn=admin,dc=pinniped,dc=dev" pinniped_test_ldap_bind_account_password=password pinniped_test_ldap_users_search_base="ou=users,dc=pinniped,dc=dev" pinniped_test_ldap_groups_search_base="ou=groups,dc=pinniped,dc=dev" pinniped_test_ldap_groups_search_filter="" pinniped_test_ldap_user_dn="cn=pinny,ou=users,dc=pinniped,dc=dev" pinniped_test_ldap_user_cn="pinny" pinniped_test_ldap_user_password=${ldap_test_password} pinniped_test_ldap_user_unique_id_attribute_name="uidNumber" pinniped_test_ldap_user_unique_id_attribute_value="1000" pinniped_test_ldap_user_email_attribute_name="mail" pinniped_test_ldap_user_email_attribute_value="pinny.ldap@example.com" pinniped_test_ldap_expected_direct_groups_dn="cn=ball-game-players,ou=beach-groups,ou=groups,dc=pinniped,dc=dev;cn=seals,ou=groups,dc=pinniped,dc=dev" pinniped_test_ldap_expected_indirect_groups_dn="cn=pinnipeds,ou=groups,dc=pinniped,dc=dev;cn=mammals,ou=groups,dc=pinniped,dc=dev" pinniped_test_ldap_expected_direct_groups_cn="ball-game-players;seals" pinniped_test_ldap_expected_direct_posix_groups_cn="ball-game-players-posix;seals-posix" pinniped_test_ldap_expected_indirect_groups_cn="pinnipeds;mammals" popd >/dev/null # deploy concierge pushd pinniped/deploy/concierge >/dev/null echo "Creating concierge deployment yamls..." ytt --file . \ --data-value "app_name=$concierge_app_name" \ --data-value "namespace=$concierge_namespace" \ --data-value "image_repo=$IMAGE_REPO" \ --data-value "image_digest=${IMAGE_DIGEST:-}" \ --data-value "image_tag=${IMAGE_TAG:-}" \ --data-value-yaml "image_pull_dockerconfigjson=${IMAGE_PULL_SECRET:-}" \ --data-value "api_serving_certificate_duration_seconds=${API_SERVING_CERT_DURATION:-2592000}" \ --data-value "api_serving_certificate_renew_before_seconds=${API_SERVING_CERT_RENEW_BEFORE:-2160000}" \ --data-value "log_level=debug" \ --data-value-yaml "custom_labels=$concierge_custom_labels" \ --data-value "discovery_url=$discovery_url" >../../../deployment-yamls/install-pinniped-concierge.yaml popd pushd deployment-yamls >/dev/null # create the two yaml files for kubectl based on the kapp one with everything in it yq eval 'select(.kind == "CustomResourceDefinition" or .kind == "Namespace" or .kind == "ServiceAccount")' install-pinniped-concierge.yaml >install-pinniped-concierge-crds.yaml yq eval 'select(.kind != "CustomResourceDefinition" and .kind != "Namespace" and .kind != "ServiceAccount")' install-pinniped-concierge.yaml > install-pinniped-concierge-resources.yaml set -x echo "Deploying concierge crds to the cluster..." kubectl apply -f install-pinniped-concierge-crds.yaml kubectl wait --for condition="established" --timeout=60s crd -l app=pinniped-concierge echo "Deploying concierge resources to the cluster..." kubectl apply -f install-pinniped-concierge-resources.yaml kubectl wait --for condition="available" --timeout=60s -n pinniped-concierge deployments/pinniped-concierge # deploy supervisor # set ytt values related to ingress. supervisor_ytt_service_flags=() # We assume we are running on # kind, and therefore expect to talk to the supervisor via NodePort and ClusterIP services. # This nodePort is the same port number is hardcoded in the port forwarding of our kind configuration. supervisor_ytt_service_flags+=("--data-value-yaml=service_https_nodeport_port=443") supervisor_ytt_service_flags+=("--data-value-yaml=service_https_nodeport_nodeport=31243") supervisor_ytt_service_flags+=("--data-value-yaml=service_https_clusterip_port=443") popd pushd pinniped/deploy/supervisor >/dev/null echo "Creating install-pinniped-supervisor.yaml..." ytt --file . \ --data-value "app_name=$supervisor_app_name" \ --data-value "namespace=$supervisor_namespace" \ --data-value "image_repo=$IMAGE_REPO" \ --data-value "image_digest=${IMAGE_DIGEST:-}" \ --data-value "image_tag=${IMAGE_TAG:-}" \ --data-value-yaml "image_pull_dockerconfigjson=${IMAGE_PULL_SECRET:-}" \ --data-value "log_level=debug" \ --data-value-yaml "custom_labels=$supervisor_custom_labels" \ "${supervisor_ytt_service_flags[@]}" \ >../../../deployment-yamls/install-pinniped-supervisor.yaml popd pushd deployment-yamls >/dev/null echo "Deploying supervisor to the cluster..." kubectl apply -f install-pinniped-supervisor.yaml kubectl wait --for condition="available" --timeout=60s -n pinniped-supervisor deployments/pinniped-supervisor popd >/dev/null set +x # When we test on kind, we use "kubectl port-forward" in the task script to expose these ports for the integration tests. supervisor_https_address='https://localhost:12344' supervisor_https_ingress_address= supervisor_https_ingress_ca_bundle= # # Set up the integration test env vars # pinniped_cluster_capability_file_content=$(cat "pinniped/test/cluster_capabilities/kind.yaml") cat </tmp/integration-test-env export PINNIPED_TEST_TOOLS_NAMESPACE='${pinniped_test_tools_namespace}' export PINNIPED_TEST_CONCIERGE_NAMESPACE='${concierge_namespace}' export PINNIPED_TEST_CONCIERGE_APP_NAME='${concierge_app_name}' export PINNIPED_TEST_CONCIERGE_CUSTOM_LABELS='${concierge_custom_labels}' export PINNIPED_TEST_USER_USERNAME='${test_username}' export PINNIPED_TEST_USER_GROUPS='${test_groups}' export PINNIPED_TEST_USER_TOKEN='${test_user_token}' export PINNIPED_TEST_WEBHOOK_ENDPOINT='${webhook_url}' export PINNIPED_TEST_WEBHOOK_CA_BUNDLE='${webhook_ca_bundle}' export PINNIPED_TEST_SUPERVISOR_NAMESPACE='${supervisor_namespace}' export PINNIPED_TEST_SUPERVISOR_APP_NAME='${supervisor_app_name}' export PINNIPED_TEST_SUPERVISOR_CUSTOM_LABELS='${supervisor_custom_labels}' export PINNIPED_TEST_SUPERVISOR_HTTPS_ADDRESS='${supervisor_https_address}' export PINNIPED_TEST_SUPERVISOR_HTTPS_INGRESS_ADDRESS='${supervisor_https_ingress_address}' export PINNIPED_TEST_SUPERVISOR_HTTPS_INGRESS_CA_BUNDLE='${supervisor_https_ingress_ca_bundle}' export PINNIPED_TEST_PROXY='${test_proxy}' export PINNIPED_TEST_LDAP_HOST='${pinniped_test_ldap_host}' export PINNIPED_TEST_LDAP_STARTTLS_ONLY_HOST='${pinniped_test_ldap_starttls_only_host}' export PINNIPED_TEST_LDAP_LDAPS_CA_BUNDLE='${pinniped_test_ldap_ldaps_ca_bundle}' export PINNIPED_TEST_LDAP_BIND_ACCOUNT_USERNAME='${pinniped_test_ldap_bind_account_username}' export PINNIPED_TEST_LDAP_BIND_ACCOUNT_PASSWORD='${pinniped_test_ldap_bind_account_password}' export PINNIPED_TEST_LDAP_USERS_SEARCH_BASE='${pinniped_test_ldap_users_search_base}' export PINNIPED_TEST_LDAP_GROUPS_SEARCH_BASE='${pinniped_test_ldap_groups_search_base}' export PINNIPED_TEST_LDAP_GROUPS_SEARCH_FILTER='${pinniped_test_ldap_groups_search_filter}' export PINNIPED_TEST_LDAP_USER_DN='${pinniped_test_ldap_user_dn}' export PINNIPED_TEST_LDAP_USER_CN='${pinniped_test_ldap_user_cn}' export PINNIPED_TEST_LDAP_USER_PASSWORD='${pinniped_test_ldap_user_password}' export PINNIPED_TEST_LDAP_USER_UNIQUE_ID_ATTRIBUTE_NAME='${pinniped_test_ldap_user_unique_id_attribute_name}' export PINNIPED_TEST_LDAP_USER_UNIQUE_ID_ATTRIBUTE_VALUE='${pinniped_test_ldap_user_unique_id_attribute_value}' export PINNIPED_TEST_LDAP_USER_EMAIL_ATTRIBUTE_NAME='${pinniped_test_ldap_user_email_attribute_name}' export PINNIPED_TEST_LDAP_USER_EMAIL_ATTRIBUTE_VALUE='${pinniped_test_ldap_user_email_attribute_value}' export PINNIPED_TEST_LDAP_EXPECTED_DIRECT_GROUPS_DN='${pinniped_test_ldap_expected_direct_groups_dn}' export PINNIPED_TEST_LDAP_EXPECTED_INDIRECT_GROUPS_DN='${pinniped_test_ldap_expected_indirect_groups_dn}' export PINNIPED_TEST_LDAP_EXPECTED_DIRECT_GROUPS_CN='${pinniped_test_ldap_expected_direct_groups_cn}' export PINNIPED_TEST_LDAP_EXPECTED_DIRECT_POSIX_GROUPS_CN='${pinniped_test_ldap_expected_direct_posix_groups_cn}' export PINNIPED_TEST_LDAP_EXPECTED_INDIRECT_GROUPS_CN='${pinniped_test_ldap_expected_indirect_groups_cn}' export PINNIPED_TEST_CLI_OIDC_CALLBACK_URL='${test_cli_oidc_callback_url}' export PINNIPED_TEST_CLI_OIDC_CLIENT_ID='${test_cli_oidc_client_id}' export PINNIPED_TEST_CLI_OIDC_ISSUER_CA_BUNDLE='${test_cli_oidc_issuer_ca_bundle}' export PINNIPED_TEST_CLI_OIDC_ISSUER='${test_cli_oidc_issuer}' export PINNIPED_TEST_CLI_OIDC_PASSWORD='${test_cli_oidc_password}' export PINNIPED_TEST_CLI_OIDC_USERNAME='${test_cli_oidc_username}' export PINNIPED_TEST_CLI_OIDC_USERNAME_CLAIM='${test_supervisor_upstream_oidc_username_claim}' export PINNIPED_TEST_CLI_OIDC_GROUPS_CLAIM='${test_supervisor_upstream_oidc_groups_claim}' export PINNIPED_TEST_CLI_OIDC_EXPECTED_GROUPS='${test_supervisor_upstream_oidc_groups}' export PINNIPED_TEST_SUPERVISOR_UPSTREAM_OIDC_CALLBACK_URL='${test_supervisor_upstream_oidc_callback_url}' export PINNIPED_TEST_SUPERVISOR_UPSTREAM_OIDC_ADDITIONAL_SCOPES='${test_supervisor_upstream_oidc_additional_scopes}' export PINNIPED_TEST_SUPERVISOR_UPSTREAM_OIDC_USERNAME_CLAIM='${test_supervisor_upstream_oidc_username_claim}' export PINNIPED_TEST_SUPERVISOR_UPSTREAM_OIDC_GROUPS_CLAIM='${test_supervisor_upstream_oidc_groups_claim}' export PINNIPED_TEST_SUPERVISOR_UPSTREAM_OIDC_CLIENT_ID='${test_supervisor_upstream_oidc_client_id}' export PINNIPED_TEST_SUPERVISOR_UPSTREAM_OIDC_CLIENT_SECRET='${test_supervisor_upstream_oidc_client_secret}' export PINNIPED_TEST_SUPERVISOR_UPSTREAM_OIDC_ISSUER_CA_BUNDLE='${test_supervisor_upstream_oidc_issuer_ca_bundle}' export PINNIPED_TEST_SUPERVISOR_UPSTREAM_OIDC_ISSUER='${test_supervisor_upstream_oidc_issuer}' export PINNIPED_TEST_SUPERVISOR_UPSTREAM_OIDC_PASSWORD='${test_supervisor_upstream_oidc_password}' export PINNIPED_TEST_SUPERVISOR_UPSTREAM_OIDC_USERNAME='${test_supervisor_upstream_oidc_username}' export PINNIPED_TEST_SUPERVISOR_UPSTREAM_OIDC_EXPECTED_GROUPS='${test_supervisor_upstream_oidc_groups}' export PINNIPED_TEST_SHELL_CONTAINER_IMAGE="ghcr.io/pinniped-ci-bot/test-kubectl:latest" read -r -d '' PINNIPED_TEST_CLUSTER_CAPABILITY_YAML << PINNIPED_TEST_CLUSTER_CAPABILITY_YAML_EOF || true ${pinniped_cluster_capability_file_content} PINNIPED_TEST_CLUSTER_CAPABILITY_YAML_EOF export PINNIPED_TEST_CLUSTER_CAPABILITY_YAML EOF # Copy the env vars file that was output by the previous script which are needed during integration tests cp /tmp/integration-test-env integration-test-env-vars/ cp "$KUBECONFIG" kubeconfig/kubeconfig cp "$PWD/cluster-pool/name" kubeconfig/cluster-name