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
|
# -- Overrides the image tag
|
||||||
tag: latest@sha256:96ab1600d945b4a99c8610b5c8b31e346da63dc20573a26bb0777dd0190db5d4
|
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:
|
tools:
|
||||||
kubectl:
|
kubectl:
|
||||||
image:
|
image:
|
||||||
|
|||||||
Reference in New Issue
Block a user