This commit is contained in:
2026-07-25 14:51:48 -05:00
parent 1ea21c065e
commit 69cc236635
18 changed files with 770 additions and 106 deletions
+18 -1
View File
@@ -11,7 +11,9 @@ credentials.
{
"code": "TAPM-ABCDE-FGHIJ",
"host_fingerprint": "sha256-of-the-host-machine-id",
"hostname": "pve01"
"hostname": "pve01",
"requested_action": "install-rmm",
"requested_package": ""
}
```
@@ -29,6 +31,11 @@ Successful response:
"sha256": "64-lowercase-hexadecimal-characters",
"download_url": "https://tapm.scity.us/api/v1/packages/sentinelone-linux"
}
],
"actions": [
"install-rmm",
"install-acronis",
"install-screenconnect"
]
}
```
@@ -36,6 +43,16 @@ Successful response:
The first exchange enrolls that host against the authorization. Reusing the
same code and host fingerprint does not consume another host slot. A different
fingerprint consumes one slot until the configured limit is reached.
When `requested_action` or `requested_package` is present, the broker validates
that entitlement before enrolling the host. Older clients may omit both fields,
but current clients should always identify what they intend to use.
An installer must proceed only when its required package slug or action slug is
present in this response. The current action slugs are:
- `install-rmm`
- `install-acronis`
- `install-screenconnect`
## Download a package
+42 -39
View File
@@ -1,16 +1,22 @@
# Deployment
This service is intended to run on both webserver VMs, with only the active
webserver's broker container started. Both installations use the same MariaDB
Galera database, Gitea application, package registry, and secrets. The
containers use Linux host networking so `127.0.0.1:3306` reaches each
webserver's local HAProxy listener.
This service runs active-active on both webserver VMs. Both installations use
the same MariaDB Galera database, Gitea application, package registry, and
secrets. The containers use Linux host networking so `127.0.0.1:3306` reaches
each webserver's local HAProxy listener.
## 1. DNS and TLS
Create `tapm.scity.us` in PowerDNS and point it at the existing HAProxy
frontend. Install the certificate using the existing certificate automation.
The broker only listens on `127.0.0.1:8080`; Nginx terminates TLS.
Set `TAPM_LISTEN_ADDR` to each node's physical address when the load balancer
connects directly to port 8080:
- Webserver-Node1: `10.10.1.121:8080`
- Webserver-Node2: `10.10.1.122:8080`
Restrict port 8080 to the load-balancer addresses. If Nginx terminates TLS on
each webserver instead, keep the broker on `127.0.0.1:8080`.
An example virtual host is in
[`deploy/nginx/tapm.scity.us.conf`](../deploy/nginx/tapm.scity.us.conf).
@@ -48,14 +54,16 @@ Create these separately:
2. A `tapm-packages` service account with read access only to the private
`TAI/files` package owner. Create a personal access token for this account
and store it only in the broker environment file.
3. An OAuth2 application with callback URL
3. A `tapm-publisher` service account with `write:package` access. Its token is
used only by authenticated portal uploads.
4. An OAuth2 application with callback URL
`https://tapm.scity.us/auth/callback`.
The OAuth client secret authenticates the portal to Gitea. The package token
is used only server-side while proxying an authorized file. Neither value is
returned to a technician or Proxmox host. The broker requests only Gitea's
`read:user` OAuth scope, which it uses to confirm the signed-in username
against `TAPM_ALLOWED_GITEA_USERS`.
The OAuth client secret authenticates the portal to Gitea. The read token is
used only while proxying an authorized file, and the write token is used only
for authenticated uploads. None are returned to a technician or Proxmox host.
The broker requests only Gitea's `read:user` OAuth scope, which it uses to
confirm the signed-in username against `TAPM_ALLOWED_GITEA_USERS`.
## 4. Broker configuration
@@ -68,8 +76,8 @@ cp .env.example .env
chmod 600 .env
```
Edit `.env` and use the same values on both webservers. Generate the cookie
secret with:
Edit `.env` and use the same secrets on both webservers. The listen address is
the one node-specific value. Generate the cookie secret with:
```sh
openssl rand -base64 48
@@ -97,29 +105,16 @@ docker compose run --rm migrate
Migrations use a MariaDB advisory lock, so an accidental simultaneous run
cannot apply the same migration twice.
## 6. Start the active instance
## 6. Start both instances
On the active webserver:
On both webservers:
```sh
docker compose up -d broker
curl --fail http://127.0.0.1:8080/health/ready
curl --fail "http://${TAPM_LISTEN_ADDR}/health/ready"
```
On the standby webserver, keep the image and `.env` current but leave the
broker stopped. The existing failover automation can run:
```sh
docker compose stop broker
```
on the old active VM, followed by:
```sh
docker compose up -d broker
```
on the new active VM. There is no local application state to transfer.
There is no local application state and no session affinity requirement.
## 7. HAProxy health check
@@ -127,13 +122,21 @@ The load balancer should consider an origin healthy only when
`GET /health/ready` returns HTTP 200. `/health/live` checks only the process;
`/health/ready` also verifies Galera connectivity.
Only the active webserver should be eligible for traffic. Retaining a single
active origin avoids duplicate service management while Galera preserves
sessions and authorization state across failover.
Both healthy webservers can receive traffic. `leastconn` is useful because
package uploads and downloads stay open longer than portal requests.
## 8. Publish a protected package
Publish files to the private Gitea Generic Package Registry:
The normal workflow is **Protected packages → Upload a new version** in the
portal. The broker streams the file directly to Gitea, calculates SHA-256,
updates the catalog, and writes an audit event without buffering the installer
on local disk.
The load balancer or Nginx must allow request bodies up to
`TAPM_MAX_UPLOAD_BYTES` and use a sufficiently long request timeout. The
default is 1 GiB and 30 minutes.
For recovery, a package can still be published directly:
```sh
curl --user 'publisher:PACKAGE_WRITE_TOKEN' \
@@ -147,15 +150,15 @@ Calculate its checksum:
sha256sum SentinelAgent_linux_x86_64_v26_1_1_31.deb
```
Sign in at `https://tapm.scity.us`, enter the matching registry package name,
version, filename, and SHA-256, then enable it. The broker intentionally does
not browse the registry with the technician's credentials.
Sign in at `https://tapm.scity.us`, expand **Register package metadata
manually**, enter the matching values, and enable it. The broker never uses the
technician's Gitea credentials for package operations.
## 9. Backup and rotation
- Include `tapm_broker` in the existing Galera backup policy.
- Keep `.env` outside Git and readable only by the service administrator.
- Rotate the Gitea package token and OAuth secret if either webserver is
- Rotate both Gitea package tokens and the OAuth secret if either webserver is
compromised.
- Changing `TAPM_COOKIE_SECRET` signs out portal users; it does not invalidate
active deployment codes.