Upgrade to v1.76¶
Move a v1.75 installation to v1.76.3, on Lambda or Kubernetes. History is in the CHANGELOG.
Before you start¶
- Run v1.75 on secrets layout v5 (v1.75 first if older).
- Admit the new roles (step 1) before the first apply.
- The first apply deletes the old issuer log group.
- Set
backup.recipientsbefore the backup function starts (step 3).
v1.76.4 needs no action: the edge cache is opt-in and policy/compile is an unused library.
What is new¶
| Module | Lambda function | Kubernetes | Serves |
|---|---|---|---|
| issuer | sluis-<inst>-issuer, renamed |
issuer Deployment | sign-in, tokens, console |
| github | sluis-<inst>-github |
modules.github |
controller passes, console, installation-token mint |
| slack | sluis-<inst>-slack |
modules.slack |
controller passes, console |
sluis-<inst>-google |
modules.google |
directory refresh, console, sign-in identity | |
| cloudflare | sluis-<inst>-cloudflare, with a preset |
modules.cloudflare |
token and R2 mint |
| backup, restore | sluis-<inst>-backup, -restore |
backup.enabled CronJobs, restore.enabled Job |
age-encrypted backups, format 2 (v1.76.1); the backup role lists internal/* and external/* (v1.76.3) |
github-mint is gone. With <module>.remote set, the issuer opens none of that module's stores.
The issuer moves by Pulumi aliases, creating before it deletes:
| Resource | First apply |
|---|---|
| function, role, role policy, async invoke config | replaced |
| log group | old deleted, new created: export what you need |
| API integration, schedules, invoke grants | updated in place |
| tables, parameters, keys, buckets | unchanged |
restore identity (RandomBytes, SSM parameter) |
created, with NewBackup |
| the v4 state secret and recovery password | deleted on Layout: v5 unless Compat.KeepV4 (v1.76.0) |
To keep the old name, set aws.functions.issuer to sluis or sluis-http: nothing is replaced.
1. Admit the new roles¶
Take the lists from the library, not from hand lists.
senders, _ := args.Senders()
roles, _ := args.Roles()
viewers, _ := args.ViewerRoles()
statements, _ := args.KeyPolicyStatements(sluispulumi.KeyPolicyOptions{Admins: adminArns})
| Estate side | Admit |
|---|---|
| key policies | statements: SluisKeyAdminReads now covers the restore identity (v1.76.2), SluisKeyDenyRestoreIdentity refuses it to the backup role |
| audit senders, OTLP writers | senders |
| viewer matchers | viewers |
aws.functions.github-mint, its roles in key policies, senders and viewers |
delete; the schema refuses the key |
Set TransitionRoles for the renaming apply, and remove it once the old role is gone.
2. Update the policy¶
| Change | Action |
|---|---|
| roster controllers | a service_account or aws matcher places them in all:sluis:roster-controller, else Explain refuses them |
sluisctl client |
register it beside accessctl before workstations upgrade |
Explain |
operators only, and audited |
clients:
sluisctl: { kind: public, requires: [all:sluis:operator], redirects: [/callback], sign_in_exchange: true }
accessctl: { kind: public, requires: [all:sluis:operator], redirects: [/callback], sign_in_exchange: true }
sluisctl login probes for sluisctl and, on invalid_client, signs in as accessctl once. An explicit clientId: accessctl never falls back: delete it. sluisctl explain is removed.
sluisctl token --audience example --show
3. Move the backup to age keys¶
Make an offline break-glass key and give its recipient to the library (back up and restore on layout v5).
age-keygen -o breakglass.txt
age-keygen -y breakglass.txt # the age1... recipient
backup, _ := sluispulumi.NewBackup(ctx, "acme", &sluispulumi.BackupArgs{
BackupCommon: common,
ExtraRecipients: []string{"age1..."},
}, pulumi.Providers(awsProvider))
| Change | Action |
|---|---|
ArchiveKeyAlias, KeyPolicyOptions.BackupArchive, RestoreArchive, ArchiveGrant.KeyArn |
delete: deprecated, they add nothing |
| hand-written archive statements on a shared key | delete |
NewRestore |
keep NewBackup of the same instance in the stack: it creates the identity |
Kubernetes backup.config.backup |
set recipients; drop key, region and keys.archive, ignored with a warning for one release |
an S3 or R2 store that refuses x-amz-checksum-sha256 |
ports.blob.s3.checksum and backup.target.checksum: md5 or none (v1.76.1) |
Compat.DropV4 |
delete: a no-op on v5. Set Compat.KeepV4 to keep the v4 parameters |
4. Apply¶
On Lambda, apply with the v1.76.3 library and preview again until clean. On Kubernetes, enable the modules:
modules:
github: { enabled: true }
slack: { enabled: true }
| Setting | Effect |
|---|---|
<module>.serve in the callee's document |
/rpc on rpcPort (8081), TokenReview, issuers is the issuer's ServiceAccount |
<module>.remote.url in the issuer's |
calls the Service |
modules.<m>.audience |
token audience, the module's name |
| issuer pod | one projected token per audience |
serve with remote is refused. Another subject gets a 401.
5. Move the audit catalogue¶
Deploy the release's whole sluis-audit-catalogue_<version>.tar.gz with the writer.
| Version | Adds |
|---|---|
| 1.19.0 | roster.access.explained |
| 1.20.0 | refusal fields on roster.token.exchanged, roster.person.signed_in, roster.recovery.signed_in |
The audit installation refuses a different document under a held version (rule).
6. Update the clients¶
Refusals say not authorised (request <id>) and carry X-Request-Id. Match on error, never on error_description. The reason is under request_id in the log and context.request_id in the audit trail.
Verify¶
| Check | Expect |
|---|---|
sluis check --config issuer.yaml |
passes, each module too |
| preview | clean |
sluisctl login, token --show |
signs in as sluisctl |
| one console page per module | answers |
| GitHub mint | token, no github-mint call |
roster.access.explained |
one record per look-up |
| roster controllers | no not authorised |
Kubernetes /healthz; /rpc with no bearer |
200; 401 |
sluisctl backup list after the first run |
<id>.tar.gz.age with its <id>.json; sluis backup verify <id> --identity breakglass.txt passes |
Roll back¶
- Repoint the issuer's
livealias whileTransitionRolesis set. - Keep both clients until every workstation signs in as
sluisctl. - A v1.76.1 backup opens only with an age identity; v1.75 cannot read it.