aac-cli 0.1.5__tar.gz → 0.1.6__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (32) hide show
  1. {aac_cli-0.1.5/aac_cli.egg-info → aac_cli-0.1.6}/PKG-INFO +214 -25
  2. {aac_cli-0.1.5 → aac_cli-0.1.6}/README.md +213 -24
  3. {aac_cli-0.1.5 → aac_cli-0.1.6}/aac_cli/__init__.py +1 -1
  4. {aac_cli-0.1.5 → aac_cli-0.1.6}/aac_cli/init_cli.py +168 -26
  5. {aac_cli-0.1.5 → aac_cli-0.1.6}/aac_cli/workspace_cli.py +40 -21
  6. aac_cli-0.1.6/aac_cli/workspace_health.py +373 -0
  7. {aac_cli-0.1.5 → aac_cli-0.1.6}/aac_cli/workspace_layout.py +17 -7
  8. {aac_cli-0.1.5 → aac_cli-0.1.6/aac_cli.egg-info}/PKG-INFO +214 -25
  9. {aac_cli-0.1.5 → aac_cli-0.1.6}/pyproject.toml +1 -1
  10. aac_cli-0.1.5/aac_cli/workspace_health.py +0 -156
  11. {aac_cli-0.1.5 → aac_cli-0.1.6}/LICENSE +0 -0
  12. {aac_cli-0.1.5 → aac_cli-0.1.6}/MANIFEST.in +0 -0
  13. {aac_cli-0.1.5 → aac_cli-0.1.6}/aac_cli/__main__.py +0 -0
  14. {aac_cli-0.1.5 → aac_cli-0.1.6}/aac_cli/admin_key_pem.py +0 -0
  15. {aac_cli-0.1.5 → aac_cli-0.1.6}/aac_cli/api_key_rotation_state.py +0 -0
  16. {aac_cli-0.1.5 → aac_cli-0.1.6}/aac_cli/cli.py +0 -0
  17. {aac_cli-0.1.5 → aac_cli-0.1.6}/aac_cli/config.py +0 -0
  18. {aac_cli-0.1.5 → aac_cli-0.1.6}/aac_cli/config_render.py +0 -0
  19. {aac_cli-0.1.5 → aac_cli-0.1.6}/aac_cli/dev_material.py +0 -0
  20. {aac_cli-0.1.5 → aac_cli-0.1.6}/aac_cli/idp_recovery.py +0 -0
  21. {aac_cli-0.1.5 → aac_cli-0.1.6}/aac_cli/profiles.py +0 -0
  22. {aac_cli-0.1.5 → aac_cli-0.1.6}/aac_cli/reference.py +0 -0
  23. {aac_cli-0.1.5 → aac_cli-0.1.6}/aac_cli/registration_state.py +0 -0
  24. {aac_cli-0.1.5 → aac_cli-0.1.6}/aac_cli/secure_files.py +0 -0
  25. {aac_cli-0.1.5 → aac_cli-0.1.6}/aac_cli/sso_login.py +0 -0
  26. {aac_cli-0.1.5 → aac_cli-0.1.6}/aac_cli/workspace_manifest.py +0 -0
  27. {aac_cli-0.1.5 → aac_cli-0.1.6}/aac_cli.egg-info/SOURCES.txt +0 -0
  28. {aac_cli-0.1.5 → aac_cli-0.1.6}/aac_cli.egg-info/dependency_links.txt +0 -0
  29. {aac_cli-0.1.5 → aac_cli-0.1.6}/aac_cli.egg-info/entry_points.txt +0 -0
  30. {aac_cli-0.1.5 → aac_cli-0.1.6}/aac_cli.egg-info/requires.txt +0 -0
  31. {aac_cli-0.1.5 → aac_cli-0.1.6}/aac_cli.egg-info/top_level.txt +0 -0
  32. {aac_cli-0.1.5 → aac_cli-0.1.6}/setup.cfg +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: aac-cli
3
- Version: 0.1.5
3
+ Version: 0.1.6
4
4
  Summary: The aac platform CLI — headless operator interface to the AAC control plane (tenant registration, chain audit).
5
5
  Author: Agent Authority Cloud Project
6
6
  License-Expression: Apache-2.0
@@ -56,8 +56,15 @@ Python 3.10 or newer is required.
56
56
 
57
57
  ## Guided setup for developer tenants: `aac init`
58
58
 
