Installation automation - License key approach

This commit is contained in:
2026-07-26 17:02:16 +05:30
parent d6dc33d9b1
commit 60f5450f47
385 changed files with 4557 additions and 2228 deletions

View File

@@ -0,0 +1,56 @@
# Client registration and installation domain
## Ownership
```text
client_registration_details
└── client_account (tenant)
├── client_license
│ └── license_activation_key
└── client_installation
```
- A registration is the legal contracting and billing entity.
- A registration may own multiple isolated tenants.
- A tenant belongs to exactly one registration.
- A tenant may have license history; installation uses a specific license.
- `client_license.max_installations` defaults to one and is cloud-enforced.
- A license key authorizes activation but is never a runtime credential.
- Every installation has a unique UUID and signing key pair.
- The installation private key never leaves the customer server.
## Installation capacity
`PENDING`, `ACTIVE`, and `SUSPENDED` installations consume capacity.
`DECOMMISSIONED`, `REVOKED`, and `FAILED` installations do not.
Registration must lock the applicable active license row, count consuming
installations, and insert the new `PENDING` installation in one transaction.
This prevents two concurrent requests from taking the same final slot.
## Status transitions
```text
PENDING -> ACTIVE -> SUSPENDED -> ACTIVE
|
+-> DECOMMISSIONED
+-> REVOKED
PENDING -> FAILED
```
- Suspension is temporary and continues consuming capacity.
- Decommission permanently retires a legitimate old server.
- Revocation permanently invalidates a compromised or prohibited server.
- Decommission and revocation require an actor, timestamp, and reason.
- Historical installation rows are retained for audit.
## Activation credentials
The customer receives a client code and a random license activation key.
The database stores only a strong key hash and a non-secret display hint.
After validation, the cloud issues a single-use activation session with a
short expiry and binds it to the intended installation UUID.
Client codes, tenant IDs, installation IDs, and key hints are identifiers,
not authentication secrets.

View File

@@ -0,0 +1,85 @@
# 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.
5. The Java wizard blocks unless Docker, Docker Engine, and Compose v2 work.
6. The wizard 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
001003. 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`
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 wizard
```bash
mvn -pl cygnus-installer -am package
CYGNUS_CLOUD_URL=https://cloud.example.com \
java -jar cygnus-installer/target/cygnus-installer-1.0.0-SNAPSHOT.jar
```
After a successful run, review the generated `compose.yml`, set
`CYGNUS_IMAGE`, and start with `docker compose up -d`.
The wizard asks for the output directory. Press Enter to accept
`CYGNUS_INSTALL_OUTPUT`, which defaults to `./cygnus-installation`. It creates:
- `compose.yml`
- `config/installation.yml`
- `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 cloud stores only its public key.
## 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.