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:
2026-05-18 10:43:33 -06:00
parent 171ade4ff1
commit e878b392e4
8 changed files with 513 additions and 5 deletions

View File

@@ -51,6 +51,56 @@ to the same Apple ID.
Use `moonlight-qt` from your distro's package manager (Flatpak on Steam Deck,
`pacman`/`apt` elsewhere). It is the same Qt-based client as macOS and Windows.
## Trusting the omarchy-stream CA
If the host was installed with the cert step (default), its Sunshine web UI
uses a cert signed by a private root CA whose key is stored in 1Password. To
avoid the browser warning on `https://<host>.lan:47990`, install the CA on each
client device. This is a one-time step per device.
### macOS
`./install-macos.sh` handles this automatically if `op` is signed in. To do it
manually:
```bash
op read --no-newline "op://Private/Omarchy-Stream Root CA/cert" > /tmp/ca.pem
sudo security add-trusted-cert -d -r trustRoot \
-k /Library/Keychains/System.keychain /tmp/ca.pem
rm /tmp/ca.pem
```
### iOS / iPadOS
1. In the 1Password app, open the **Omarchy-Stream Root CA** item in the
**Private** vault. Copy the `cert` field into the body of an email and send
it to yourself with the file extension `.crt` or `.pem` (Mail handles inline
PEM oddly; an attachment is cleanest).
2. Open the email on the iOS device and tap the attachment. iOS will offer to
install a configuration profile.
3. Settings → General → VPN & Device Management → Downloaded Profile → Install.
4. **Important second step**: Settings → General → About → Certificate Trust
Settings → enable full trust for the omarchy-stream Root CA. Without this,
Safari still warns.
### Android
1. From 1Password, save the CA `cert` field to a `.crt` file on the device
(Downloads folder is fine).
2. Settings → Security → Encryption & credentials → Install a certificate → CA
certificate.
3. Acknowledge the warning, select the file, give it a name.
(Path varies slightly by Android version / OEM skin — search Settings for "CA
certificate" if the path above doesn't match.)
### Apple TV
Cert profiles can be installed by emailing the cert to an account on the
Apple TV and tapping it, or by using Apple Configurator from a Mac. For
LAN-only use the self-signed warning is also tolerable — Apple TV has no
browser, so the cert is only relevant if you ever inspect the host directly.
## First pair
The pairing flow is the same on every client.

View File

@@ -51,6 +51,43 @@ else
exit 1
fi
# --- CA trust install (1Password-backed) ------------------------------------
# If `op` is available and signed in, fetch the omarchy-stream Root CA from
# 1Password and add it to the System keychain as a trusted root. This makes
# Safari / Chrome / curl trust the Sunshine web UI on every host without the
# self-signed warning. Skip cleanly if op isn't available or not signed in;
# the user can re-run after `eval $(op signin)`.
SKIP_CA="${SKIP_CA:-0}"
OP_VAULT="${OP_VAULT:-Private}"
OP_CA_ITEM="${OP_CA_ITEM:-Omarchy-Stream Root CA}"
if [[ $SKIP_CA -eq 1 ]]; then
info "Skipping CA install (SKIP_CA=1)"
elif ! command -v op >/dev/null 2>&1; then
info "1Password CLI ('op') not found. Skipping CA trust install."
info "Install it from https://1password.com/downloads/command-line/ and re-run for trusted certs."
elif ! op whoami >/dev/null 2>&1; then
info "1Password CLI is not signed in. Skipping CA trust install."
info "Sign in with 'eval \$(op signin)' and re-run for trusted certs."
else
step "Installing omarchy-stream CA into System keychain"
ca_tmp="$(mktemp -t omarchy-ca.XXXXXX.pem)"
trap 'rm -f "$ca_tmp"' EXIT
if op read --no-newline "op://${OP_VAULT}/${OP_CA_ITEM}/cert" >"$ca_tmp" 2>/dev/null && [[ -s "$ca_tmp" ]]; then
info "Fetched CA from 1Password (vault: ${OP_VAULT})"
info "Adding to /Library/Keychains/System.keychain — you may be prompted for your password."
if sudo security add-trusted-cert -d -r trustRoot \
-k /Library/Keychains/System.keychain "$ca_tmp"; then
ok "CA installed as trusted root."
else
warn "security add-trusted-cert failed. You can add the cert manually via Keychain Access."
fi
else
warn "Could not read 'cert' field from item '${OP_CA_ITEM}' in vault '${OP_VAULT}'."
warn "Run scripts/cert-bootstrap.sh on a Linux host first, then re-run this script."
fi
fi
step "Next steps"
info "App location: /Applications/Moonlight.app"
info "Launch: open -a Moonlight"