59
- `aac init` signs you in, registers a developer tenant (or reuses the one
60
- your profile is already bound to), takes the trust domain AAC assigns to the
59
+ `aac init` prepares the AAC side of one of your agents on this machine: it
60
+ registers the agent's identity with AAC and creates the keys, certificates
61
+ and configuration its sidecar needs. The agent itself is yours. The first
62
+ run also creates your profile and registers your tenant; run it again with
63
+ a new `--workspace` and `--workload-path`, and the same `--trust-url` and
64
+ `--idp`, for each further agent.
65
+
66
+ Along the way it signs you in, registers a developer tenant (or reuses the
67
+ one your profile is already bound to), takes the trust domain AAC assigns to the
61
68
  tenant, registers a sample workload, generates development keys and
62
69
  certificates, and writes a complete sidecar configuration together with the
63
70
  files the trust-anchor publisher and Docker Compose need.
@@ -86,6 +93,20 @@ aac init --profile stage \
86
93
  --create-tenant
87
94
  ```
88
95
 
96
+ `--idp` names how you sign in: `github` or `google`, the two sign-ins AAC
97
+ offers developer tenants. If you need another sign-in provider, contact
98
+ support@cascadeauth.com.
99
+
100
+ `--trust-url` is required when a workspace is created: it is the public URL
101
+ where your AAC environment serves trust material, and for AAC stage it is
102
+ `https://trust.stage.cascadeauth.dev`. If you leave it out, the command
103
+ stops before creating anything and names the value your tenant already
104
+ uses, if it has one.
105
+
106
+ Setting up a new developer tenant takes two browser sign-ins: the first
107
+ registers the tenant, the second starts the tenant-admin session that
108
+ registers the workload. The command says so before the first one.
109
+
89
110
  Progress lines `[1/5]` to `[5/5]` name the five steps: tenant, sign-in,
90
111
  hosted trust domain, workload, and material; the configuration files are
91
112
  rendered last. Rerunning the
@@ -119,6 +140,101 @@ production means a tenant-admin key under production custody
119
140
  (`aac tenant rotate-admin-key`), a new root key id published by your
120
141
  publisher, and certificates from your approved issuer.
121
142
 
143
+ ### What a workspace is for, and how to use it
144
+
145
+ A workspace holds everything one workload needs to run beside an AAC
146
+ sidecar, kept apart from every other workload: its identity in your
147
+ tenant's trust domain, its own root signing key and key id, its development
148
+ CA and certificates, the pairing secret its sidecar and agent share, and the
149
+ configuration files rendered for them. It also records how far setup got,
150
+ so rerunning `aac init` resumes where it stopped.
151
+
152
+ Use one workspace per workload. `aac init --workspace <name>` creates a
153
+ workspace (with `--trust-url`) or resumes it (the default name is
154
+ `starter`), and three commands look after it:
155
+
156
+ ```bash
157
+ aac workspace status --workspace starter # what exists, what is due, and the next step
158
+ aac workspace renew --workspace starter # fresh certificates and keys
159
+ aac workspace render --workspace starter --force # rewrite the configuration files
160
+ ```
161
+
162
+ A second workload is a second workspace with its own workload path:
163
+
164
+ ```bash
165
+ aac init --profile stage --workspace worker --workload-path demo/worker \
166
+ --idp github --trust-url https://trust.stage.cascadeauth.dev
167
+ ```
168
+
169
+ Pass the same `--trust-url` and `--idp` as for your first workspace. Each
170
+ workspace records its own, and the trust URL also goes into the tenant's
171
+ `publisher.env`, which every workspace of the tenant shares. A render never
172
+ changes that file's endpoints, so a workspace created with a different
173
+ trust URL stops at its last step and has to be set up again under a new
174
+ name.
175
+
176
+ `--workspace` names the local files; `--workload-path` chooses the
177
+ workload's identity, the path at the end of its SPIFFE ID (`demo/agent`
178
+ unless you choose another). Two workspaces with the same workload path are
179
+ the same workload holding different keys: that is what a replacement
180
+ computer wants, and what a second workload does not. The workspace name is
181
+ permanent, because the root key id is made from it. `aac init` needs the
182
+ profile the workspace was created with; the `aac workspace` commands read it
183
+ from the workspace itself.
184
+
185
+ ### What "render" means
186
+
187
+ To render is to write the configuration files that follow from what the
188
+ workspace records, without touching any key: `sidecar-config.yaml` and
189
+ `compose.env` in the workspace, and `publisher.env` in the tenant
190
+ directory. They hold endpoints, identifiers, settings and the paths of the
191
+ key files, never key material.
192
+
193
+ `aac init` renders them as its last step. Render again with
194
+ `aac workspace render --workspace <name> --force` when a configuration file
195
+ is lost or to change the layout; without `--force`, `render` refuses to
196
+ overwrite files that exist. The layout decides the paths written into the
197
+ sidecar configuration: `host` (the default) uses paths on this machine, for
198
+ a sidecar that runs directly on it, and `container` uses the paths where the
199
+ files are mounted inside the containers. `compose.env` always holds the
200
+ paths on this machine that Docker mounts from, and `publisher.env` the
201
+ paths a publisher running on this machine reads.
202
+
203
+ `publisher.env` belongs to the tenant, and every workspace of the tenant
204
+ renders it. A render rewrites its paths and poll interval for this machine
205
+ (hand edits to those are replaced), but refuses, even with `--force`, to
206
+ change its tenant ID, trust domain or URLs, because that would repoint the
207
+ publisher for every workspace. The refusal names the values that differ.
208
+ If the file is the stale one, for example after you deliberately moved the
209
+ tenant to new endpoints and set up its workspaces again, move it aside
210
+ (`mv publisher.env publisher.env.old` in the tenant directory) and render
211
+ again from a workspace with the intended endpoints. The admin key and the
212
+ published public keys stay where they are.
213
+
214
+ ### How profiles, workspaces and tenant data fit together
215
+
216
+ ```text
217
+ profile (~/.aac/config) ── bound to ──> tenant
218
+ ├── credentials: ~/.aac/credentials/<tenant-id>
219
+ ├── tenant directory: ~/.aac/tenants/<tenant-id>/
220
+ └── workspaces: ~/.aac/workspaces/<name>/, one per workload
221
+ ```
222
+
223
+ * A **profile**, in `~/.aac/config`, names the AAC admin and data-plane
224
+ endpoints you use and, once registration or sign-in has bound it, the one
225
+ tenant it acts for. The trust URL and the sign-in choice are recorded in
226
+ each workspace instead. "Profiles and configuration", further down,
227
+ covers profiles in full.
228
+ * The **tenant data** is shared by all of a tenant's workspaces on this
229
+ machine: the tenant API key and the tenant-admin session in
230
+ `~/.aac/credentials/`, and the tenant directory
231
+ `~/.aac/tenants/<tenant-id>/` with the tenant-admin signing key, the public
232
+ keys and certificates the publisher uploads, and `publisher.env`.
233
+ * A **workspace**, in `~/.aac/workspaces/<name>/`, holds one workload's
234
+ material. It records the profile and the tenant it was created for and
235
+ keeps them: one tenant can have many workspaces, and a workspace never
236
+ moves to another tenant.
237
+
122
238
  ### What each file is for, and what to back up
123
239
 
124
240
  The table lists every file the CLI creates, what it is for, how long it
@@ -126,21 +242,21 @@ lives and whether to back it up. `<workspace>` is the workspace name
126
242
  (default `starter`) and `<tenant-id>` the tenant id AAC allocated.
127
243
 
128
244
  <!-- inventory-table:start -->
