Skip to main content
View Markdown ↗

Copy this page

Select and copy the Markdown below, then paste it into your LLM.

On this page

Install the management portal offline

The portal is on main. There is no packaged installer and no systemd unit in the repository yet; the unit below is an example.

The portal is one static Go binary, portal, with no third-party modules in the production build. It runs on one Linux VM inside the enclave, makes no outbound connections, and needs no container runtime, database or package registry. Workstations pull from it; it never connects to them.

What you need

  • A Linux VM with systemd 250 or later (for encrypted credentials), ideally with a TPM.
  • A server certificate and key for the portal's name, issued by the enclave CA.
  • The enclave CA certificate that issues your administrators' smart-card certificates.
  • A Go toolchain on the build machine. The VM itself needs none.

Build

cd testifysec/portal
CGO_ENABLED=0 go build -trimpath -o portal .
go test ./...

Copy portal to the VM, for example to /usr/local/bin/portal.

Create the service user and data directory

The portal refuses to create its data directory; the installer does, so its existence is durable before the first profile version is written.

useradd --system --no-create-home --shell /usr/sbin/nologin badger-portal
install -d -m 0700 -o badger-portal -g badger-portal /var/lib/badger-portal

Seal the signing key

The signing key is never plaintext on disk. Generate it and seal it as a systemd encrypted credential bound to the TPM:

portal -generate-key | systemd-creds encrypt --with-key=tpm2 --name=portal-signing-key - /etc/credstore.encrypted/portal-signing-key

Use --with-key=host+tpm2, or --with-key=host on a VM with no TPM. A host-key-only seal is as safe as the host key file. systemd decrypts the credential at start into memory only the service can read; the portal loads it from $CREDENTIALS_DIRECTORY and refuses to start without it. There is no API to export the key. Back it up, if at all, under your key-custody procedure.

Seal the TLS server key the same way, so it is not plaintext on disk either, then remove the plaintext copy:

systemd-creds encrypt --with-key=tpm2 --name=server-key server.key /etc/credstore.encrypted/server-key
shred -u server.key

systemd exposes it to the service at /run/credentials/badger-portal.service/server-key, which the configuration below names. The unit must be called badger-portal.service for that path.

Write the configuration

{
  "listen": ":8443",
  "tlsCert": "/etc/badger-portal/server.crt",
  "tlsKey": "/run/credentials/badger-portal.service/server-key",
  "clientCa": "/etc/badger-portal/enclave-ca.pem",
  "dataDir": "/var/lib/badger-portal",
  "signingKeyCredential": "portal-signing-key",
  "tenantId": "tenant-example",
  "minimumSequence": 1,
  "bootstrap": {
    "CN=ADMIN.ALICE,OU=Example,O=Example": "admin",
    "CN=APPROVER.BOB,OU=Example,O=Example": "approver"
  }
}

Unknown keys are refused. minimumSequence should be at least the minimum sequence your admission build trusts.

bootstrap names at most one certificate subject for admin and one for approver, written in RFC 2253 order (most specific first, as above). It lets those two people act only until a user in the portal's directory first holds that role; after that the bootstrap entry stops working for good, even if every holder is later offboarded. It is how the first administrator and approver grant real roles, not a place to list users.

Run it as a service

An example unit, saved as /etc/systemd/system/badger-portal.service:

[Unit]
Description=Badger management portal
After=network-online.target

[Service]
User=badger-portal
ExecStart=/usr/local/bin/portal -config /etc/badger-portal/config.json
LoadCredentialEncrypted=portal-signing-key
LoadCredentialEncrypted=server-key
NoNewPrivileges=yes
ProtectSystem=strict
ReadWritePaths=/var/lib/badger-portal

[Install]
WantedBy=multi-user.target

The portal serves HTTPS only, with TLS 1.2 or later, and verifies every client certificate against clientCa. There is no plaintext port. GET /healthz is the only route that answers without a client certificate:

curl --cacert /etc/badger-portal/enclave-ca.pem https://portal.example.invalid:8443/healthz

The portal takes an exclusive lock on its audit log, so a second process on the same data directory refuses to start.

Add the first users

Roles come from the portal's user directory. The portal stores no passwords: a user is an identity the enclave PKI already issued, identified by the verified certificate subject.

  1. The bootstrap administrator provisions each person (POST /api/v1/users). A new user is pending, with no role.
  2. The administrator requests a role for the user (admin, approver or auditor).
  3. An approver who is neither the requester nor the user approves or rejects it in the approver queue. Only active users with a role can act.
  4. The administrator adds users to the deployments they work on.

Dropping a role takes effect at once. Offboarding is final: it clears the user's role, deployment memberships and pending requests in one step. Every change is one record in the audit log. A person's clearance is not the portal's to decide; see shared responsibility. The calls are listed in the portal API reference.

Back up and restore

Stop the service or snapshot the VM, then copy the data directory. Every file in it is written once or appended to, so a copy taken between writes is consistent. Restoring an older backup and signing again would reuse sequence numbers; check that each profile's highest stored sequence is at least what workstations last saw before you sign anything. A portal verify-audit command and a refusal to start on an older audit head are planned and not built.

Next

Author, approve and publish a profile.

Reference generated from the product documentation. Match commands and support details to your installed release.