113 lines
4.8 KiB
Markdown
113 lines
4.8 KiB
Markdown
# Client registration and controlled installation runbook
|
||
|
||
## Lifecycle
|
||
|
||
1. An administrator creates one legal registration.
|
||
2. One or more tenant accounts are attached to that registration.
|
||
3. A time-bound license defines package, user, and installation limits.
|
||
4. An activation key is generated, stored only as a BCrypt hash, and emailed.
|
||
The recipient is always the primary contact email stored on the client
|
||
registration; API callers cannot redirect the key to another address.
|
||
5. The Technobee Service Installer blocks unless Docker, Docker Engine, and
|
||
Compose v2 work.
|
||
6. The installer validates the key, generates an RSA-3072 installation key, and
|
||
registers the installation in one database transaction.
|
||
7. The plaintext activation key is neither returned again nor written locally.
|
||
8. Runtime token issuance requires an active registration, tenant, license, and
|
||
installation.
|
||
9. An administrator can decommission or revoke an old installation before
|
||
activating its replacement.
|
||
|
||
## Database migration
|
||
|
||
Apply `004_client_registration_activation.sql` after identity migrations
|
||
001–003. The migration is additive and idempotent. Always back up production
|
||
before applying it and validate the constraints on a staging copy first.
|
||
|
||
## Required cloud configuration
|
||
|
||
- Database and Redis variables already used by the cloud service
|
||
- JWT and assertion encryption key locations
|
||
- `CYGNUS_MAIL_HOST`, `CYGNUS_MAIL_PORT`, `CYGNUS_MAIL_USERNAME`,
|
||
`CYGNUS_MAIL_PASSWORD`, and `CYGNUS_REGISTRATION_EMAIL_FROM`
|
||
- Optional `CYGNUS_ACTIVATION_MAX_ATTEMPTS` and
|
||
`CYGNUS_ACTIVATION_RATE_WINDOW`
|
||
|
||
The cloud service can start without SMTP, but the activation-key email endpoint
|
||
will reject delivery until SMTP is configured.
|
||
|
||
## Administrative API order
|
||
|
||
All administration endpoints require an access token with
|
||
`cygnus.admin` scope.
|
||
|
||
1. `POST /api/v1/admin/client-registrations`
|
||
2. `POST /api/v1/admin/client-registrations/{registrationId}/tenants`
|
||
3. `POST /api/v1/admin/tenants/{tenantId}/licenses`
|
||
4. `POST /api/v1/admin/tenants/{tenantId}/licenses/{licenseId}/activation-key`
|
||
|
||
The activation-key request contains only `expiresAt`. The cloud service reads
|
||
the delivery address from `client_registration_details.primary_contact_email`.
|
||
|
||
For replacements:
|
||
|
||
- `POST /api/v1/admin/tenants/{tenantId}/installations/{id}/decommission`
|
||
- `POST /api/v1/admin/tenants/{tenantId}/installations/{id}/revoke`
|
||
|
||
Both require a non-empty reason, invalidate the cached installation, increment
|
||
its security version, and write an audit event.
|
||
|
||
## Running the Technobee Service Installer
|
||
|
||
```bash
|
||
mvn -pl cygnus-installer -am package
|
||
TECHNOBEE_INSTALLER_CONFIG=cygnus-installer/config/cygnus-installer.ini \
|
||
java -jar cygnus-installer/target/technobee-service-installer-1.0.0-SNAPSHOT.jar
|
||
```
|
||
|
||
This opens the Swing installation wizard. Add `--cli` when running on a
|
||
headless server or when the terminal workflow is preferred.
|
||
|
||
Select Matrix or Cygnus using the INI `product` property. The INI also supplies
|
||
the cloud URL, installation API base path, environment, output directory, and
|
||
the product profile. No cloud URL, route, service name, or filesystem path is
|
||
compiled into the installer workflow.
|
||
|
||
The installer asks for the Matrix or Cygnus Docker image and writes it to
|
||
`.env` using the selected profile's image variable. After a successful run,
|
||
review `compose.yml` and `.env`, then start with `docker compose up -d`.
|
||
It also asks for the registry host, username, and password and performs
|
||
`docker login --password-stdin`. The password is not stored in the generated
|
||
installation package.
|
||
|
||
The installer asks for the output directory. Press Enter to accept the INI
|
||
`output_directory`. It creates:
|
||
|
||
- `compose.yml`
|
||
- `.env`
|
||
- `config/installation.yml`
|
||
- `config/machine-assertion.jwt`
|
||
- `config/keys/client-signing-private.pem`
|
||
- `config/keys/client-signing-public.pem`
|
||
|
||
The generated private key must remain readable only by the service account.
|
||
Never email or copy it to the cloud. The encrypted machine assertion and
|
||
private key remain on premises; the cloud receives and stores only the public
|
||
key. The generated service configuration records the returned client ID,
|
||
installation ID/code, cloud URL, assertion path, and key paths.
|
||
|
||
The installer does not connect directly to PostgreSQL or Redis. Registration,
|
||
license enforcement, and installation identity remain the selected cloud
|
||
service's responsibility.
|
||
|
||
## Operational checks
|
||
|
||
- Alert on repeated HTTP 429 activation responses.
|
||
- Alert on failed SMTP delivery and keep activation-key issue events auditable.
|
||
- Review installations that have stale `last_seen_at`.
|
||
- Revoke suspected keys/installations immediately.
|
||
- Do not increase `max_installations` to recover a failed server. Decommission
|
||
the old installation with a reason, then activate the replacement.
|
||
- Back up registration, tenant, license, installation, activation-key, session,
|
||
and installation-audit tables together.
|