Installer security
The Parako.ID installer is a 3000-line bash script that runs with root privileges (for system-wide installs). Identity providers are crown-jewel systems — compromise means full identity compromise of every relying party. This page documents the installer’s threat model and the trust chain that lets you verify, byte for byte, that the script you piped to bash is the one the maintainer published.
Trust chain summary
Section titled “Trust chain summary”| Artifact | Verified against | Mechanism |
|---|---|---|
install.sh itself | Maintainer-published SHA256 | sha256sum install.sh compared to the value in the GitHub Release notes |
| Release tarball | SHA256SUMS | sha256sum |
| Release tarball | Sigstore transparency log | cosign verify-blob with identity bound to release.yml |
| Cosign binary (auto-installed) | Inline SHA256 constant in install.sh | First-time chain-of-trust bootstrap |
Threat model
Section titled “Threat model”The installer assumes:
- TLS is intact between the operator and
get.parako.idand between the operator and GitHub. - The Sigstore transparency log is intact at
https://rekor.sigstore.dev. - GitHub’s OIDC identity service is intact at
https://token.actions.githubusercontent.com.
Under these assumptions, the installer protects against:
- A compromised release tarball published to GitHub Releases (cosign + Sigstore catches a tarball that wasn’t built by the
release.ymlworkflow onmain). - An MITM attack on the tarball download path (TLS 1.2+ enforced; HTTP downloads refused).
- An MITM attack on the mirror download path (TLS 1.2+ enforced; non-HTTPS mirror URLs are refused).
- A maintainer who tries to push a release outside CI (cosign-binding to
release.ymlmeans manually-built tarballs cannot pass verification). - A compromised release pipeline that bypasses cosign (the operator’s
install.shrefuses the unsigned tarball; the escape hatch--insecure-no-signaturerequires explicit reason text logged to the structured install log).
The installer does not protect against:
- A compromised GitHub account that has CI write permissions and can modify
release.ymlitself (the cosign identity is bound to the workflow path — if that path is rewritten, future signatures are bound to the rewritten path). Mitigation: pin the workflow file with branch protection + required reviews. - A compromise of Sigstore or GitHub OIDC (out of scope; same trust anchor as the rest of the OSS ecosystem).
- An attacker who is already root on the target machine before the installer runs (no installer can defend against this).
Verifying the installer itself
Section titled “Verifying the installer itself”Each release of Parako.ID publishes the SHA256 of install.sh in the release notes. To verify what you’re about to pipe to bash:
# Download without executingcurl --proto '=https' --tlsv1.2 -fsSL https://get.parako.id -o /tmp/install.sh
# Get the expected SHA256 from the release notes# (look for: "Installer SHA256: <value>" in the v0.2.0 release on GitHub)EXPECTED="<value from release notes>"
# CompareACTUAL=$(sha256sum /tmp/install.sh | awk '{print $1}')[ "$ACTUAL" = "$EXPECTED" ] && echo "verified" || echo "MISMATCH — DO NOT RUN"
# If verified, run from diskbash /tmp/install.sh --helpThis single check pins the entire installer to a known-good byte sequence. If it matches, the rest of the trust chain (cosign for the release tarball) is bootstrapped from that.
Cosign chain-of-trust bootstrap
Section titled “Cosign chain-of-trust bootstrap”The installer must verify a cosign-signed release tarball, but cosign itself may not be installed on a fresh box. The chain-of-trust pattern is:
- Inline constants in
install.sh:Terminal window COSIGN_VERSION=2.4.1COSIGN_SHA256_LINUX_AMD64=<sha256 of the official cosign-linux-amd64 binary>COSIGN_SHA256_LINUX_ARM64=<sha256 of the official cosign-linux-arm64 binary> - Bootstrap fetch: if
cosignisn’t inPATH, the installer downloadshttps://github.com/sigstore/cosign/releases/download/v${COSIGN_VERSION}/cosign-linux-${arch}and computes its SHA256. - Verify: the SHA256 must match the inlined constant exactly. Mismatch → hard fail.
- Install: the verified cosign binary is installed to
/usr/local/bin/cosign(or~/.local/bin/cosignfor user installs). - Use: the verified cosign is then used to verify the Parako.ID release tarball against Sigstore.
The trust root of this chain is the inlined SHA256 constant. When the maintainer bumps COSIGN_VERSION, the constants must be updated in lockstep — see Maintainer procedure below.
Release verification
Section titled “Release verification”For each Parako.ID release v0.2.0+, the CI workflow release.yml signs three artifacts via cosign keyless:
parako-id-v${V}.tar.gz→parako-id-v${V}.tar.gz.sig+.pemparako-id-v${V}.zip→parako-id-v${V}.zip.sig+.pemSHA256SUMS→SHA256SUMS.sig+.pem
The cosign certificate identity is bound to the workflow path:
--certificate-identity-regexp 'https://github\.com/Dahkenangnon/Parako\.ID/\.github/workflows/release\.yml@.*'--certificate-oidc-issuer 'https://token.actions.githubusercontent.com'This regex means: only signatures produced by the release.yml workflow in the Parako.ID repo (on any branch/tag) verify. A signature from any other workflow, or any other repo, is rejected.
You can verify a Parako.ID release independently:
gh release download v0.2.0 \ -p 'parako-id-v0.2.0.tar.gz' \ -p 'parako-id-v0.2.0.tar.gz.sig' \ -p 'parako-id-v0.2.0.tar.gz.pem'
cosign verify-blob \ --signature parako-id-v0.2.0.tar.gz.sig \ --certificate parako-id-v0.2.0.tar.gz.pem \ --certificate-identity-regexp 'https://github\.com/Dahkenangnon/Parako\.ID/\.github/workflows/release\.yml@.*' \ --certificate-oidc-issuer 'https://token.actions.githubusercontent.com' \ parako-id-v0.2.0.tar.gzExpected output: Verified OK.
The --insecure-no-signature escape
Section titled “The --insecure-no-signature escape”In the rare case where Sigstore is unreachable (network partition, Sigstore outage, regulated network), the installer offers an explicit escape:
curl --proto '=https' --tlsv1.2 -fsSL https://get.parako.id | sudo bash -s -- \ --update --insecure-no-signature \ --reason "Sigstore outage on 2026-06-15; verified SHA256 manually from release notes"The escape requires:
- The exact word
--insecure-no-signature - A non-empty
--reason "<text>" - In interactive mode, the operator typing
yesin full when prompted
The reason is logged verbatim to the structured install log at /var/log/parako-install-<ts>.log (or ${XDG_STATE_HOME}/parako/parako-install-<ts>.log for non-root installs). Use this escape only when you have manually verified the tarball SHA256 against the release notes.
Sensitive-value redaction
Section titled “Sensitive-value redaction”The installer writes a structured JSON-lines log at /var/log/parako-install-${ts}.log (or ${XDG_STATE_HOME}/parako/... for non-root installs). Every line passes through a redactor that masks:
- URI authentication (
scheme://user:pass@host→scheme://***@host) - Any value following a key named
password,secret,token,credential,api_key,hmac_secret,jwt_secret,cookie_secret_N,encryption_key,pairwise_salt
You can safely share the install log when reporting bugs.
File permissions
Section titled “File permissions”Files the installer writes (mode is enforced regardless of the operator’s umask):
| File | Mode | Owner | Notes |
|---|---|---|---|
/var/log/parako-install-*.log | 0600 | install operator | Installer’s own structured log |
/usr/local/bin/parako | 0755 | root:root | Operator helper; install is non-fatal |
/usr/local/bin/cosign | 0755 | root:root | Only if cosign bootstrap was needed |
${INSTALL_DIR}/.parako-state | 0644 | install operator | No secrets; readable by non-root operators |
${INSTALL_DIR}/.install-lock | 0644 | install operator | flock target for install / update / rollback / gc |
Files the installer does not create or modify:
| File | Why |
|---|---|
runtime/.env | Operator-owned secrets |
runtime/jwks/jwks.json | Operator-owned signing keys |
runtime/parako.jsonc, runtime/parako-rp.jsonc | Operator-owned config |
runtime/data/parako.db | Operator-owned database |
/etc/systemd/system/*.service | Operator-managed supervisor |
/etc/nginx/sites-available/* | Operator-managed reverse proxy |
/etc/letsencrypt/* | Operator-managed TLS |
Network egress points
Section titled “Network egress points”During install and update, the installer makes outbound HTTPS connections only to:
| Host | Purpose |
|---|---|
api.github.com | Resolve latest release tag (skipped under --offline and when --version is set) |
github.com / objects.githubusercontent.com | Release tarball + signature + certificate download |
rekor.sigstore.dev / fulcio.sigstore.dev | Cosign transparency log + certificate authority |
Under --offline, the installer makes no network calls and requires --version, --tarball, --checksum, --signature, --certificate, and a preinstalled cosign binary on PATH.
No telemetry. The installer does not phone home.
Maintainer procedure
Section titled “Maintainer procedure”Updating cosign bootstrap constants
Section titled “Updating cosign bootstrap constants”When the cosign release version is bumped:
- Download the new
cosign-linux-amd64andcosign-linux-arm64binaries fromhttps://github.com/sigstore/cosign/releases/tag/v${NEW_VERSION}. - Compute their SHA256 sums.
- Update
COSIGN_VERSION,COSIGN_SHA256_LINUX_AMD64,COSIGN_SHA256_LINUX_ARM64ininstaller/install.sh:§1. - Update the cosign-installer step in
.github/workflows/release.ymlto the matching version. - Test against the test VPS (fresh install +
--update).
Publishing the installer SHA256
Section titled “Publishing the installer SHA256”After each release, publish the SHA256 of installer/install.sh in the GitHub release notes so operators can verify the installer before piping to bash:
sha256sum installer/install.shRotating cosign keys
Section titled “Rotating cosign keys”Sigstore keyless signing does not use long-lived keys, so there’s no key rotation per se. The trust anchor is the workflow path. To revoke trust:
- Update
COSIGN_CERT_IDENTITY_REGEXininstaller/install.shto a regex that excludes the bad commit range. - Publish a security advisory.
See also
Section titled “See also”- Installer
- Security — defense-in-depth at the application layer
- parako CLI
- Sigstore documentation
- Aaron Maxwell — Unofficial Bash Strict Mode