Sign Sunshine certs with a 1Password-backed root CA
Replaces Sunshine's self-signed cert with one minted from a private root CA
whose key material lives in 1Password. Every host running install.sh fetches
the CA via 'op read', mints itself a host cert with SANs for <hostname>.lan
and the current LAN IP, and installs the CA into the system trust store.
Bootstrap (run once, anywhere)
- scripts/cert-bootstrap.sh: generates a 4096-bit RSA root CA (10y validity),
uploads it as a Secure Note titled "Omarchy-Stream Root CA" in the Private
vault with two fields: cert (text) and key (concealed). Refuses to overwrite
an existing item without --force.
Per-host (lib/certs.sh)
- fetch_and_install_certs: reads op://Private/Omarchy-Stream Root CA/{cert,key}
to a tmpfs-staged temp dir (XDG_RUNTIME_DIR), mints a host cert via openssl
with serverAuth + clientAuth EKU, drops cert/key at ~/.config/sunshine/
credentials/{cacert,cakey}.pem, installs the CA at
/etc/ca-certificates/trust-source/anchors/omarchy-stream-ca.pem and runs
update-ca-trust.
- Idempotent: skips re-mint when on-disk cert is signed by the current CA,
has the expected SANs, and isn't within 30 days of expiry. Override with
FORCE_CERTS=1 or --force-certs.
install.sh
- Adds --no-certs, --force-certs flags; sources lib/certs.sh; runs cert step
after permissions/config and before firewall so the service restart at the
end of install picks up the new cert.
client/install-macos.sh
- After installing Moonlight, if `op` is available and signed in, fetches the
CA and adds it as a trusted root to /Library/Keychains/System.keychain via
`security add-trusted-cert -d -r trustRoot`. Skips cleanly when op isn't
ready.
uninstall.sh
- Adds --remove-ca-trust to delete the system trust anchor. By default the
CA is left in place since other tools may rely on it.
verify.sh
- Adds checks for: cert signed by omarchy-stream CA, cert >30 days from
expiry, CA present in system trust store.
Docs
- README "Trusted TLS certs via 1Password" section: bootstrap flow, per-host
flow, client trust matrix (Linux / macOS / iOS / Android / Apple TV),
re-pairing note (first cert install on a host invalidates pinned Moonlight
fingerprints), config env vars.
- client/README gains per-platform CA-trust install steps with concrete
`op read` + platform-specific commands.
This commit is contained in:
60
README.md
60
README.md
@@ -78,11 +78,16 @@ Every step is idempotent. In order:
|
||||
./install.sh --no-sunshine # client-only (install Moonlight only)
|
||||
./install.sh --no-moonlight # host-only
|
||||
./install.sh --from-source # build sunshine from source (default uses sunshine-bin)
|
||||
./install.sh --no-certs # skip the 1Password-backed cert step
|
||||
./install.sh --force-certs # re-mint the host cert even if current
|
||||
./install.sh --doctor # verification only (no install)
|
||||
|
||||
./scripts/cert-bootstrap.sh # one-time: generate root CA, push to 1Password
|
||||
|
||||
./uninstall.sh # remove packages and udev rule, keep user data
|
||||
./uninstall.sh --purge # also delete ~/.config/sunshine
|
||||
./uninstall.sh --keep-moonlight
|
||||
./uninstall.sh --remove-ca-trust # also remove the omarchy-stream CA from system trust
|
||||
```
|
||||
|
||||
Environment overrides:
|
||||
@@ -116,6 +121,61 @@ Per-vendor encoder picks:
|
||||
|
||||
Everything else (bitrate, paired clients, app launchers) is set via the web UI.
|
||||
|
||||
## Trusted TLS certs via 1Password
|
||||
|
||||
The installer can replace Sunshine's default self-signed cert with one minted from a private root CA whose key material lives in 1Password. Result: no more browser warning on `https://<host>.lan:47990`, and any tool that respects the system trust store (curl, openssl, browsers using NSS) trusts the host directly.
|
||||
|
||||
### One-time bootstrap (run on any one machine)
|
||||
|
||||
```bash
|
||||
./scripts/cert-bootstrap.sh
|
||||
```
|
||||
|
||||
This:
|
||||
1. Generates a 4096-bit RSA root CA (10-year validity).
|
||||
2. Uploads it to 1Password as a Secure Note titled **Omarchy-Stream Root CA** in the **Private** vault, with two fields:
|
||||
- `cert` (text): the PEM cert.
|
||||
- `key` (concealed): the PEM private key.
|
||||
3. Prints the `op://Private/Omarchy-Stream Root CA/{cert,key}` references for confirmation.
|
||||
|
||||
Refuses to overwrite an existing CA item unless you pass `--force` — replacing the CA invalidates every host cert previously minted from it.
|
||||
|
||||
### Per-host (built into install.sh)
|
||||
|
||||
`./install.sh` runs a cert step that:
|
||||
|
||||
1. Reads the CA from 1Password (the `op` CLI must be signed in, `eval $(op signin)` first).
|
||||
2. Mints a host cert with SAN entries for `<hostname>.lan` and the host's current LAN IP, signed by the CA, valid 365 days.
|
||||
3. Writes the cert / key into `~/.config/sunshine/credentials/{cacert,cakey}.pem` (the same paths Sunshine uses by default).
|
||||
4. Installs the CA cert into `/etc/ca-certificates/trust-source/anchors/omarchy-stream-ca.pem` and runs `update-ca-trust`.
|
||||
5. The next service restart picks up the new cert.
|
||||
|
||||
The step is idempotent: if the on-disk cert is signed by the current CA, has the right SANs, and isn't expiring within 30 days, it's left alone. Force a re-mint with `--force-certs`.
|
||||
|
||||
Skip the cert step entirely with `--no-certs` — Sunshine will fall back to generating its own self-signed cert as before.
|
||||
|
||||
### Clients trust the CA too
|
||||
|
||||
| Client | How |
|
||||
|---|---|
|
||||
| Another Linux host | Same `install.sh` — the cert step installs the CA into `/etc/ca-certificates` regardless of whether the host runs Sunshine. |
|
||||
| macOS | `client/install-macos.sh` fetches the CA from 1Password and runs `security add-trusted-cert -d -r trustRoot -k /Library/Keychains/System.keychain`. |
|
||||
| iOS / iPadOS | Email yourself the CA PEM, install as a profile, then enable full trust in Settings → General → About → Certificate Trust Settings. Documented in `client/README.md`. |
|
||||
| Android | Settings → Security → Encryption & credentials → Install from storage → CA certificate. Documented in `client/README.md`. |
|
||||
|
||||
### Cert replacement and Moonlight re-pairing
|
||||
|
||||
Sunshine uses one cert for both the web UI and the pairing handshake. Replacing the cert invalidates the fingerprint pinned by previously-paired Moonlight clients. **After the first cert install on a host, re-pair every Moonlight client once** via the web UI. After that, the cert is stable and re-runs of `install.sh` don't re-mint unless the cert is expiring.
|
||||
|
||||
### Configuration
|
||||
|
||||
| Variable | Default | Effect |
|
||||
|---|---|---|
|
||||
| `OP_VAULT` | `Private` | 1Password vault that holds the CA item |
|
||||
| `OP_CA_ITEM` | `Omarchy-Stream Root CA` | Title of the CA item |
|
||||
| `CERT_DAYS` | `365` | Host cert validity (days) |
|
||||
| `FORCE_CERTS` | `0` | Set to `1` to re-mint even when the existing cert is current |
|
||||
|
||||
## Clients
|
||||
|
||||
The host-side installer handles Linux clients via `moonlight-qt`. For everything else, see `client/README.md` for per-platform install plus the first-pair walkthrough.
|
||||
|
||||
Reference in New Issue
Block a user