129
- | Material | Where | Used for | Lifetime | Back up? |
130
- |---|---|---|---|---|
131
- | tenant_api_key | `~/.aac/credentials/<tenant-id>` | CLI data-plane calls; the sidecar's workload projection | until retired or rotated; `aac tenant reissue-api-key` | **Yes.** save a protected copy in your secret manager; loss needs `aac tenant reissue-api-key` |
132
- | tenant_admin_session | `~/.aac/credentials/<tenant-id>.session` | CLI admin calls | hours; `aac sso login` | No. sign in again |
133
- | tenant_admin_signing_key | `~/.aac/tenants/<tenant-id>/tenant-admin.pem`, `~/.aac/tenants/<tenant-id>/tenant-admin.pub.pem` | the publisher signs trust-material uploads; the public half is registered with AAC | until rotated; `aac tenant rotate-admin-key` | **Recommended.** recommended for developer tenants (loss needs `aac tenant rotate-admin-key`); production custody belongs in an HSM/KMS, not a password manager |
134
- | root_signing_key | `~/.aac/workspaces/<workspace>/pki/root.pem`, `~/.aac/workspaces/<workspace>/pki/root.pub.pem`, `~/.aac/tenants/<tenant-id>/root-keys/<workspace>-root-v1.pub.pem` | the sidecar mints authority chains; the public half is published under the key id | until you retire its key id (root key ids are fixed per workspace name) | No. never restore: a replacement workspace gets a new name and therefore a new key id, published alongside the old one until the old one is retired |
135
- | development_ca | `~/.aac/workspaces/<workspace>/ca/dev-ca.key`, `~/.aac/workspaces/<workspace>/pki/dev-ca.crt`, `~/.aac/workspaces/<workspace>/pair/dev-ca.crt`, `~/.aac/tenants/<tenant-id>/spiffe-bundle/<workspace>-dev-ca.ca.pem` | signs the workload, terminal and TLS certificates; peers trust it via the published bundle | 7 days; `aac workspace renew --ca` | No. development only; reissue |
136
- | workload_svid | `~/.aac/workspaces/<workspace>/pki/workload.key`, `~/.aac/workspaces/<workspace>/pki/workload.crt` | the sidecar's SPIFFE identity: proves on every live request that this workload holds the key behind its certificate | 1 day; `aac workspace renew` | No. development only; reissue |
137
- | terminal_attestation | `~/.aac/workspaces/<workspace>/pki/terminal.key`, `~/.aac/workspaces/<workspace>/pki/terminal.crt` | signs the receipt (terminal attestation) the sidecar issues when this workload completes a delegated request; auditors verify it offline against your published CA; kept separate from the workload key so neither can forge the other's role | 1 day; `aac workspace renew` | No. development only; reissue |
138
- | localhost_tls | `~/.aac/workspaces/<workspace>/pki/server.key`, `~/.aac/workspaces/<workspace>/pki/server.crt` | the sidecar's HTTPS listener | 1 day; `aac workspace renew` | No. development only; reissue |
139
- | outbound_ca_bundle | `~/.aac/workspaces/<workspace>/pki/outbound-ca.pem` | the sidecar verifies TLS to AAC and to itself | rebuilt by renew; `aac workspace renew` | No. derived |
140
- | pairing_secret | `~/.aac/workspaces/<workspace>/pair/pairing.secret` | the sidecar and its agent authenticate each other (same bytes in both) | until regenerated | No. regenerable; both processes must read the same file |
141
- | workspace_manifest | `~/.aac/workspaces/<workspace>/manifest.json` | the workspace's identities and progress; every `workspace` verb reads it first | for the life of the workspace | **Recommended.** cannot be recreated by any command; without it start a new workspace under a new name (see the new-computer setup procedure) |
142
- | published_public_inputs | `~/.aac/tenants/<tenant-id>/root-keys`, `~/.aac/tenants/<tenant-id>/spiffe-bundle` | the publisher's input directories: every root public key and CA certificate this tenant has published, across all workspaces | for the life of the tenant | **Recommended.** back up with the tenant directory: a replacement workspace must publish its new root key alongside a still-ACTIVE previous one (the control plane refuses a root-key set that drops every ACTIVE key at once) |
143
- | rendered_files | `~/.aac/workspaces/<workspace>/sidecar-config.yaml`, `~/.aac/workspaces/<workspace>/compose.env`, `~/.aac/tenants/<tenant-id>/publisher.env` | non-secret configuration derived from the manifest | re-rendered on demand; `aac workspace render --force` | No. derived; `aac workspace render --force` recreates them |
245
+ | No. | Material | Where | Used for | Lifetime | Back up? |
246
+ |---|---|---|---|---|---|
247
+ | 1 | tenant_api_key | `~/.aac/credentials/<tenant-id>` | CLI data-plane calls; the sidecar's workload projection | until retired or rotated; `aac tenant reissue-api-key` | **Yes.** save a protected copy in your secret manager; loss needs `aac tenant reissue-api-key` |
248
+ | 2 | tenant_admin_session | `~/.aac/credentials/<tenant-id>.session` | CLI admin calls | hours; `aac sso login` | No. sign in again |
249
+ | 3 | tenant_admin_signing_key | `~/.aac/tenants/<tenant-id>/tenant-admin.pem`, `~/.aac/tenants/<tenant-id>/tenant-admin.pub.pem` | the publisher signs trust-material uploads; the public half is registered with AAC | until rotated; `aac tenant rotate-admin-key` | **Recommended.** recommended for developer tenants (loss needs `aac tenant rotate-admin-key`; a lost public half is derived from the private key); production custody belongs in an HSM/KMS, not a password manager |
250
+ | 4 | root_signing_key | `~/.aac/workspaces/<workspace>/pki/root.pem`, `~/.aac/workspaces/<workspace>/pki/root.pub.pem`, `~/.aac/tenants/<tenant-id>/root-keys/<workspace>-root-v1.pub.pem` | the sidecar mints authority chains; the public half is published under the key id | until you retire its key id (root key ids are fixed per workspace name) | No. never restore the private key: a replacement workspace gets a new name and therefore a new key id, published alongside the old one until the old one is retired; its public copies are recreated from it |
251
+ | 5 | development_ca | `~/.aac/workspaces/<workspace>/ca/dev-ca.key`, `~/.aac/workspaces/<workspace>/pki/dev-ca.crt`, `~/.aac/workspaces/<workspace>/pair/dev-ca.crt`, `~/.aac/tenants/<tenant-id>/spiffe-bundle/<workspace>-dev-ca.ca.pem` | signs the workload, terminal and TLS certificates; peers trust it via the published bundle | 7 days; `aac workspace renew --ca` | No. development only; reissue; a lost copy of the certificate is copied back from `pki/dev-ca.crt` |
252
+ | 6 | workload_svid | `~/.aac/workspaces/<workspace>/pki/workload.key`, `~/.aac/workspaces/<workspace>/pki/workload.crt` | the sidecar's SPIFFE identity: proves on every live request that this workload holds the key behind its certificate | 1 day; `aac workspace renew` | No. development only; reissue |
253
+ | 7 | terminal_attestation | `~/.aac/workspaces/<workspace>/pki/terminal.key`, `~/.aac/workspaces/<workspace>/pki/terminal.crt` | signs the receipt (terminal attestation) the sidecar issues when this workload completes a delegated request; auditors verify it offline against your published CA; kept separate from the workload key so neither can forge the other's role | 1 day; `aac workspace renew` | No. development only; reissue |
254
+ | 8 | localhost_tls | `~/.aac/workspaces/<workspace>/pki/server.key`, `~/.aac/workspaces/<workspace>/pki/server.crt` | the sidecar's HTTPS listener | 1 day; `aac workspace renew` | No. development only; reissue |
255
+ | 9 | outbound_ca_bundle | `~/.aac/workspaces/<workspace>/pki/outbound-ca.pem` | the sidecar verifies TLS to AAC and to itself | rebuilt by renew; `aac workspace renew` | No. derived |
256
+ | 10 | pairing_secret | `~/.aac/workspaces/<workspace>/pair/pairing.secret` | the sidecar and its agent authenticate each other (same bytes in both) | until regenerated | No. regenerable; both processes must read the same file |
257
+ | 11 | workspace_manifest | `~/.aac/workspaces/<workspace>/manifest.json` | the workspace's identities and progress; every `workspace` verb reads it first | for the life of the workspace | **Recommended.** cannot be recreated by any command; without it start a new workspace under a new name (see the new-computer setup procedure) |
258
+ | 12 | published_public_inputs | `~/.aac/tenants/<tenant-id>/root-keys`, `~/.aac/tenants/<tenant-id>/spiffe-bundle` | the publisher's input directories: every root public key and CA certificate this tenant has published, across all workspaces | for the life of the tenant | **Recommended.** back up with the tenant directory: a replacement workspace must publish its new root key alongside a still-ACTIVE previous one (the control plane refuses a root-key set that drops every ACTIVE key at once) |
259
+ | 13 | rendered_files | `~/.aac/workspaces/<workspace>/sidecar-config.yaml`, `~/.aac/workspaces/<workspace>/compose.env`, `~/.aac/tenants/<tenant-id>/publisher.env` | non-secret configuration derived from the manifest | re-rendered on demand; `aac workspace render --force` | No. derived; `aac workspace render --force` recreates them |
144
260
  <!-- inventory-table:end -->
