Skip to content

Repository files navigation

signet

The key that proves which machine you are; sealed in hardware, exportable to no one.

Go Release Licence

One self-contained Go binary that gives a machine a hardware-rooted signing identity and trades a signed challenge for a short-lived bearer token — on whichever secure hardware the host has.

Installation · Quickstart · Backends · Documentation · Contributing

What is signet?

A machine that needs secrets has to prove it is itself before a broker will hand anything over. The robust way to do that is a non-exportable key sealed in hardware: the machine signs a challenge, the broker verifies the signature against a public key it enrolled once, and issues a short-lived credential. No long-lived secret sits on disk, in an env var, or in a config file.

signet is a single self-contained Go binary that implements this pattern across the three secure-hardware substrates a real fleet actually has:

  • Apple Secure Enclave: auto-detected on macOS
  • TPM 2.0: auto-detected on Linux and Windows with a reachable TPM device
  • YubiKey / PIV token: cross-platform fallback, or explicit with --backend piv

The backends are compiled in and selected at runtime; switching hardware is a one-flag change, not a migration. The private key never leaves the hardware. The only thing on disk is a short-lived bearer cache and, on macOS, the Enclave's own opaque key blob (useless if copied off the machine).

signet acts as a standard credential helper, the same shape as git credential, docker-credential-*, and AWS credential_process. A consumer shells out for a fresh Authorization header on demand; signet produces it and exits. For workloads that cannot reach the hardware at all (a container with no path to the YubiKey), the agent subcommand runs one daemon that owns the token and signs for socket clients on request — the ssh-agent pattern — while every other subcommand stays single-shot.

This is the same pattern AWS ships as IAM Roles Anywhere, generalised across the three secure-hardware substrates a heterogeneous fleet actually has.

Installation

brew install poodle64/tap/signet

For Nix (home-manager / nix-darwin), a fetchurl + SRI derivation lives in nix/signet.nix; copy it into your config and add it to home.packages.

To install manually, download the per-platform tarball and checksum from the latest release, verify, and put the binary on your PATH:

shasum -a 256 -c signet-*-*.tar.gz.sha256
tar -xzf signet-*-*.tar.gz
install -m755 signet ~/.local/bin/signet

Quickstart

# Print the hardware key's public half and enrol it with the broker (once per machine)
signet enrol

# Check hardware is detected and working
signet doctor

# Attest to a broker and get a bearer header
signet auth https://your-broker.example.internal

# Consumer pre-flight: confirm attestation and credential scope
signet verify --broker https://your-broker.example.internal --credential my-secret

# Print version
signet version

After enrol, paste the printed public key into the broker. From then on auth is the only call a consumer makes; signet handles caching, renewal, and re-attestation automatically.

Backends

signet auto-detects the available hardware. Pass --backend to override.

Backend Platform Auto-detected? --backend value
Apple Secure Enclave macOS Yes secure-enclave (aliases enclave, se)
TPM 2.0 Linux, Windows Yes (if /dev/tpmrm0 or TBS is reachable) tpm
YubiKey / PIV token macOS, Linux, Windows Fallback on Linux/Windows piv

There is no software-key fallback. A host with no secure hardware fails loudly; signet never silently degrades to a key on disk.

See Hardware backends for the security model, library details, and build-tag notes.

Features

One binary, three backends
Secure Enclave on Macs, a TPM on Linux servers, a YubiKey/PIV token anywhere; compiled in and selected at runtime, so switching hardware is a one-flag change, not a migration.
A credential helper, not a daemon
The same shape as git credential, docker-credential-*, and AWS credential_process: a consumer shells out for a fresh bearer header on demand and holds no standing secret of its own.
Nothing exportable, nothing at rest
The P-256 signing key is generated in hardware and never appears in a file, env var, log, or argv. The only persisted state is a short-lived bearer cache.
No software-key fallback, by design
A host with no secure hardware fails loudly rather than quietly degrading to a key on disk, so "this identity is hardware-rooted" is never a claim that is sometimes false.
Consumer pre-flight (verify)
Runs the full attestation round-trip and optionally probes a credential's vend scope. Exits with typed codes (0/2/3/4/5) so a health check or CI gate can branch on the exact failure mode.
Agent mode for container workloads
One daemon owns the hardware token and signs on request over Unix sockets — one socket pinned to one PIV slot — so a container attests without the token ever being mounted into it.

