Skip to content

Upgrade to v1.77.1

v1.77.1 removes storage layout v4 and its tools (ADR 0072), signs the recovery account in by SRP instead of a password (ADR 0076) and sends HSTS. History is in the CHANGELOG.

Before you start

The installation must run layout v5 on v1.77.0 or earlier (v1.77 if older). v1.77.1 neither reads layout v4 nor migrates from it. Upgrade the service and the Pulumi library together: the service reads a verifier the library writes. Stop any script that sends the recovery password to <console>/login/recovery: the service answers it with 400 without reading it.

Check Expected
secrets with source: ssm layout: v5
ports.dynamodb or adapters.state.settings tables, one per module; no table
DynamoDB the module tables only; the v4 table is retired
SSM nothing under <root>/internal/credentials/; no layout v4 name of a moved secret (below)
the Pulumi program Layout: LayoutV5 and no Compat other than RetireLegacyTable

A layout v4 installation moves with v1.77.0 first: v1.75, v1.76, sluis migrate v5 prune.

v1.77.1 reads none of these layout v4 names:

Layout v4 name below <root>/ Layout v5 name
internal/credentials/... internal/<module>/...
internal/config/issuer/state-secret internal/oidc/state-secret
internal/config/recovery/password internal/oidc/recovery-password
internal/config/providers/google/<p>/client-id, client-secret internal/oidc/signin/<p>/...
internal/config/clients/<id>/secret internal/oidc/clients/<id>

Delete them with sluis migrate v5 prune of v1.77.0, or by name. The ssm source still reads other names under internal/config/, such as valkey/password.

aws ssm describe-parameters --query 'Parameters[].Name' --output text \
  --parameter-filters "Key=Name,Option=BeginsWith,Values=/sluis/<instance>/internal/credentials/"

What was removed

Removed Use instead
secrets.layout: v4, and an ssm section without layout layout: v5
ports.dynamodb.table, adapters.state.settings.table, the installation's aws.table tables, one per module
sluis migrate v5 v1.77.0
sluis migrate --skip directory --skip google
sluis serve sluis issuer
Pulumi Layout, LayoutV4, LayoutV5, LayoutV4V5 on LambdaArgs, RoleArgs, KeyPolicyArgs nothing
Pulumi CompatArgs; Compat on LambdaArgs and StatesArgs nothing
Pulumi StatesArgs.Legacy, LegacyStateArgs, States.Legacy, States.LegacyBackupArn, LegacyBackupArnOutput, LegacyBackupRetentionDays nothing
Pulumi NewState, StateArgs, State, StateType, StateGrant.TableArn, PortsArgs.TableName NewStates, States.Grant()
Pulumi LambdaArgs.MigrationRoleArn nothing
Pulumi StateSecretParameterName, RecoveryPasswordParameterName, ConfigParameterPrefix the ...V5 names

A document that names a removed key does not load.

1. Update the Pulumi program

 args := &sluispulumi.LambdaArgs{
-   Layout: sluispulumi.LayoutV5,
 }
 roles := sluispulumi.RoleArgs{
-   Layout: sluispulumi.LayoutV5,
 }
-state := &sluispulumi.StateGrant{Tables: tables, TableArn: legacy}
+state := &sluispulumi.StateGrant{Tables: tables}

Delete any constant built from ConfigParameterPrefix or StateSecretParameterName. A layout v5 installation's preview then shows no change.

2. Update documents and command lines

Where Change
secrets: {source: ssm} add layout: v5
a single table name the module tables in tables
sluis serve sluis issuer
--skip directory --skip google

3. Kubernetes with another secrets store

With the openbao or memory Secrets adapter, copy each credential sluis writes to its layout v5 address, keeping the <ref>, before the new version starts. One not copied reads as absent, so make its connection again.

Credential Before v1.77.1
Google Workspace key credentials/directory/google/<id>/<ref> credentials/google/workspace/<id>/<ref>
organisation credentials/github-org/<org>/<ref> credentials/github/org/<org>/<ref>
link App credentials/github-app/link/<ref> credentials/github/app/link/<ref>
catalogue App credentials/github-app/<id>/<ref> credentials/github/app/<id>/<ref>
runner App credentials/github-runner-app/<tier>/<org>/<ref> credentials/github/app/runner-<tier>-<org>/<ref>
GitHub link credentials/github-link/<account>/<ref> credentials/github/link/<account>/<ref>
Slack workspace credentials/slack-workspace/<team>/<ref> credentials/slack/workspace/<team>/<ref>
Slack App credentials/slack-app/<id>/<ref> credentials/slack/app/<id>/<ref>
console session key credentials/console/session-key credentials/oidc/console/session-key
generated client credentials/oidc-client/<id>/secret unchanged

4. Update the policy

The issuer's password sign-in signs in as system:serviceaccount:<namespace>:<recovery.serviceAccount>, or sluis:recovery where none is set. Place it in the group the console client requires, as a cluster already does.

all:sluis:operator:
  matchers:
    - service_account: {namespace: sluis, name: recovery}

5. Apply

The library writes the recovery verifier and denies the issuer's role the password.

pulumi preview --diff
pulumi up
Resource Effect
internal/oidc/recovery-verifier created
internal/oidc/recovery-password, conformance-password the issuer's role loses read
recovery.verifierSecret: recovery/verifier rendered in place of recovery.passwordSecret

Without Pulumi, derive the credential and store it where recovery.verifierSecret names.

sluisctl recovery password --instance <instance> | sluisctl recovery verifier

6. Check the behaviour changes

Change Who notices
The sign-in page proves the password with SRP-6a and never sends it operators who recover
The issuer and the console send Strict-Transport-Security on https a host that cannot answer https
Refusal log lines carry method, path, client_id and user_agent log alerts that match refusals
sluis secrets rekey compares keys by resolved ARN operators who rekey
Audit database URLs need sslmode=verify-full, a CA file and a password file (upgrade audit) installations that run audit with Postgres

hsts.maxAge and hsts.includeSubDomains tune the header (endpoints).

7. Roll

Roll the service, the modules and the library together.

Verify

Sign in at https://<issuer host>/console/login with Recovery sign-in, then turn recovery off (turn off recovery).

Roll back

Roll back to v1.77.0 with the same documents. With another secrets store, copy the credentials back first.