145
261
 
146
262
  In short: back up the tenant API key and the whole tenant directory while
@@ -163,6 +279,17 @@ published under the next anchor id and needs the publisher restarted.
163
279
  `render` never touches keys and refuses to overwrite rendered files unless
164
280
  `--force` is given.
165
281
 
282
+ `status` also names one next step, `next_command`. When material is
283
+ missing, it is the fix for the first missing item: restore it from your
284
+ backup, recreate a lost public copy from the file it copies, renew, or
285
+ render. Otherwise it is renewal when a certificate is due. After the step,
286
+ run `status` again. Commands it names that change your tenant carry the
287
+ workspace's own `--tenant-id` and `--admin-url`, so a value left in
288
+ `AAC_TENANT_ID` or `AAC_ADMIN_URL` cannot aim them at another tenant. The
289
+ file recipes use `openssl`, which must be OpenSSL 1.1.1 or newer: the
290
+ `openssl` that ships with macOS cannot read Ed25519 keys, so install a
291
+ current OpenSSL there, for example with Homebrew.
292
+
166
293
  Every private file is created once, readable only by you, and never
167
294
  overwritten. Before generating anything, `init` checks every destination
168
295
  and refuses with the full list if one already exists. `aac init` never
@@ -173,6 +300,36 @@ side effect of setup. A second workspace for the same tenant
173
300
  (`--workspace other`) reuses the tenant-admin key and gets its own root key