Wiring as a credential helper

Wire signet auth as the headersHelper in a Claude Code MCP config, or as any other credential_process-style helper. Backend selection is a flag:

{
  "mcpServers": {
    "my-broker": {
      "type": "http",
      "url": "https://your-broker.example.internal/mcp",
      "headersHelper": "signet auth https://your-broker.example.internal"
    }
  }
}

To use a specific backend: signet auth --backend piv https://your-broker.example.internal

auth prints signet's own attestation bearer: the credential that proves this machine's identity to the broker. Some hosted servers instead expect a broker-vended credential, a separate secret the broker holds on the consumer's behalf (a hosted API's bearer, an upstream service token), as their Authorization header. For that case wire signet headers instead: it attests the same way auth does, then vends the named credential and prints it as the header:

{
  "mcpServers": {
    "example-api": {
      "type": "http",
      "url": "https://your-broker.example.internal/mcp",
      "headersHelper": "signet headers --broker https://your-broker.example.internal --credential example-api"
    }
  }
}

--header and --format control the emitted JSON key and value wrapping (default Authorization / bearer), and --bare drops the JSON framing to print the value alone; the shape to interpolate into curl -H, since a JSON-wrapped value builds a malformed header and earns a 401 that looks just like a stale credential. See Usage for the full flag and exit-code reference.

Some consumers need the vended credential written to a file instead of an HTTP header: an agent placing a value at a destination (a .env, an .envrc.local, a stack secret sink) without it ever passing through a shell pipeline or an LLM transcript. signet vend-to-file attests the same way, then writes one field's value straight to disk, atomically, at mode 0600 by default:

signet vend-to-file --broker https://your-broker.example.internal example-api /etc/myapp/token

Nothing but a byte-count confirmation line ever reaches stdout; the credential value only ever lands in the destination file. See Usage for --field, --mode, --print-shape, and the full exit-code reference.

A stdio MCP server needs its credential in an environment variable before it even starts, and .mcp.json has no envHelper equivalent to headersHelper. signet exec closes that gap: it attests and vends the same way, sets the value as an environment variable on a child process, and replaces itself with that child, so the value goes straight from the broker into the child's own environment and never sits in the calling shell, an env var, or a file:

signet exec --broker https://your-broker.example.internal --credential github-pat \
  --env-var GITHUB_PERSONAL_ACCESS_TOKEN -- github-mcp-server stdio

Nothing is printed on success — the child is about to speak its own protocol on stdout — and no signet process is left running: exec replaces itself with <command> (syscall.Exec) rather than spawning a subprocess it waits on. See Usage for the -- contract and the full exit-code reference.

signet speaks the /v1/attest HTTP contract and nothing more; it is not coupled to any specific broker's business logic, and any secrets broker implementing the contract can consume it.

Documentation

Guide What it covers
Usage All ten subcommands (enrol, sign, auth, verify, headers, vend-to-file, exec, agent, doctor, version); wiring as a credential helper
Configuration Flags (--backend, --slot, --identity), backend selection, and on-disk paths
Hardware backends The Secure Enclave, TPM, and PIV backends in depth
Building from source The cgo build, the Swift shim, and the release toolchain
Contributing Build prerequisites, per-platform constraints, test commands
Security Reporting vulnerabilities and supported versions
Brand assets docs/branding/

Contributing

See CONTRIBUTING.md for build prerequisites and the per-platform native-build constraint.

make build       # builds ./signet
make test        # runs the test suite
The key that proves which machine you are; sealed in hardware, exportable to no one.
MIT Licence · Report Bug · Security

About

Cross-platform hardware-rooted signing CLI — Apple Secure Enclave, TPM 2.0, and YubiKey/PIV in one self-contained Go binary.

Topics

Resources

Contributing

Security policy

Stars

0 stars

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages