Customer-held signing keys
Every job a host runs is signed with your organization’s key, and the agent refuses anything else. Normally that key lives in Google Cloud KMS and Updawg signs approved jobs with it. With a customer-held key, you hold it: our key endorses yours once, and from then on Updawg signs nothing. Each approved job waits until you sign it in your own environment, and a job you did not sign is one no host will run — whatever happens to Updawg.
The cost is that the key is yours to keep. If you lose it, Updawg cannot recover it: every host has to be re-enrolled. Keep a copy somewhere safe, or keep it in an HSM.
1. Make a key
Section titled “1. Make a key”Where the key will live — a workstation, a CI runner, a machine in front of your HSM, never a managed host:
updawgctl keygen --out org.keyIt writes the private key to org.key, readable only by you, and prints the
public key. updawgctl is in the agent package; any Linux machine with it
installed will do, enrolled or not. A key you made with
openssl genpkey -algorithm ed25519 works too.
2. Hand signing over to it
Section titled “2. Hand signing over to it”Under Settings → Signing keys, an admin or owner chooses Use your own key. The dialog shows your organization’s id; prove you hold the key:
updawgctl prove-key --org org_… --key org.keyand paste the line it prints. Updawg checks the proof — a hand-over to a key nobody holds cannot be undone, so a mistyped key fails here — and our key endorses yours. A few seconds later yours is the active key and ours is retiring.
3. Point your hosts at it
Section titled “3. Point your hosts at it”Existing hosts move over within minutes: Updawg asks each one to renew its
certificate, and it picks up your key after checking our endorsement of it.
Agents released before 2026-10-11 move at their next scheduled renewal instead,
within a month. sudo updawgctl renew on a host does it at its next check-in.
Until a host has moved, it is still sent jobs signed with our key.
For hosts you enrol from now on, set the key in /etc/updawg/agent.toml, or
pass it to the installer:
curl -fsSL https://get.updawg.net | sudo UPDAWG_TOKEN=enr_… UPDAWG_ORG_KEY=MCowBQYDK2VwAyEA… shA host with trusted_org_key set pins only your key and keys it endorsed. If
the server offered it anything else, it would refuse to enrol and write
nothing. You can add trusted_org_key to existing hosts too;
sudo updawgctl status says whether the host has pinned it yet.
4. Sign jobs
Section titled “4. Sign jobs”Approving a proposal now makes jobs that wait for your signature: the portal
shows them as Awaiting your signature, and the Signing keys card says how
many there are. Sign them with an API token that has the
read and approve scopes:
export UPDAWG_API_TOKEN=upd_…updawgctl sign --org acme --key org.keyFor each job it shows what the job will do — the host, the exact package versions, whether it may reboot — decoded from the bytes it is about to sign, and asks. It signs only jobs for your key, checks each signature before sending it, and the host verifies it again before running anything.
To sign on a schedule, add --yes. To sign with an HSM or a cloud KMS instead
of a key file, give a command that reads the bytes to sign on stdin and prints
the Ed25519 signature:
updawgctl sign --org acme --yes \ --command 'my-hsm-sign --key updawg-org' \ --public-key MCowBQYDK2VwAyEA…Limit what is signed unattended
Section titled “Limit what is signed unattended”--yes on a schedule signs every job waiting for your key, so anyone who can
get a proposal approved gets your signature. A policy file narrows that to what
you decided in advance; anything outside it is left waiting for a person, and
the run says why:
# Job kinds it may sign. Anything else waits.allow = ["refresh_inventory", "run_preflight", "apply_updates"]# Whether a job may restart the host: a reboot job, or an update that asks# for one. Off unless you say so.reboot = false# An update touching more packages than this waits.max_packages = 50# An update touching any package matching these waits. `*` matches anything.deny_packages = ["linux-image-*", "kernel*", "openssh-server"]updawgctl sign --org acme --key org.key --yes --policy sign-policy.tomlThe policy is checked against each job’s own document, the bytes about to be signed. A misspelt key or job kind is an error rather than ignored, and a policy that allows nothing signs nothing.
Before jobs expire
Section titled “Before jobs expire”A job not signed by the time it expires expires, and its proposal halts, as it
would for a host that never picked it up. Notification rules for
jobs.awaiting_signature hear about waiting jobs twice: when they are made,
and again four hours before the first of them expires.
5. Retire our key
Section titled “5. Retire our key”Each key on the Signing keys card says how many hosts pinned it at their last check-in, and each host’s page lists the keys it holds. Once every host has your key, choose Retire next to Updawg’s key. From then on Updawg is never asked to sign for your organization, and hosts refuse anything our key signed once they next renew. We then destroy the key in Cloud KMS.
A host that has not picked your key up by then gets no job it can run until it renews, so retire after the hosts have moved — or re-enrol the stragglers.
What this does and does not protect against
Section titled “What this does and does not protect against”With your key held by you and ours retired, nobody who compromises Updawg —
our servers, our database, our cloud account, or us — can make a job your
hosts will run. They can still stop sending jobs, or show you wrong
information in the portal; updawgctl sign shows each job from the document
itself so that what you sign is what you see.
Rotating your own key
Section titled “Rotating your own key”To replace your key with a new one, your current key endorses the next, where your keys live, exactly as ours endorsed yours. Hosts follow the endorsement within minutes, as they did the hand-over; nothing needs re-enrolling.
-
Make the next key:
updawgctl keygen --out next.key. -
Endorse it with the active one.
--fromis the active key’s id from the Signing keys card, and--next-public-keyis what keygen printed:Terminal window updawgctl endorse --org org_… --from sk_… \--next-public-key MCowBQYDK2VwAyEA… --key org.keyWith an HSM, use
--commandand--public-keyfor the active key, as forsign. -
Prove you hold the next key:
updawgctl prove-key --org org_… --key next.key. -
Under Settings → Signing keys, choose Rotate your key and paste both lines. The next key is active at once, and the previous one is retiring: hosts still accept it until they renew.
-
Sign with the new key from now on. When every host pins it, retire the previous one on the card, and set the new public key as
trusted_org_keyon hosts you enrol from now on.
Both lines are good for a day. The endorsement names the active key by id and by its public key, so one made before somebody else rotated is refused.