174
301
  id.
175
302
 
303
+ ### What to do when keys and certificates expire
304
+
305
+ It is the certificates that expire, and renewing replaces their keys with
306
+ them. `aac workspace status` shows when each certificate runs out and flags
307
+ it before it does: six hours ahead for the one-day certificates, a day
308
+ ahead for the development CA.
309
+
310
+ | Material | Lasts | When it runs out | What to do |
311
+ |---|---|---|---|
312
+ | Workload, terminal-attestation and localhost TLS certificates | 1 day | the sidecar can no longer prove its identity, sign receipts or serve HTTPS | `aac workspace renew --workspace <name>`, then restart the sidecar so it loads them |
313
+ | Development CA | 7 days | certificates it signed stop being trusted, and no new ones can be issued | `renew` also replaces the CA when it is expired or within a day of expiry, or when `--ca` is given, and then reissues every certificate under it: restart the publisher so the new CA is published, restart the sidecar and anything else that trusted the old CA, and confirm with `aac workspace status --workspace <name> --remote` |
314
+ | Tenant-admin session | hours | administration commands ask you to sign in again | `aac sso login` |
315
+ | Tenant API key, tenant-admin signing key, root signing key | do not expire | — | replaced only on purpose: see "Keys" and "Setting up aac-cli on a new computer" |
316
+
317
+ A simple routine: when you start work, run
318
+ `aac workspace status --workspace <name>`, and when it names renewal, run
319
+ `aac workspace renew --workspace <name>` and restart the sidecar. About once
320
+ a week that renewal also replaces the development CA (`renew` then reports
321
+ `republication_required: true`): restart the publisher, the sidecar and the
322
+ agent, and anything else that trusted the old CA. Renewing is safe to
323
+ repeat, but it is not a no-op: every run issues fresh keys and moves the old
324
+ files to the workspace's `archive/` directory, so whatever reads them must
325
+ reload. With the
326
+ [AAC Compose starter](https://github.com/CascadeAuth/aac-compose-starter),
327
+ `./starter up` recreates the containers so they load the new files; it
328
+ does not renew anything itself.
329
+
330
+ All of this is development material. In production, certificates come from
331
+ your own issuer and follow its renewal process.
332
+
176
333
  ## Setting up aac-cli on a new computer
177
334
 
178
335
  This procedure covers a lost machine and a second machine alike. It needs
@@ -211,7 +368,8 @@ profile; `aac profile show` prints it, and the example below uses
211
368
  ```
212
369
 
213
370
  Restore `~/.aac/tenants/<tenant-id>/` from the backup, with directories
214
- readable only by you and files likewise.
371
+ readable only by you and files likewise. Its `publisher.env` still names
372
+ the old machine's paths; step 3 rewrites them for this one.
215
373
 
216
374
  If the tenant directory was not backed up, first check whether another
217
375
  machine still holds `~/.aac/tenants/<tenant-id>/`: every machine that has
@@ -220,7 +378,8 @@ profile; `aac profile show` prints it, and the example below uses
220
378
 
221
379
  If no copy exists anywhere, the tenant-admin key and every root key that
222
380
  lived on the lost machine are gone for good. Install a new admin key,
223
- then account for every root key the tenant has published:
381
+ then account for every root key the tenant has published (the `openssl`
382
+ commands need OpenSSL 1.1.1 or newer, which macOS does not ship):
224
383
 
225
384
  ```bash
226
385
  openssl genpkey -algorithm ed25519 -out tenant-admin.pem
@@ -359,13 +518,17 @@ aac sso whoami --profile stage --output table # cached session and th
359
518
  aac sso logout --profile stage
360
519
  ```
361
520
 
521
+ A developer tenant signs in with `--idp github` or `--idp google`; if you
522
+ need another sign-in provider, contact support@cascadeauth.com. An
523
+ enterprise tenant signs in through its Microsoft Entra ID connection, named
524
+ by the connection's exact URL with `--idp-url`; when several connections
525
+ are registered, the error message lists the exact commands to choose one.
526
+
362
527
  Sign-in uses the device flow by default, so the browser can be on another
363
528
  machine and headless hosts work. Google connections use a loopback flow
364
529
  instead, because Google's device flow is scope-restricted; `--flow`
365
- overrides the choice. An enterprise tenant names its identity-provider
366
- connection by the connection's exact URL with `--idp-url`; when several
367
- connections are registered, the error message lists the exact commands to
368
- choose one. `whoami` and `logout` work offline and never contact AAC.
530
+ overrides the choice. `whoami` and `logout` work offline and never contact
531
+ AAC.
369
532
 
370
533
  ## Output and exit codes
371
534
 
@@ -396,6 +559,10 @@ the `AAC_BOOTSTRAP_TOKEN` environment variable. The token authorises only
396
559
  the onboarding steps shown with it; every other administration command runs
397
560
  under a signed-in session.
398
561
 
562
+ For enterprise sign-in, AAC supports Microsoft Entra ID (also known as
563
+ Azure Active Directory or Azure AD). If your organisation needs another
564
+ identity provider, contact support@cascadeauth.com.
565
+
399
566
  ### Register the tenant
400
567
 
401
568
  Generate the tenant-admin key pair first. The CLI transmits the public half
@@ -429,7 +596,8 @@ aac tenant update --profile prod --tenant-id tnt-550e8400-e29b-41d4-9716-4466554
429
596
  ### Connect your identity provider
430
597
 
431
598
  An identity-provider connection is described by a JSON file
432
- (`aac sso register-idp --help` shows the fields). Before the first
599
+ (`aac sso register-idp --help` shows the fields, with an example for a
600
+ Microsoft Entra ID tenant). Before the first
433
601
  connection, generate an offline recovery key so the connection can be
434
602
  repaired if the provider is ever unavailable; only the enrollment file
435
603
  leaves the machine:
@@ -468,6 +636,27 @@ aac tenant rotate-admin-key --profile prod \
468
636
  --tenant-admin-pubkey-file tenant-admin.public.pem
469
637
  ```
470
638
 
639
+ A developer tenant set up with `aac init` keeps its tenant-admin key in its
640
+ tenant directory, where the publisher's configuration points. To replace a
641
+ lost key there, write the new pair in place, readable only by you, sign in,
642
+ register the new public half, and then recreate every publisher container.
643
+ Pass the tenant id and admin URL explicitly, as `aac workspace status`
644
+ does, so the change cannot land on another tenant. The `openssl` commands
645
+ need OpenSSL 1.1.1 or newer, which macOS does not ship:
646
+
647
+ ```bash
648
+ cd ~/.aac/tenants/tnt-550e8400-e29b-41d4-9716-446655440000
649
+ (umask 077 && openssl genpkey -algorithm ed25519 -out tenant-admin.pem.tmp && mv tenant-admin.pem.tmp tenant-admin.pem)
650
+ (umask 077 && openssl pkey -in tenant-admin.pem -pubout -out tenant-admin.pub.pem.tmp && mv tenant-admin.pub.pem.tmp tenant-admin.pub.pem)
651
+ aac sso login --profile stage --idp github \
652
+ --tenant-id tnt-550e8400-e29b-41d4-9716-446655440000 \
653
+ --admin-url https://api.stage.cascadeauth.dev
654
+ aac tenant rotate-admin-key --profile stage \
655
+ --tenant-id tnt-550e8400-e29b-41d4-9716-446655440000 \
656
+ --admin-url https://api.stage.cascadeauth.dev \
657
+ --tenant-admin-pubkey-file tenant-admin.pub.pem
658
+ ```
659
+
471
660
  The tenant API key can be rotated without downtime. `issue` stages a second
472
661
  active key in a new file and never replaces the current one; move every
473
662
  client to it, then retire the old key by its exact id: