Skip to content

Authenticate every request by client certificate - #457

Open
silug wants to merge 2 commits into
OpenVoxProject:mainfrom
silug:harden-cert-authn
Open

Authenticate every request by client certificate#457
silug wants to merge 2 commits into
OpenVoxProject:mainfrom
silug:harden-cert-authn

Conversation

@silug

@silug silug commented Aug 4, 2026

Copy link
Copy Markdown
Contributor

Pull Request (PR) description

OpenVoxDB accepted any request that reached it whenever [puppetdb] certificate-allowlist was unset, because wrap-cert-authn returned the handler unwrapped in that case. The HTTPS listener is configured with client-auth = want rather than need, so a client presenting no certificate at all could read the whole database, submit commands for any certname, and delete node data.

The allowlist was also bypassed for cleartext requests, since kitchensink's cn-whitelist->authorizer authorizes any request whose scheme is :http. An operator who configured an allowlist got no enforcement on the cleartext port, and no indication of that.

Authentication is now always applied. A request must present a certificate signed by OpenVoxDB's CA, and where an allowlist is configured its CN must appear there, with the allowlist checked locally rather than through the scheme-sensitive kitchensink helper.

A cleartext connection cannot present a certificate, so cleartext requests are exempt only when they come from a loopback address, which is what the shipped configuration expects: [jetty] host defaults to localhost and the port exists for local administration and the performance dashboard. Operators who terminate authentication elsewhere, such as behind a reverse proxy on another host, can set the new [puppetdb] allow-unauthenticated-cleartext to exempt the port entirely; that logs a warning at startup.

This is a breaking change for deployments that rely on unauthenticated access: anonymous HTTPS clients and remote cleartext clients are now rejected with a 403 rather than served.

Generated by Claude Code

This Pull Request (PR) fixes the following issues

N/A

OpenVoxDB accepted any request that reached it whenever [puppetdb]
certificate-allowlist was unset, because wrap-cert-authn returned the
handler unwrapped in that case. The HTTPS listener is configured with
client-auth = want rather than need, so a client presenting no
certificate at all could read the whole database, submit commands for
any certname, and delete node data.

The allowlist was also bypassed for cleartext requests, since
kitchensink's cn-whitelist->authorizer authorizes any request whose
scheme is :http. An operator who configured an allowlist got no
enforcement on the cleartext port, and no indication of that.

Authentication is now always applied. A request must present a
certificate signed by OpenVoxDB's CA, and where an allowlist is
configured its CN must appear there, with the allowlist checked
locally rather than through the scheme-sensitive kitchensink helper.

A cleartext connection cannot present a certificate, so cleartext
requests are exempt only when they come from a loopback address, which
is what the shipped configuration expects: [jetty] host defaults to
localhost and the port exists for local administration and the
performance dashboard. Operators who terminate authentication elsewhere,
such as behind a reverse proxy on another host, can set the new
[puppetdb] allow-unauthenticated-cleartext to exempt the port entirely;
that logs a warning at startup.

This is a breaking change for deployments that rely on unauthenticated
access: anonymous HTTPS clients and remote cleartext clients are now
rejected with a 403 rather than served.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Signed-off-by: Steven Pritchard <steven.pritchard@gmail.com>
@silug silug added the backwards-incompatible This change will lead to a major version bump for the next release label Aug 4, 2026
@silug
silug requested a lite review from Copilot August 4, 2026 19:31

Copilot AI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

This PR closes authentication bypasses by ensuring certificate-based authentication is enforced consistently, including when the certificate allowlist is unset and for requests arriving over cleartext HTTP.

Changes:

  • Reworks wrap-cert-authn to always require a client certificate (and optionally enforce a CN allowlist), independent of request scheme.
  • Adds a loopback-only exemption for cleartext HTTP plus a new allow-unauthenticated-cleartext config override (with startup warning).
  • Updates tests and documentation to reflect the new authentication behavior and configuration.

Reviewed changes

Copilot reviewed 7 out of 7 changed files in this pull request and generated 3 comments.

Show a summary per file
File Description
test/puppetlabs/puppetdb/middleware_test.clj Expands middleware tests to cover allowlist behavior, unauthenticated HTTPS rejection, and cleartext exemptions.
src/puppetlabs/puppetdb/pdb_routing.clj Wires new allow-unauthenticated-cleartext setting into middleware and logs a warning when enabled.
src/puppetlabs/puppetdb/middleware.clj Implements always-on cert authentication, allowlist enforcement independent of scheme, and loopback logic for cleartext.
src/puppetlabs/puppetdb/config.clj Introduces allow-unauthenticated-cleartext configuration key and schema output type.
documentation/maintain_and_tune.markdown Updates dashboard access guidance to account for loopback-only cleartext behavior and new config option.
documentation/configure.markdown Documents allowlist behavior and adds docs for allow-unauthenticated-cleartext.
config.sample.ini Adds the new allow-unauthenticated-cleartext option to the sample config.

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment thread src/puppetlabs/puppetdb/middleware.clj Outdated
Comment thread src/puppetlabs/puppetdb/config.clj
Comment thread src/puppetlabs/puppetdb/middleware.clj Outdated
Make reject-unauthenticated-request and loopback-request? private, as
both are only used within middleware.clj, and cover the defaulting and
boolean coercion of allow-unauthenticated-cleartext in config-test.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Signed-off-by: Steven Pritchard <steven.pritchard@gmail.com>
@silug
silug marked this pull request as ready for review August 4, 2026 19:59
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

backwards-incompatible This change will lead to a major version bump for the next release

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants