Skip to content

Security: Kentrow/keymaker

SECURITY.md

Security policy

Keymaker handles OVHcloud API credentials and can revoke keys. Security reports are welcome and taken seriously.

Supported versions

From 1.0, the latest minor release of the latest major version receives security fixes, as the latest minor release did during 0.x. A release in 1.x changes nothing that the compatibility promise covers, so moving to the latest one is always safe. Upgrade to it before reporting, and mention the version you run (keymaker --version).

Reporting a vulnerability

Report vulnerabilities privately, through GitHub's private vulnerability reporting:

https://github.com/kentrow/keymaker/security/advisories/new

Never open a public issue, discussion or pull request for a vulnerability.

Never send a real credential, not in a report, a log excerpt or a screenshot: no application key, application secret, consumer key or ovh.conf content. If a report needs one to be reproduced, describe the access rules it had instead. If a credential was exposed, revoke it on OVHcloud first.

A useful report includes the version, how Keymaker runs (image, Compose, source), the steps to reproduce, the impact you expect, and any proof of concept that uses placeholder values.

What to expect

Keymaker is maintained by one person, in their own time.

  • Acknowledgement within 7 days.
  • An assessment, and a fix or mitigation plan, as soon as the issue is understood, typically within 30 days.
  • A GitHub security advisory published with the fix. Reporters are credited unless they ask not to be.

Scope

In scope: Keymaker itself, meaning the code in this repository, the container image published at ghcr.io/kentrow/keymaker and its documented configuration.

Out of scope:

  • The OVHcloud API, its authentication, the createToken page and any other OVHcloud service. Report those to OVHcloud.
  • An attacker who already controls the machine running Keymaker or can read its configuration file.
  • A key after it has been created and deployed elsewhere.
  • Deployments that ignore the documented setup, for example publishing the port on a routable address.

Security model in brief

The details, and how each point is implemented, are in docs/ARCHITECTURE.md.

  • Local and single-user. Anyone who can reach the interface can act with the management credential. The binary listens on 127.0.0.1 by default. The image listens on 0.0.0.0 inside its network namespace, so the host-side port mapping must be bound to 127.0.0.1.
  • Access token. A random token is generated at every start, printed once in the startup address, and required on every route except GET /healthz, whose body is a fixed ok.
  • Page token. Every mutation requires a second token in a custom header, so a page from another origin, including another local service, cannot drive a revocation.
  • Browser hardening. A strict content security policy without unsafe-inline or unsafe-eval, framing forbidden, no referrer, no resource loaded from outside the binary.
  • No persistence. Nothing is written to disk. The configuration file is read-only. Keys created through Keymaker are issued on the OVHcloud page, and their values never reach the process.
  • Redacted logs. The application secret and the consumer key are removed from every log record by the logging pipeline itself.
  • Revocation guards. The ordinary revocation and the bulk revocation refuse the credential Keymaker authenticates with, checked against the API at the moment of the call. It can only be ended on purpose, through its own way out, "Revoke and leave", which names no key. A single revocation requires the identifier to be typed. The bulk revocation only touches expired and refused keys, selected by the server.
  • Address guard. The credential Keymaker authenticates with is only restricted to a list covering the address the process is seen from, looked up at the moment of the change. With the lookup switched off, it is not restricted from here at all.
  • Closed outbound set. The OVHcloud API of the configured endpoint, and api.ipify.org only when the reader asks for the public address or restricts the key Keymaker uses. KEYMAKER_IP_LOOKUP=off removes that call.
  • Least privilege. The management key needs read rules on credentials and applications, and optional delete rules. The rule that changes the addresses of a key is left out of the key Keymaker suggests, since it can widen the reach of any key. Never grant it /me/* or /*.
  • Hardened image. Distroless, non-root, meant to run with a read-only filesystem, no capabilities and no-new-privileges.

Operational advice

  • Run the container as documented: port published on 127.0.0.1, configuration mounted read-only, --read-only, --cap-drop=ALL, --security-opt no-new-privileges.
  • Keep ovh.conf out of version control and readable by its owner only (chmod 600), and run the container as that owner with --user rather than widening the file permissions.
  • Give the management key an expiration, restrict it to your address, and leave out the delete rule if you only need the inventory.
  • The startup log contains the access token. Treat that output as sensitive for as long as the process runs.

There aren't any published security advisories