mirror of
https://github.com/vmware-tanzu/pinniped.git
synced 2026-06-03 13:36:51 +00:00
Enchance and move the ldapsearch hack script
This commit is contained in:
223
hack/ldapsearch.sh
Executable file
223
hack/ldapsearch.sh
Executable file
@@ -0,0 +1,223 @@
|
||||
#!/usr/bin/env bash
|
||||
|
||||
# Copyright 2023 the Pinniped contributors. All Rights Reserved.
|
||||
# SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
set -euo pipefail
|
||||
|
||||
# This script is a rough approximation of what the Pinniped Supervisor Golang code does to search an LDAP provider
|
||||
# during an end-user's login. This is intended to be helpful for debugging your LDAPIdentityProvider spec settings.
|
||||
# Because it is implemented in bash, it is not necessarily exactly the same as the actual Supervisor code.
|
||||
# Note that this does not yet support ActiveDirectoryIdentityProvider, which has some more complex behavior to
|
||||
# determine default values for some of the spec fields.
|
||||
|
||||
pinniped_path="$(cd "$(dirname "${BASH_SOURCE[0]}")/.." && pwd)"
|
||||
cd "$pinniped_path" || exit 1
|
||||
|
||||
source hack/lib/helpers.sh
|
||||
|
||||
#
|
||||
# Handle argument parsing and help message
|
||||
#
|
||||
help=no
|
||||
resource_type_and_name=""
|
||||
namespace=""
|
||||
username=""
|
||||
|
||||
while (("$#")); do
|
||||
case "$1" in
|
||||
-h | --help)
|
||||
help=yes
|
||||
shift
|
||||
;;
|
||||
-r | --resource)
|
||||
shift
|
||||
# If there are no more command line arguments, or there is another command line argument but it starts with a dash, then error
|
||||
if [[ "$#" == "0" || "$1" == -* ]]; then
|
||||
log_error "-r|--resource requires a resource type and name to be specified as type/name"
|
||||
exit 1
|
||||
fi
|
||||
resource_type_and_name=$1
|
||||
shift
|
||||
;;
|
||||
-n | --namespace)
|
||||
shift
|
||||
# If there are no more command line arguments, or there is another command line argument but it starts with a dash, then error
|
||||
if [[ "$#" == "0" || "$1" == -* ]]; then
|
||||
log_error "-n|--namespace requires a namespace name to be specified"
|
||||
exit 1
|
||||
fi
|
||||
namespace=$1
|
||||
shift
|
||||
;;
|
||||
-u | --username)
|
||||
shift
|
||||
# If there are no more command line arguments, or there is another command line argument but it starts with a dash, then error
|
||||
if [[ "$#" == "0" || "$1" == -* ]]; then
|
||||
log_error "-u|--username requires a username to be specified"
|
||||
exit 1
|
||||
fi
|
||||
username=$1
|
||||
shift
|
||||
;;
|
||||
-*)
|
||||
log_error "Unsupported flag $1" >&2
|
||||
if [[ "$1" == *"active-directory"* ]]; then
|
||||
log_error "Did you mean --get-active-directory-vars?"
|
||||
fi
|
||||
exit 1
|
||||
;;
|
||||
*)
|
||||
log_error "Unsupported positional arg $1" >&2
|
||||
exit 1
|
||||
;;
|
||||
esac
|
||||
done
|
||||
|
||||
if [[ "$help" == "yes" ]]; then
|
||||
me="$(basename "${BASH_SOURCE[0]}")"
|
||||
log_note "Usage:"
|
||||
log_note " $me [flags]"
|
||||
log_note
|
||||
log_note "Flags:"
|
||||
log_note " -h, --help: print this usage"
|
||||
log_note " -r, --resource: specify the resource type and name (e.g. ldapidentityprovider/my-ldap-idp) - required"
|
||||
log_note " -n, --namespace: specify the namespace in which the resource exists - required"
|
||||
log_note " -u, --username: specify a username, as an end-user would type it during a login - required"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
if [[ -z "$namespace" ]]; then
|
||||
log_error "-n|--namespace is required"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
if [[ -z "$resource_type_and_name" ]]; then
|
||||
log_error "-r|--resource is required"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
if [[ "$resource_type_and_name" != ldapidentityprovider/* ]]; then
|
||||
log_error "-r|--resource currently only supports ldapidentityprovider type resources."
|
||||
log_error "Please specify the value as \"ldapidentityprovider/name-of-resource\"."
|
||||
exit 1
|
||||
fi
|
||||
|
||||
if [[ -z "$username" ]]; then
|
||||
log_error "-u|--username is required"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
RESOURCE_FILE=$(mktemp)
|
||||
trap "rm $RESOURCE_FILE" EXIT
|
||||
|
||||
kubectl get "$resource_type_and_name" \
|
||||
--namespace "$namespace" \
|
||||
--output yaml >"$RESOURCE_FILE"
|
||||
|
||||
# See docs for LDAPIdentityProvider.spec for details about these settings.
|
||||
# https://github.com/vmware-tanzu/pinniped/blob/main/generated/1.28/README.adoc#k8s-api-go-pinniped-dev-generated-1-28-apis-supervisor-idp-v1alpha1-ldapidentityproviderspec
|
||||
LDAP_HOST=$(yq '.spec.host' "$RESOURCE_FILE") # required
|
||||
LDAP_CA_BUNDLE=$(yq '.spec.tls.certificateAuthorityData // ""' "$RESOURCE_FILE") # optional
|
||||
LDAP_BIND_SECRETNAME=$(yq '.spec.bind.secretName' "$RESOURCE_FILE") # required
|
||||
LDAP_USER_SEARCH_BASE=$(yq '.spec.userSearch.base' "$RESOURCE_FILE") # required
|
||||
LDAP_USER_SEARCH_FILTER=$(yq '.spec.userSearch.filter // ""' "$RESOURCE_FILE") # optional unless Attributes.Username is set to "dn"
|
||||
LDAP_USER_SEARCH_ATTRIBUTES_USERNAME=$(yq '.spec.userSearch.attributes.username' "$RESOURCE_FILE") # required
|
||||
LDAP_USER_SEARCH_ATTRIBUTES_UID=$(yq '.spec.userSearch.attributes.uid' "$RESOURCE_FILE") # required
|
||||
LDAP_GROUP_SEARCH_BASE=$(yq '.spec.groupSearch.base // ""' "$RESOURCE_FILE") # optional, disables group search when blank
|
||||
LDAP_GROUP_SEARCH_FILTER=$(yq '.spec.groupSearch.filter // ""' "$RESOURCE_FILE") # optional, defaults to member={}
|
||||
LDAP_GROUP_SEARCH_USER_ATTRIBUTE_FOR_FILTER=$(yq '.spec.groupSearch.userAttributeForFilter // ""' "$RESOURCE_FILE") # optional, defaults to using dn
|
||||
LDAP_GROUP_SEARCH_ATTRIBUTES_GROUPNAME=$(yq '.spec.groupSearch.attributes.groupName // ""' "$RESOURCE_FILE") # optional, defaults to using dn
|
||||
|
||||
# Set defaults for missing optional values.
|
||||
if [[ -z "$LDAP_USER_SEARCH_FILTER" ]]; then
|
||||
LDAP_USER_SEARCH_FILTER="${LDAP_USER_SEARCH_ATTRIBUTES_USERNAME}={}"
|
||||
fi
|
||||
if [[ -z "$LDAP_GROUP_SEARCH_FILTER" ]]; then
|
||||
LDAP_GROUP_SEARCH_FILTER="member={}"
|
||||
fi
|
||||
if [[ -z "$LDAP_GROUP_SEARCH_USER_ATTRIBUTE_FOR_FILTER" ]]; then
|
||||
LDAP_GROUP_SEARCH_USER_ATTRIBUTE_FOR_FILTER="dn"
|
||||
fi
|
||||
if [[ -z "$LDAP_GROUP_SEARCH_ATTRIBUTES_GROUPNAME" ]]; then
|
||||
LDAP_GROUP_SEARCH_ATTRIBUTES_GROUPNAME="dn"
|
||||
fi
|
||||
|
||||
LDAP_BIND_SECRET_FILE=$(mktemp)
|
||||
trap "rm $LDAP_BIND_SECRET_FILE" EXIT
|
||||
|
||||
kubectl get secret "$LDAP_BIND_SECRETNAME" \
|
||||
--namespace "$namespace" \
|
||||
--output yaml >"$LDAP_BIND_SECRET_FILE"
|
||||
|
||||
LDAP_BIND_DN=$(yq '.data.username | @base64d' "$LDAP_BIND_SECRET_FILE") # required
|
||||
LDAP_BIND_PASSWORD=$(yq '.data.password | @base64d' "$LDAP_BIND_SECRET_FILE") # required
|
||||
|
||||
basic_cmd=()
|
||||
|
||||
if [[ -n "${LDAP_CA_BUNDLE}" ]]; then
|
||||
LDAP_CA_BUNDLE_FILE="/tmp/ldap_tls_cacert.pem"
|
||||
echo "$LDAP_CA_BUNDLE" | base64 -d >$LDAP_CA_BUNDLE_FILE
|
||||
|
||||
basic_cmd+=("LDAPTLS_CACERT=$LDAP_CA_BUNDLE_FILE")
|
||||
fi
|
||||
|
||||
basic_cmd+=("ldapsearch" "-x")
|
||||
basic_cmd+=("-H" "'ldaps://$LDAP_HOST'")
|
||||
|
||||
if [[ -n "${LDAP_BIND_DN}" ]]; then
|
||||
basic_cmd+=("-D" "'$LDAP_BIND_DN'")
|
||||
fi
|
||||
|
||||
if [[ -n "${LDAP_BIND_PASSWORD}" ]]; then
|
||||
basic_cmd+=("-w" "'$LDAP_BIND_PASSWORD'")
|
||||
fi
|
||||
|
||||
# Construct a command which will print the whole user record, if found.
|
||||
find_user_cmd=${basic_cmd[*]}
|
||||
find_user_cmd+=("-b" "'$LDAP_USER_SEARCH_BASE'")
|
||||
find_user_cmd+=("-z" "1") # limit one result
|
||||
find_user_cmd+=("-s" "sub")
|
||||
find_user_cmd+=("'${LDAP_USER_SEARCH_FILTER//\{\}/"$username"}'")
|
||||
|
||||
log_note "The following commands are provided to aid in debugging."
|
||||
log_note "Copy and paste these commands into a bash shell to run them."
|
||||
|
||||
echo
|
||||
log_note "Use the following command to search for the user's LDAP record."
|
||||
log_note "The value of the \"$LDAP_USER_SEARCH_ATTRIBUTES_USERNAME\" attribute will be their Kubernetes username,"
|
||||
log_note "(not including any configured transformations on the FederationDomain),"
|
||||
log_note "and the value of the \"$LDAP_USER_SEARCH_ATTRIBUTES_UID\" attribute will be their Supervisor UID."
|
||||
echo "${find_user_cmd[*]}"
|
||||
|
||||
if [[ -z "$LDAP_GROUP_SEARCH_BASE" ]]; then
|
||||
echo
|
||||
log_note "Group search is not enabled because spec.groupSearch.base is empty."
|
||||
exit
|
||||
fi
|
||||
|
||||
# Add more to the user search command to get only the value of the configured username attribute.
|
||||
find_user_cmd+=("$LDAP_GROUP_SEARCH_USER_ATTRIBUTE_FOR_FILTER" "-LLL")
|
||||
find_user_cmd+=("|" "grep" "-E" "'^${LDAP_GROUP_SEARCH_USER_ATTRIBUTE_FOR_FILTER}: '")
|
||||
find_user_cmd+=("|" "sed" "'s/^${LDAP_GROUP_SEARCH_USER_ATTRIBUTE_FOR_FILTER}: //'")
|
||||
|
||||
# Construct a command that will print a list of group names to which the user belongs.
|
||||
find_groups_cmd=${basic_cmd[*]}
|
||||
find_groups_cmd+=("-b" "'$LDAP_GROUP_SEARCH_BASE'")
|
||||
find_groups_cmd+=("-s" "sub")
|
||||
find_groups_cmd+=('${LDAP_GROUP_SEARCH_FILTER//\{\}/"$GROUP_SEARCH_KEY"}')
|
||||
find_groups_cmd+=("${LDAP_GROUP_SEARCH_ATTRIBUTES_GROUPNAME}")
|
||||
find_groups_cmd+=("-LLL")
|
||||
find_groups_cmd+=("|" "grep" "-E" "'^${LDAP_GROUP_SEARCH_ATTRIBUTES_GROUPNAME}: '")
|
||||
find_groups_cmd+=("|" "sed" "'s/^${LDAP_GROUP_SEARCH_ATTRIBUTES_GROUPNAME}: //'")
|
||||
|
||||
echo
|
||||
log_note "Use the following three commands to search for the user's group memberships."
|
||||
log_note "The third command should result in their list of group names for Kubernetes"
|
||||
log_note "(not including any configured transformations on the FederationDomain)."
|
||||
echo "LDAP_GROUP_SEARCH_FILTER=\"${LDAP_GROUP_SEARCH_FILTER}\""
|
||||
echo
|
||||
echo "GROUP_SEARCH_KEY=\$( ${find_user_cmd[*]} )"
|
||||
echo
|
||||
echo "${find_groups_cmd[*]}"
|
||||
echo
|
||||
@@ -1,19 +0,0 @@
|
||||
# ldapsearch.sh
|
||||
|
||||
Translate your `LDAPIdentityProvider` into `ldapsearch` queries for debugging purposes.
|
||||
|
||||
Usage
|
||||
|
||||
```shell
|
||||
kubectl get ldapidentityprovider <name> \
|
||||
--namespace=<namespace> \
|
||||
--output=yaml | ./hack/ldapsearch/ldapsearch.sh
|
||||
```
|
||||
|
||||
Add `--debug` for some additional output.
|
||||
|
||||
```shell
|
||||
kubectl get ldapidentityprovider <name> \
|
||||
--namespace=<namespace> \
|
||||
--output=yaml | ./hack/ldapsearch/ldapsearch.sh --debug
|
||||
```
|
||||
@@ -1,83 +0,0 @@
|
||||
#!/usr/bin/env bash
|
||||
|
||||
# Copyright 2023 the Pinniped contributors. All Rights Reserved.
|
||||
# SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
set -euo pipefail
|
||||
|
||||
STDIN_DUMP=`mktemp`
|
||||
trap "rm $STDIN_DUMP" EXIT
|
||||
|
||||
# Read from STDIN
|
||||
cat > $STDIN_DUMP
|
||||
|
||||
LDAP_IDENTITY_PROVIDER_FILE=`mktemp`
|
||||
trap "rm $LDAP_IDENTITY_PROVIDER_FILE" EXIT
|
||||
|
||||
yq 'select(document_index == 0)' $STDIN_DUMP > $LDAP_IDENTITY_PROVIDER_FILE
|
||||
|
||||
LDAP_IDP_NAME=`yq '.metadata.name' $LDAP_IDENTITY_PROVIDER_FILE`
|
||||
LDAP_IDP_NAMESPACE=`yq '.metadata.namespace' $LDAP_IDENTITY_PROVIDER_FILE`
|
||||
LDAP_HOST=`yq '.spec.host' $LDAP_IDENTITY_PROVIDER_FILE`
|
||||
LDAP_USER_SEARCH_BASE_DN=`yq '.spec.userSearch.base' $LDAP_IDENTITY_PROVIDER_FILE`
|
||||
LDAP_USER_SEARCH_FILTER=`yq '.spec.userSearch.filter' $LDAP_IDENTITY_PROVIDER_FILE`
|
||||
LDAP_CA_BUNDLE=`yq '.spec.tls.certificateAuthorityData | @base64d' $LDAP_IDENTITY_PROVIDER_FILE`
|
||||
LDAP_BIND_SECRETNAME=`yq '.spec.bind.secretName' $LDAP_IDENTITY_PROVIDER_FILE`
|
||||
LDAP_BIND_DN=""
|
||||
LDAP_BIND_PASSWORD=""
|
||||
|
||||
if [[ -n "${LDAP_BIND_SECRETNAME}" ]]; then
|
||||
LDAP_BIND_SECRET_FILE=`mktemp`
|
||||
trap "rm $LDAP_BIND_SECRET_FILE" EXIT
|
||||
|
||||
kubectl get secret "$LDAP_BIND_SECRETNAME" \
|
||||
--namespace "$LDAP_IDP_NAMESPACE" \
|
||||
--output yaml > $LDAP_BIND_SECRET_FILE
|
||||
|
||||
LDAP_BIND_DN=`yq '.data.username | @base64d' $LDAP_BIND_SECRET_FILE`
|
||||
LDAP_BIND_PASSWORD=`yq '.data.password | @base64d' $LDAP_BIND_SECRET_FILE`
|
||||
fi
|
||||
|
||||
if [[ "${1:-}" == "--debug" ]]; then
|
||||
echo LDAP_IDP_NAME="$LDAP_IDP_NAME"
|
||||
echo LDAP_IDP_NAMESPACE="$LDAP_IDP_NAMESPACE"
|
||||
echo LDAP_HOST="$LDAP_HOST"
|
||||
echo LDAP_USER_SEARCH_BASE_DN="$LDAP_USER_SEARCH_BASE_DN"
|
||||
echo LDAP_USER_SEARCH_FILTER="$LDAP_USER_SEARCH_FILTER"
|
||||
echo LDAP_CA_BUNDLE="$LDAP_CA_BUNDLE"
|
||||
echo LDAP_BIND_SECRETNAME="$LDAP_BIND_SECRETNAME"
|
||||
echo LDAP_BIND_DN="$LDAP_BIND_DN"
|
||||
echo LDAP_BIND_PASSWORD="$LDAP_BIND_PASSWORD"
|
||||
fi
|
||||
|
||||
output=()
|
||||
|
||||
if [[ -n "${LDAP_CA_BUNDLE}" ]]; then
|
||||
LDAP_CA_BUNDLE_FILE=ldaptls_cacert.pem
|
||||
echo "$LDAP_CA_BUNDLE" > $LDAP_CA_BUNDLE_FILE
|
||||
|
||||
output+=("LDAPTLS_CACERT=$LDAP_CA_BUNDLE_FILE")
|
||||
fi
|
||||
|
||||
output+=("ldapsearch" "-x")
|
||||
output+=("-H" "ldaps://$LDAP_HOST")
|
||||
|
||||
if [[ -n "${LDAP_BIND_DN}" ]]; then
|
||||
output+=("-D" "$LDAP_BIND_DN")
|
||||
fi
|
||||
|
||||
if [[ -n "${LDAP_BIND_PASSWORD}" ]]; then
|
||||
output+=("-w" "'$LDAP_BIND_PASSWORD'")
|
||||
fi
|
||||
|
||||
output+=("-b" "$LDAP_USER_SEARCH_BASE_DN")
|
||||
output+=("-s" "sub")
|
||||
output+=("$LDAP_USER_SEARCH_FILTER")
|
||||
|
||||
echo "${output[*]}"
|
||||
|
||||
#LDAPTLS_CACERT=/path/to/ca-bundle.pem ldapsearch \
|
||||
#-x -H ldaps://LDAP_HOST -D LDAP_BIND_DN -w LDAP_BIND_PASSWORD \
|
||||
#-b LDAP_USER_SEARCH_BASE_DN \
|
||||
#-s sub (LDAP_USER_SEARCH_FILTER-with-placeholder-replaced-by-username)
|
||||
#
|
||||
Reference in New Issue
Block a user