Federation test (#423)
Co-authored-by: kfox1111 <[email protected]> Co-authored-by: Marco Franssen <[email protected]>
This commit is contained in:
co-authored by
kfox1111
Marco Franssen
parent
8e9d42acf7
commit
cbe0001131
+116
@@ -0,0 +1,116 @@
|
||||
#!/usr/bin/env bash
|
||||
|
||||
set -x
|
||||
|
||||
# https://gist.github.com/stokito/f2d7ea0b300f14638a9063559384ec89/
|
||||
# Decode a JWT from stdin and verify it's signature with the JWT issuer public key
|
||||
# Only RS256 keys are supported for signature check
|
||||
#
|
||||
# HOW TO USE:
|
||||
# $ export JWTTOKEN="eyF...<your token here>...g"
|
||||
# $ ./jwt-decode.sh https://example.com/keys "${JWTTOKEN}"
|
||||
# if signature check failed then error code will be non-zero
|
||||
|
||||
URL=$1
|
||||
|
||||
JWT=$2
|
||||
|
||||
if [ -z "$(command -v jq)" ]; then
|
||||
echo "This script will NOT work on your machine."
|
||||
echo "Please install jq first: https://stedolan.github.io/jq/download/"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
base64_padding() {
|
||||
local len=$(( ${#1} % 4 ))
|
||||
local padded_b64=''
|
||||
if [ ${len} = 2 ]; then
|
||||
padded_b64="${1}=="
|
||||
elif [ ${len} = 3 ]; then
|
||||
padded_b64="${1}="
|
||||
else
|
||||
padded_b64="${1}"
|
||||
fi
|
||||
echo -n "$padded_b64"
|
||||
}
|
||||
|
||||
base64url_to_b64() {
|
||||
base64_padding "${1}" | tr -- '-_' '+/'
|
||||
}
|
||||
|
||||
b2hex() { echo -n "$1"==== | fold -w 4 | sed '$ d' | tr -d '\n' |base64 -d | xxd -p | tr -d \\n; }
|
||||
|
||||
mint_rsa_key() {
|
||||
JWK=$1
|
||||
|
||||
# Extract the modulus and exponent from the JWK, converting from URL-safe Base64 to standard Base64
|
||||
MODULUS=$(echo "$JWK" | jq -r '.n' | tr '_-' '/+')
|
||||
EXPONENT=$(echo "$JWK" | jq -r '.e' | tr '_-' '/+')
|
||||
|
||||
modulus=$(b2hex "$MODULUS")
|
||||
exponent=$(b2hex "$EXPONENT")
|
||||
|
||||
asnconf=$(mktemp)
|
||||
|
||||
asnconf="asn1=SEQUENCE:pubkeyinfo\n[pubkeyinfo]\nalgorithm=SEQUENCE:rsa_alg\npubkey=BITWRAP,SEQUENCE:rsapubkey\n[rsa_alg]\nalgorithm=OID:rsaEncryption\nparameter=NULL\n[rsapubkey]\nn=INTEGER:0x$modulus\ne=INTEGER:0x$exponent"
|
||||
|
||||
derfile=$(mktemp)
|
||||
echo >&2 "derfile: $derfile"
|
||||
echo -e "$asnconf" | openssl asn1parse -genconf /dev/stdin -noout -out "$derfile"
|
||||
|
||||
openssl rsa -in "$derfile" -inform DER -pubin
|
||||
}
|
||||
|
||||
# read the JWT from stdin and split by comma into three variables
|
||||
IFS='.' read -r JWT_HEADER_B64URL JWT_PAYLOAD_B64URL JWT_SIGNATURE_B64URL <<< "${JWT}"
|
||||
|
||||
JWT_HEADER_B64=$(base64url_to_b64 "${JWT_HEADER_B64URL}")
|
||||
JWT_PAYLOAD_B64=$(base64url_to_b64 "${JWT_PAYLOAD_B64URL}")
|
||||
JWT_SIGNATURE_B64=$(base64url_to_b64 "${JWT_SIGNATURE_B64URL}")
|
||||
|
||||
JWT_HEADER=$(echo "${JWT_HEADER_B64}" | base64 -d)
|
||||
JWT_PAYLOAD=$(echo "${JWT_PAYLOAD_B64}" | base64 -d)
|
||||
|
||||
echo "JWT Header:"
|
||||
echo "${JWT_HEADER}" | jq
|
||||
echo "JWT Payload:"
|
||||
echo "${JWT_PAYLOAD}" | jq
|
||||
echo "JWT Signature (Base 64 padded):"
|
||||
echo "${JWT_SIGNATURE_B64}"
|
||||
|
||||
JWT_ALG=$(echo "$JWT_HEADER" | jq -r .alg)
|
||||
JWT_KID=$(echo "$JWT_HEADER" | jq -r .kid)
|
||||
#JWT_TYP=$(echo "$JWT_HEADER" | jq -r .typ)
|
||||
#JWT_ISS=$(echo "$JWT_PAYLOAD" | jq -r .iss)
|
||||
JWT_SUB=$(echo "$JWT_PAYLOAD" | jq -r .sub)
|
||||
JWT_EMAIL=$(echo "$JWT_PAYLOAD" | jq -r .email)
|
||||
JWT_IAT=$(echo "$JWT_PAYLOAD" | jq -r .iat)
|
||||
echo "alg: $JWT_ALG kid: $JWT_KID"
|
||||
echo "sub: $JWT_SUB email: $JWT_EMAIL iat: $JWT_IAT"
|
||||
|
||||
echo "URL: ${URL}"
|
||||
JWK_SET=$(curl -k -s "${URL}")
|
||||
echo >&2 "JWK_SET: $JWK_SET"
|
||||
JWK=$(echo "$JWK_SET" | jq -c -r --arg KID "$JWT_KID" '.keys[] | select(.kid==$KID)')
|
||||
echo >&2 "JWK: $JWK"
|
||||
|
||||
PUB_KEY_FILE=$(mktemp)
|
||||
mint_rsa_key "$JWK" > "$PUB_KEY_FILE"
|
||||
|
||||
# verify signature
|
||||
if [ "${JWT_ALG}" = "RS256" ]; then
|
||||
#SIG_FILE="/tmp/$JWT_SUB-$JWT_IAT.sig.dat"
|
||||
SIG_FILE=$(mktemp)
|
||||
echo -n "$JWT_SIGNATURE_B64" | base64 -d > "${SIG_FILE}"
|
||||
JWT_BODY=$(echo -n "$JWT_HEADER_B64URL.$JWT_PAYLOAD_B64URL")
|
||||
echo -n "$JWT_BODY" | openssl dgst -sha256 -verify "${PUB_KEY_FILE}" -signature "${SIG_FILE}"
|
||||
JWT_SIG_VERIFIED=$?
|
||||
rm "${SIG_FILE}"
|
||||
if [ ${JWT_SIG_VERIFIED} -ne 0 ]; then
|
||||
>&2 echo "Bad Signature"
|
||||
exit ${JWT_SIG_VERIFIED};
|
||||
fi
|
||||
else
|
||||
>&2 echo "Error 3: Unsupported signature algorithm $JWT_ALG"
|
||||
exit 3
|
||||
fi
|
||||
@@ -0,0 +1,87 @@
|
||||
apiVersion: v1
|
||||
kind: Pod
|
||||
metadata:
|
||||
name: "{{ include "spiffe-oidc-discovery-provider.fullname" . }}-test-keys"
|
||||
namespace: {{ include "spiffe-oidc-discovery-provider.namespace" . }}
|
||||
labels:
|
||||
{{- include "spiffe-oidc-discovery-provider.labels" . | nindent 4 }}
|
||||
annotations:
|
||||
"helm.sh/hook": test
|
||||
spec:
|
||||
{{- with .Values.podSecurityContext }}
|
||||
securityContext:
|
||||
{{- toYaml . | nindent 4 }}
|
||||
{{- end }}
|
||||
serviceAccountName: {{ include "spiffe-oidc-discovery-provider.serviceAccountName" . }}
|
||||
initContainers:
|
||||
- name: static-busybox
|
||||
image: {{ template "spire-lib.image" (dict "image" .Values.tests.busybox.image "global" .Values.global) }}
|
||||
command:
|
||||
- sh
|
||||
- -c
|
||||
- |
|
||||
cp /bin/busybox /data/busybox
|
||||
chmod +x /data/busybox
|
||||
{{- with .Values.securityContext }}
|
||||
securityContext:
|
||||
{{- toYaml . | nindent 8 }}
|
||||
{{- end }}
|
||||
volumeMounts:
|
||||
- name: data-volume
|
||||
mountPath: /data
|
||||
- name: gettoken
|
||||
image: {{ template "spire-lib.image" (dict "appVersion" $.Chart.AppVersion "image" .Values.tools.kubectl.image "global" .Values.global "KubeVersion" .Capabilities.KubeVersion.Version "image" .Values.tests.agent.image) }}
|
||||
command:
|
||||
- /data/busybox
|
||||
- sh
|
||||
- -c
|
||||
- |
|
||||
while true; do
|
||||
/opt/spire/bin/spire-agent api fetch jwt -audience foo -format json -socketPath /spire-agent/spire-agent.sock -timeout 5s > /data/token.svid
|
||||
[ $? -eq 0 ] && break
|
||||
sleep 1
|
||||
done
|
||||
{{- with .Values.securityContext }}
|
||||
securityContext:
|
||||
{{- toYaml . | nindent 8 }}
|
||||
{{- end }}
|
||||
volumeMounts:
|
||||
- name: data-volume
|
||||
mountPath: /data
|
||||
- name: spire-api
|
||||
mountPath: /spire-agent
|
||||
readOnly: true
|
||||
containers:
|
||||
- name: verify-keys
|
||||
image: {{ template "spire-lib.image" (dict "image" .Values.tests.toolkit.image "global" .Values.global) }}
|
||||
command:
|
||||
- bash
|
||||
env:
|
||||
- name: TMPDIR
|
||||
value: /data
|
||||
args:
|
||||
- -c
|
||||
- |
|
||||
URL=http://{{ include "spiffe-oidc-discovery-provider.fullname" . }}.{{ include "spiffe-oidc-discovery-provider.namespace" . }}.svc.{{ include "spire-lib.cluster-domain" . }}:{{ .Values.service.port }}
|
||||
curl -k -s -f "${URL}"/keys
|
||||
JWT=$(cat /data/token.svid | jq -r '.[].svids[0].svid' | xargs)
|
||||
cat <<'EOF' >> /data/jwt-decode.sh
|
||||
{{- (.Files.Get "files/test/jwt-decode.sh") | nindent 10 }}
|
||||
EOF
|
||||
bash /data/jwt-decode.sh "${URL}"/keys "${JWT}"
|
||||
{{- with .Values.securityContext }}
|
||||
securityContext:
|
||||
{{- toYaml . | nindent 8 }}
|
||||
{{- end }}
|
||||
volumeMounts:
|
||||
- mountPath: /data
|
||||
name: data-volume
|
||||
restartPolicy: Never
|
||||
volumes:
|
||||
- csi:
|
||||
driver: csi.spiffe.io
|
||||
readOnly: true
|
||||
name: spire-api
|
||||
- name: data-volume
|
||||
emptyDir: {}
|
||||
---
|
||||
@@ -225,6 +225,44 @@ tests:
|
||||
# -- Overrides the image tag
|
||||
tag: latest@sha256:96ab1600d945b4a99c8610b5c8b31e346da63dc20573a26bb0777dd0190db5d4
|
||||
|
||||
toolkit:
|
||||
image:
|
||||
# -- The OCI registry to pull the tests image from
|
||||
registry: cgr.dev
|
||||
# -- The repository within the registry
|
||||
repository: chainguard/slim-toolkit-debug
|
||||
# -- The tests image pull policy
|
||||
pullPolicy: IfNotPresent
|
||||
# -- This value is deprecated in favor of tag. (Will be removed in a future release)
|
||||
version: ""
|
||||
# -- Overrides the image tag
|
||||
tag: latest@sha256:d717d0a2c88518f8e36d9cfe1571639a40617e8c4291e34876d46bdeefb1ab5a
|
||||
|
||||
busybox:
|
||||
image:
|
||||
# -- The OCI registry to pull the image from
|
||||
registry: ""
|
||||
# -- The repository within the registry
|
||||
repository: busybox
|
||||
# -- The image pull policy
|
||||
pullPolicy: IfNotPresent
|
||||
# -- This value is deprecated in favor of tag. (Will be removed in a future release)
|
||||
version: ""
|
||||
# -- Overrides the image tag
|
||||
tag: uclibc@sha256:3e516f71d8801b0ce6c3f8f8e4f11093ec04e168177a90f1da4498014ee06b6b
|
||||
agent:
|
||||
image:
|
||||
# -- The OCI registry to pull the image from
|
||||
registry: ghcr.io
|
||||
# -- The repository within the registry
|
||||
repository: spiffe/spire-agent
|
||||
# -- The image pull policy
|
||||
pullPolicy: IfNotPresent
|
||||
# -- This value is deprecated in favor of tag. (Will be removed in a future release)
|
||||
version: ""
|
||||
# -- Overrides the image tag
|
||||
tag: ""
|
||||
|
||||
tools:
|
||||
kubectl:
|
||||
image:
|
||||
|
||||
Reference in New Issue
Block a user