portainer: gate the admin bootstrap on being able to log in
The previous guard was 'does the password file exist'. The first lab1 install wrote the password, then failed init on the missing setup token — leaving a file that made every later run skip the bootstrap and then fail to authenticate, so OIDC never got configured. Ask Portainer instead: try /api/auth, and bootstrap only when that yields no token. The JWT is then reused for the settings PUT rather than logging in twice.
This commit is contained in:
parent
77f361120a
commit
1c48eb4634
1 changed files with 22 additions and 13 deletions
|
|
@ -123,16 +123,28 @@ for _ in $(seq 1 24); do
|
||||||
done
|
done
|
||||||
[[ "${UP}" -eq 1 ]] || die "Portainer did not answer on :9443"
|
[[ "${UP}" -eq 1 ]] || die "Portainer did not answer on :9443"
|
||||||
|
|
||||||
# ── 4. Bootstrap the local admin (once) ──────────────────────────────
|
# ── 4. Bootstrap the local admin ─────────────────────────────────────
|
||||||
# Portainer refuses admin creation after a timeout window, so this must happen
|
# The password is kept on the VM for break-glass access — OIDC is the everyday
|
||||||
# promptly after first start. The password is kept on the VM for break-glass
|
# path, this is the account that survives an Authentik outage.
|
||||||
# access — OIDC is the everyday path, this is the account that survives an
|
#
|
||||||
# Authentik outage.
|
# The guard is "can we log in?", NOT "does the password file exist": a failed
|
||||||
|
# init leaves a password file behind, and keying off the file makes every later
|
||||||
|
# run skip the bootstrap forever (seen on the first lab1 install).
|
||||||
if ! vm "sudo test -s ${ADMIN_SECRET}" 2>/dev/null; then
|
if ! vm "sudo test -s ${ADMIN_SECRET}" 2>/dev/null; then
|
||||||
info " Bootstrapping the break-glass admin account..."
|
|
||||||
vm "sudo install -d -m 0700 \$(dirname ${ADMIN_SECRET})"
|
vm "sudo install -d -m 0700 \$(dirname ${ADMIN_SECRET})"
|
||||||
vm "openssl rand -base64 24 | sudo tee ${ADMIN_SECRET} >/dev/null && sudo chmod 0600 ${ADMIN_SECRET}"
|
vm "openssl rand -base64 24 | sudo tee ${ADMIN_SECRET} >/dev/null && sudo chmod 0600 ${ADMIN_SECRET}"
|
||||||
ADMIN_PW="$(vm "sudo cat ${ADMIN_SECRET}" | tr -d '\r')"
|
fi
|
||||||
|
ADMIN_PW="$(vm "sudo cat ${ADMIN_SECRET}" | tr -d '\r')"
|
||||||
|
|
||||||
|
portainer_jwt() {
|
||||||
|
vm "curl -sk -X POST https://localhost:9443/api/auth \
|
||||||
|
-H 'Content-Type: application/json' \
|
||||||
|
-d '{\"Username\":\"admin\",\"Password\":\"${ADMIN_PW}\"}'" 2>/dev/null | jq -r '.jwt // empty'
|
||||||
|
}
|
||||||
|
|
||||||
|
JWT="$(portainer_jwt)"
|
||||||
|
if [[ -z "${JWT}" ]]; then
|
||||||
|
info " Bootstrapping the break-glass admin account..."
|
||||||
# Portainer >= 2.39 prints a one-time setup token at startup and refuses
|
# Portainer >= 2.39 prints a one-time setup token at startup and refuses
|
||||||
# admin creation without it (HTTP 403). The log line wraps the value in ANSI
|
# admin creation without it (HTTP 403). The log line wraps the value in ANSI
|
||||||
# colour codes, so match the 64-hex token rather than "setup_token=<value>".
|
# colour codes, so match the 64-hex token rather than "setup_token=<value>".
|
||||||
|
|
@ -144,18 +156,18 @@ if ! vm "sudo test -s ${ADMIN_SECRET}" 2>/dev/null; then
|
||||||
-d '{\"Username\":\"admin\",\"Password\":\"${ADMIN_PW}\"}'" || echo 000)"
|
-d '{\"Username\":\"admin\",\"Password\":\"${ADMIN_PW}\"}'" || echo 000)"
|
||||||
case "${init_code}" in
|
case "${init_code}" in
|
||||||
200|204) info " admin created (password in ${ADMIN_SECRET} on the VM)" ;;
|
200|204) info " admin created (password in ${ADMIN_SECRET} on the VM)" ;;
|
||||||
409) info " admin already existed — keeping it" ;;
|
409) warn " an admin exists but ${ADMIN_SECRET} does not match it — reset it by hand" ;;
|
||||||
*) warn " admin init returned HTTP ${init_code}; configure the admin by hand at ${UI_URL}" ;;
|
*) warn " admin init returned HTTP ${init_code}; configure the admin by hand at ${UI_URL}" ;;
|
||||||
esac
|
esac
|
||||||
|
JWT="$(portainer_jwt)"
|
||||||
else
|
else
|
||||||
ADMIN_PW="$(vm "sudo cat ${ADMIN_SECRET}" | tr -d '\r')"
|
|
||||||
info " break-glass admin already provisioned"
|
info " break-glass admin already provisioned"
|
||||||
fi
|
fi
|
||||||
|
|
||||||
# ── 5. Point Portainer at TAPPaaS identity (OIDC) ────────────────────
|
# ── 5. Point Portainer at TAPPaaS identity (OIDC) ────────────────────
|
||||||
# identity:identity wrote these three values; if they are missing the module is
|
# identity:identity wrote these three values; if they are missing the module is
|
||||||
# still usable with the local admin, so warn rather than fail.
|
# still usable with the local admin, so warn rather than fail.
|
||||||
if [[ -n "${ADMIN_PW:-}" ]] && vm "sudo test -s ${SECRETS_ENV}" 2>/dev/null; then
|
if [[ -n "${JWT:-}" ]] && vm "sudo test -s ${SECRETS_ENV}" 2>/dev/null; then
|
||||||
info " Configuring OIDC login against Authentik..."
|
info " Configuring OIDC login against Authentik..."
|
||||||
CLIENT_ID="$(vm "sudo sh -c '. ${SECRETS_ENV}; printf %s \"\$OIDC_CLIENT_ID\"'" | tr -d '\r')"
|
CLIENT_ID="$(vm "sudo sh -c '. ${SECRETS_ENV}; printf %s \"\$OIDC_CLIENT_ID\"'" | tr -d '\r')"
|
||||||
CLIENT_SECRET="$(vm "sudo sh -c '. ${SECRETS_ENV}; printf %s \"\$OIDC_CLIENT_SECRET\"'" | tr -d '\r')"
|
CLIENT_SECRET="$(vm "sudo sh -c '. ${SECRETS_ENV}; printf %s \"\$OIDC_CLIENT_SECRET\"'" | tr -d '\r')"
|
||||||
|
|
@ -169,9 +181,6 @@ if [[ -n "${ADMIN_PW:-}" ]] && vm "sudo test -s ${SECRETS_ENV}" 2>/dev/null; the
|
||||||
USER_URI="$(jq -r '.userinfo_endpoint // empty' <<<"${WELL_KNOWN}")"
|
USER_URI="$(jq -r '.userinfo_endpoint // empty' <<<"${WELL_KNOWN}")"
|
||||||
|
|
||||||
if [[ -n "${AUTH_URI}" && -n "${TOKEN_URI}" && -n "${USER_URI}" ]]; then
|
if [[ -n "${AUTH_URI}" && -n "${TOKEN_URI}" && -n "${USER_URI}" ]]; then
|
||||||
JWT="$(vm "curl -sk -X POST https://localhost:9443/api/auth \
|
|
||||||
-H 'Content-Type: application/json' \
|
|
||||||
-d '{\"Username\":\"admin\",\"Password\":\"${ADMIN_PW}\"}'" | jq -r '.jwt // empty')"
|
|
||||||
if [[ -n "${JWT}" ]]; then
|
if [[ -n "${JWT}" ]]; then
|
||||||
# AuthenticationMethod 3 = OAuth. OAuthAutoCreateUsers lets a
|
# AuthenticationMethod 3 = OAuth. OAuthAutoCreateUsers lets a
|
||||||
# TAPPaaS identity log in without an admin pre-creating it;
|
# TAPPaaS identity log in without an admin pre-creating it;
|
||||||
|
|
|
||||||
Loading…
Add table
Reference in a new issue