mirror of
https://github.com/versity/versitygw.git
synced 2026-09-22 07:54:14 +00:00
Role last-used tracking was missing entirely - `GetRole` returned a `RoleLastUsed` element that nothing ever wrote, rendering the zero time instead of the empty element AWS returns for an unused role - and access key last-used only ever saw the `IAM`/`STS` control plane, so a credential used exclusively against the S3 gateway reported as never used. Roles now record a use whenever a request authenticates with one of their session credentials, through a new `Storer.RecordRoleUsage` mirroring `RecordAccessKeyUsage`, gated on the session's role still being the one it was minted against so a session outliving its role can't attribute its use to a same-named replacement. `LastUsedDate` became a `*time.Time` so an unused role renders as an empty element. Both records now cover the S3 data plane as well: the gateway sends its configured region and `s3` on evaluate-policy and the IAM service records the caller there, so `GetAccessKeyLastUsed's` `ServiceName` is now iam, sts or s3. That call was chosen over derive-signing-key, which runs before signature verification and takes its region and service from the caller's own `Authorization` header - recording there would let anyone who knows an access key id refresh and poison another identity's audit record. Requests denied by a bucket policy or made against a public bucket are not recorded, since neither reaches identity-policy evaluation. To keep per-request recording affordable, an update is skipped while the stored record has the same service and region and is under a minute old; a change of either is written through immediately. Assuming a role is not a use, a request denied by an identity policy is, and both successful and denied S3 requests update the record. Also moves the `OIDC-dependent` tests into the `s3-iam-session` group so runoidctests.sh runs a single group.
103 lines
3.1 KiB
Bash
Executable File
103 lines
3.1 KiB
Bash
Executable File
#!/usr/bin/env bash
|
|
#
|
|
# Run the test groups that need a real, signed OIDC ID token.
|
|
#
|
|
# AssumeRoleWithWebIdentity verifies a token's signature against its issuer's
|
|
# live JWKS, so these tests need a genuine identity provider rather than a
|
|
# fake token. GitHub Actions' own OIDC issuer is the one publicly reachable
|
|
# IdP available from inside CI, and only a job holding `id-token: write` can
|
|
# mint a token from it — which is why this script lives behind
|
|
# .github/workflows/functional-iam-oidc.yml rather than the general
|
|
# functional suite. Outside such a job the tests skip themselves, so running
|
|
# this locally is harmless but proves little.
|
|
#
|
|
# It brings up two processes: a standalone IAM service holding every user,
|
|
# role, policy and secret, and an s3 gateway that reaches its private
|
|
# endpoints over mTLS for signing keys and policy decisions.
|
|
|
|
set -Eeuo pipefail
|
|
|
|
readonly IAM_PORT=7078
|
|
readonly IAM_PRIVATE_PORT=7079
|
|
readonly GW_PORT=7077
|
|
|
|
readonly IAM_DIR=/tmp/iam-oidc
|
|
readonly GW_DIR=/tmp/s3iam-oidc-gw
|
|
readonly CERT_DIR=/tmp/s3iam-oidc-certs
|
|
|
|
IAM_PID=""
|
|
GW_PID=""
|
|
|
|
cleanup() {
|
|
local status=$?
|
|
trap - EXIT
|
|
for pid in "$GW_PID" "$IAM_PID"; do
|
|
if [[ -n "$pid" ]] && kill -0 "$pid" 2>/dev/null; then
|
|
kill "$pid" 2>/dev/null || true
|
|
fi
|
|
if [[ -n "$pid" ]]; then
|
|
wait "$pid" 2>/dev/null || true
|
|
fi
|
|
done
|
|
exit "$status"
|
|
}
|
|
|
|
trap cleanup EXIT
|
|
trap 'exit 130' INT
|
|
trap 'exit 143' TERM
|
|
|
|
wait_for_server() {
|
|
local name="$1"
|
|
local url="$2"
|
|
local pid="$3"
|
|
|
|
for _ in {1..50}; do
|
|
if curl --fail --silent --max-time 1 "$url" >/dev/null 2>&1; then
|
|
return 0
|
|
fi
|
|
if ! kill -0 "$pid" 2>/dev/null; then
|
|
echo "$name stopped before becoming ready" >&2
|
|
wait "$pid" 2>/dev/null || true
|
|
return 1
|
|
fi
|
|
sleep 0.2
|
|
done
|
|
|
|
echo "timed out waiting for $name at $url" >&2
|
|
return 1
|
|
}
|
|
|
|
rm -rf "$IAM_DIR" "$GW_DIR" "$CERT_DIR"
|
|
mkdir -p "$IAM_DIR" "$GW_DIR"
|
|
|
|
# The gateway verifies the IAM service's certificate normally, with no
|
|
# hostname override, so the server certificate needs an IP SAN matching the
|
|
# address --iam-standalone-endpoint names.
|
|
./genmtlscerts.sh "$CERT_DIR" 127.0.0.1
|
|
|
|
echo "Starting the standalone IAM service"
|
|
./versitygw --health /healthz -p ":$IAM_PORT" -a user -s pass iam \
|
|
--dir "$IAM_DIR" \
|
|
--private-ports "127.0.0.1:$IAM_PRIVATE_PORT" \
|
|
--private-cert "$CERT_DIR/iam-server.pem" \
|
|
--private-cert-key "$CERT_DIR/iam-server.key" \
|
|
--private-client-ca "$CERT_DIR/ca.pem" &
|
|
IAM_PID=$!
|
|
wait_for_server "IAM API server" "http://127.0.0.1:$IAM_PORT/healthz" "$IAM_PID"
|
|
|
|
echo "Starting the s3 gateway backed by it"
|
|
./versitygw --health /healthz -p ":$GW_PORT" -a user -s pass \
|
|
--iam-standalone-endpoint "127.0.0.1:$IAM_PRIVATE_PORT" \
|
|
--iam-standalone-client-cert "$CERT_DIR/gw-client.pem" \
|
|
--iam-standalone-client-cert-key "$CERT_DIR/gw-client.key" \
|
|
--iam-standalone-server-ca "$CERT_DIR/ca.pem" \
|
|
posix "$GW_DIR" &
|
|
GW_PID=$!
|
|
wait_for_server "s3 gateway" "http://127.0.0.1:$GW_PORT/healthz" "$GW_PID"
|
|
|
|
echo "Running the tests that need a real OIDC identity provider"
|
|
./versitygw test -a user -s pass \
|
|
-e "http://127.0.0.1:$GW_PORT" \
|
|
--iam-endpoint "http://127.0.0.1:$IAM_PORT" \
|
|
s3-iam-session
|