Machine identity: how a service proves it is itself
Short answer: a token in an environment variable is not an identity — it is a password without an owner: you cannot revoke it for one service, you cannot tell who used it, and anyone who sees the configuration can copy it. A machine identity is a separate entity with its own way of signing in, its own token lifetime and its own scope: a project, an environment and, if you want, a list of keys. In env-master a client secret can be revoked, an access token lives for minutes, an enrollment token lives for minutes and exactly one use — and trading a one-time token twice is treated as a leak and raises an alert.
Why “a token in env” is not an identity
A shared token for every service (or every environment) solves the access problem at the cost of three losses. First, you cannot revoke it for a single consumer — you have to change it for all of them. Second, the log cannot tell who presented it: the billing worker or whoever pulled it off a compromised host. Third, a token with no expiry found in a year-old backup still works. An identity instead of a token means every consumer has its own credentials, its own lifetime and its own zone of access — all visible separately in the audit trail.
What an identity in env-master is made of
A service is a first-class entity, not a side product of a token. Identities are bound to it, and each has its own contract:
- a way to sign in — Universal Auth trades a client id and secret for a short-lived token; an enrollment token is issued for initial registration and lives for minutes;
- a lifetime — the access token is measured in minutes and the SDK renews it itself; a stolen access token expires faster than it can be put to use;
- a scope — a project, an environment and, if needed, a list of keys: the
billing service gets
DB_*, not the whole of production; an IP allowlist is available on top.
A client secret is shown exactly once: only its hash remains in the database, so a lost secret is not recovered but reissued — recovery would be a sign that the secret is stored in the clear somewhere.
A repeat is a signal, not an error
An enrollment token is one-time by construction: the capture is atomic
(compare-and-set), and a second exchange attempt means two parties hold it. The
system does not merely refuse: the losing attempt raises an
enrollment.reuse-detected event and a webhook to the administrators. The same
principle applies to refresh tokens: presenting an already-rotated token kills
the sessions, because the only legitimate explanation is a race — and every
other one is theft. Details are in the threat model.
Scoping down to a key set is what makes the model grown-up
Access granularity usually ends at the environment: a production token sees all
of production. That turns every service into a potential source of a full
environment leak. Scoping to a key set changes the risk arithmetic: compromising
the reporting worker hands the attacker the reporting keys, not the main
database password and the payment provider tokens. Combined with
restricted visibility — a value never shown to a person
at all — you get a secret held by neither people nor unnecessary machines.
Where the trust boundary lies
The machine path in env-master is honestly client-side: the SDK receives ciphertext plus the environment key wrapped with x25519 under the specific identity's public key, and decrypts locally — the server never produces the plaintext in this scenario. At the same time the system is not zero-knowledge and does not claim to be: values shown to a person in the dashboard are decrypted on the server. We believe a precise statement of the boundary is more useful than a pretty term — so it is written in plain words on the security page.
Issuing a first identity takes minutes: a project, an environment, a service, a scope. From there the service fetches its secrets on its own, with no files and no humans in the delivery chain — see the quickstart.