mirror of
https://github.com/rcourtman/Pulse.git
synced 2026-09-10 02:25:56 +00:00
Document provider-MSP deploy bundle as canonical install; surface lease signing public key in setup.sh
- MSP.md now leads with deploy/provider-msp/ (compose stack, setup.sh, upgrade.sh, run-install-proof.sh), documents the HTTPS requirement (__Host- portal session cookie) and the pulse.provider-msp.role labels workspace provisioning requires, and explains the licence/lease chain including licence-expiry behavior. - setup.sh derives and prints the lease signing public key the provider MSP licence must bind (also via --print-lease-signing-public-key), and the missing-licence error now includes it with request instructions. - .env.example documents the CP_TRIAL_ACTIVATION_PRIVATE_KEY binding.
This commit is contained in:
@@ -26,6 +26,12 @@ PULSE_PROVIDER_MSP_ROOT_SPACECHECK_DIR=/var/lib/pulse-provider-msp/spacecheck/ro
|
||||
PULSE_PROVIDER_MSP_DOCKER_SPACECHECK_DIR=/var/lib/docker/.pulse-provider-msp-spacecheck
|
||||
CP_TRUSTED_PROXY_CIDRS=172.30.0.0/24
|
||||
CP_PROVIDER_MSP_LICENSE_FILE=./provider-msp-license.jwt
|
||||
# Entitlement lease signing key. setup.sh generates this; the private key
|
||||
# never leaves this host. Your provider MSP license must bind the derived
|
||||
# PUBLIC key (entitlement_signing_public_key) — print it with
|
||||
# `./setup.sh --print-lease-signing-public-key` and include it in your
|
||||
# license request. The control plane refuses to start if license and key
|
||||
# do not match.
|
||||
CP_TRIAL_ACTIVATION_PRIVATE_KEY=
|
||||
CP_TENANT_MEMORY_LIMIT=536870912
|
||||
CP_ALLOW_DOCKERLESS_PROVISIONING=false
|
||||
|
||||
@@ -297,6 +297,42 @@ ensure_generated_secrets() {
|
||||
chmod 0600 "${env_path}"
|
||||
}
|
||||
|
||||
# derive_lease_signing_public_key prints the base64 Ed25519 public key for
|
||||
# CP_TRIAL_ACTIVATION_PRIVATE_KEY. The provider MSP license must bind this
|
||||
# exact key (entitlement_signing_public_key) or the control plane will refuse
|
||||
# to start; include it when requesting your license. The private key never
|
||||
# leaves this host.
|
||||
derive_lease_signing_public_key() {
|
||||
local env_path="${PULSE_PROVIDER_MSP_INSTALL_DIR}/.env"
|
||||
[[ -f "${env_path}" ]] || die "missing ${env_path}"
|
||||
have openssl || die "openssl is required to derive the lease signing public key"
|
||||
|
||||
local key_b64 key_len tmp_der
|
||||
key_b64="$(env_value CP_TRIAL_ACTIVATION_PRIVATE_KEY "${env_path}")"
|
||||
[[ -n "${key_b64}" ]] || die "CP_TRIAL_ACTIVATION_PRIVATE_KEY is not set; run setup.sh first"
|
||||
key_len="$(printf '%s' "${key_b64}" | base64 -d 2>/dev/null | wc -c | tr -d ' ')"
|
||||
case "${key_len}" in
|
||||
64)
|
||||
# 64-byte Ed25519 private key: the public key is the trailing 32 bytes.
|
||||
printf '%s' "${key_b64}" | base64 -d | tail -c 32 | base64 | tr -d '\n'
|
||||
;;
|
||||
32)
|
||||
# 32-byte seed: wrap in a PKCS#8 DER envelope and let openssl derive
|
||||
# the public key (raw key = trailing 32 bytes of the SPKI DER).
|
||||
tmp_der="$(mktemp)"
|
||||
{
|
||||
printf '\x30\x2e\x02\x01\x00\x30\x05\x06\x03\x2b\x65\x70\x04\x22\x04\x20'
|
||||
printf '%s' "${key_b64}" | base64 -d
|
||||
} >"${tmp_der}"
|
||||
openssl pkey -inform DER -in "${tmp_der}" -pubout -outform DER 2>/dev/null | tail -c 32 | base64 | tr -d '\n'
|
||||
rm -f "${tmp_der}"
|
||||
;;
|
||||
*)
|
||||
die "CP_TRIAL_ACTIVATION_PRIVATE_KEY must decode to a 32-byte seed or 64-byte Ed25519 key (got ${key_len} bytes)"
|
||||
;;
|
||||
esac
|
||||
}
|
||||
|
||||
truthy() {
|
||||
case "$(echo "$1" | tr '[:upper:]' '[:lower:]')" in
|
||||
true|1|yes|on) return 0 ;;
|
||||
@@ -454,7 +490,13 @@ validate_env_file() {
|
||||
if [[ "${license_file}" != /* ]]; then
|
||||
license_file="${PULSE_PROVIDER_MSP_INSTALL_DIR}/${license_file}"
|
||||
fi
|
||||
[[ -f "${license_file}" ]] || die "CP_PROVIDER_MSP_LICENSE_FILE does not exist: ${license_file}"
|
||||
if [[ ! -f "${license_file}" ]]; then
|
||||
die "CP_PROVIDER_MSP_LICENSE_FILE does not exist: ${license_file}
|
||||
Request your provider MSP license with this lease signing public key
|
||||
(./setup.sh --print-lease-signing-public-key):
|
||||
$(derive_lease_signing_public_key)
|
||||
The license must bind this key or the control plane will refuse to start."
|
||||
fi
|
||||
}
|
||||
|
||||
validate_compose_config() {
|
||||
@@ -521,12 +563,24 @@ Proof:
|
||||
Portal:
|
||||
https://${domain}/
|
||||
|
||||
Lease signing public key (your provider MSP license must bind this key;
|
||||
re-print any time with ./setup.sh --print-lease-signing-public-key):
|
||||
$(derive_lease_signing_public_key)
|
||||
|
||||
EOF
|
||||
}
|
||||
|
||||
main() {
|
||||
need_root
|
||||
|
||||
if [[ "${1:-}" == "--print-lease-signing-public-key" ]]; then
|
||||
ensure_env_file
|
||||
ensure_generated_secrets
|
||||
derive_lease_signing_public_key
|
||||
printf '\n'
|
||||
exit 0
|
||||
fi
|
||||
|
||||
log "starting provider MSP first-time setup"
|
||||
apt_install apt-transport-https
|
||||
install_docker_ce
|
||||
|
||||
+40
-2
@@ -11,8 +11,23 @@ alert routing, and reporting. It assumes you have read
|
||||
runtime per client workspace. Alerts, webhook destinations, branded report
|
||||
settings, users, audit history, and metrics stay inside the client runtime;
|
||||
duplicate hostnames across clients never collide because they never share a
|
||||
runtime namespace. The stack is operated with the `pulse-control-plane`
|
||||
binary:
|
||||
runtime namespace.
|
||||
|
||||
The canonical install is the deploy bundle at
|
||||
[`deploy/provider-msp/`](../deploy/provider-msp/): a Docker Compose stack
|
||||
(Traefik ingress with wildcard TLS, a hardened Docker socket proxy, and the
|
||||
control plane), a guided `setup.sh` for fresh hosts, `upgrade.sh` for
|
||||
backup-gated upgrades, and `run-install-proof.sh` for an end-to-end fresh
|
||||
install proof. `.env.example` in that directory doubles as the operator
|
||||
runbook. Start there rather than wiring containers by hand; among other
|
||||
things the compose stack provides the `pulse.provider-msp.role=traefik` and
|
||||
`pulse.provider-msp.role=control-plane` container labels that client
|
||||
workspace provisioning requires for isolated tenant networking, and it
|
||||
terminates TLS — the management portal sets a `__Host-` (HTTPS-only) session
|
||||
cookie, so the portal does not work over plain HTTP.
|
||||
|
||||
Day-2 operations run through the `pulse-control-plane` binary (via
|
||||
`docker compose run --rm control-plane …` in the bundle):
|
||||
|
||||
```bash
|
||||
pulse-control-plane provider-msp bootstrap --account-name "Your MSP" --owner-email you@example.com
|
||||
@@ -162,3 +177,26 @@ are carried on the licence key. MSP plans are sized by client workspace count
|
||||
(Starter 5, Growth 15, Scale 40); workspace creation is blocked, not billed,
|
||||
when the limit is reached. MSP and Enterprise keys are issued through sales —
|
||||
contact support to get set up or to join the MSP design-partner program.
|
||||
|
||||
In the provider-hosted model the licence is a signed file
|
||||
(`CP_PROVIDER_MSP_LICENSE_FILE`) that also binds your control plane's
|
||||
entitlement lease signing key:
|
||||
|
||||
1. `setup.sh` generates `CP_TRIAL_ACTIVATION_PRIVATE_KEY` locally; the
|
||||
private key never leaves your host.
|
||||
2. Send the derived public key
|
||||
(`./setup.sh --print-lease-signing-public-key`) with your licence request.
|
||||
3. The issued licence binds that key. The control plane refuses to start in
|
||||
provider mode if the licence and key do not match, so a misconfigured
|
||||
stack fails at startup instead of provisioning client workspaces that
|
||||
silently run unlicensed.
|
||||
|
||||
Client runtimes lease their entitlements from your control plane (the
|
||||
control plane injects the refresh endpoint; nothing phones Pulse Cloud) and
|
||||
verify each lease through the licence chain: Pulse's embedded key signs your
|
||||
licence, your licence binds your signing key, your signing key signs the
|
||||
lease. Leases carry the MSP capability set plus `white_label`, so branded
|
||||
per-client reports work inside every client workspace. When the licence
|
||||
expires, leases stop verifying after the grace period and client runtimes
|
||||
fall back to Community behavior; renew and restart the control plane to
|
||||
restore them.
|
||||
|
||||
Reference in New Issue
Block a user