Repository navigation
Feature Guide mTLS RBAC
Control which client certificates can access which paths on mTLS-protected proxy hosts.
- Overview
- Concepts
- Setup Walkthrough
- Path-Based Access Rules
- Scoped mTLS Paths
- Trust Models
- Revocation Behaviour
- REST API
- Troubleshooting
Basic mTLS lets any client certificate signed by a trusted CA access the proxy host. mTLS RBAC adds fine-grained control:
- Roles — Named groups of client certificates (e.g. "ops", "developers", "monitoring").
- Cert-to-role assignment — Assign issued client certificates to one or more roles.
- Path-based access rules — Restrict URL paths to specific roles or individual certificates.
This lets you host multiple services behind one domain and control who reaches what.
A role is a named label attached to one or more client certificates. Roles are managed on the Certificates → Roles tab.
An access rule ties a path pattern to allowed roles and/or individual certificates. Rules are configured per proxy host in the mTLS RBAC section.
Each rule has:
-
Path pattern — Caddy path matcher (e.g.
/admin/*,/api/v1/*,/*) - Allowed roles — Roles whose certificates may access this path
- Allowed certificates — Individual certificates (in addition to roles)
- Deny all — Explicitly block all access to this path
Rules are evaluated by priority (highest first). Paths without a matching rule fall through to a default allow (any valid mTLS cert).
On the Certificates → CA / mTLS tab:
- Generate a CA if you haven't already.
- Issue client certificates for your users/services.
With Feature Guide Instance Sync, issue certificates on the master. Since v1.13.1, CA private keys are not synced. Slaves enforce mTLS with the synced CA and client certificates, but cannot issue new ones.
On the same page, switch to the Roles tab:
- Click Create New Role.
- Name it (e.g. "ops") and click Create Role.
- Assign certificates to the role.
Edit the proxy host and enable mTLS:
- Select trusted certificates or roles (the new trust model).
- In the mTLS RBAC section, add path-based access rules.
- Save.
Use curl with a client certificate:
curl --cert client.pem --key client-key.pem https://app.example.com/admin/A certificate in the "ops" role accessing /admin/* (if allowed) returns 200. A certificate not in the allowed set returns 403.
Rules are enforced at the HTTP layer (after the TLS handshake) using Caddy CEL expressions that match the client certificate's fingerprint.
Rules are ordered by priority (descending). The first matching rule wins. If no rule matches a path, any valid mTLS certificate is allowed through (backward-compatible default).
A deny-all rule blocks every client certificate for the matched path, regardless of roles. Use this for paths that should never be accessed via the proxy (e.g. internal health endpoints).
| Priority | Path | Allowed | Effect |
|---|---|---|---|
| 100 | /admin/* |
Role: ops | Only "ops" certs reach admin |
| 90 | /api/* |
Role: ops, Role: developers | Both roles reach API |
| 80 | /internal/* |
Deny all | No cert can access /internal |
| — | /* |
(default) | Any valid cert passes |
mTLS enforcement can be scoped to specific paths using protected paths or excluded paths. This is configured in the proxy host editor, in the mTLS section.
mTLS is required only on the listed path prefixes. All other paths are accessible without a client certificate. Use this when you want to restrict only certain parts of a site (e.g. an admin area) to cert holders while leaving the rest public.
mTLS is required everywhere except the listed path prefixes. The excluded paths are accessible without a client certificate. Use this when most of the site should be protected but specific paths (health checks, webhooks, public APIs) must remain open.
| Mode | Use case |
|---|---|
| Protected paths | Restrict certain admin paths to cert holders while keeping the rest public |
| Excluded paths | Protect most of the site but expose specific public paths (health checks, webhooks) |
| No scoping (default) | All paths require a valid client certificate |
Scoped paths are evaluated at the Caddy routing layer, before RBAC rules. A request to an unscoped path bypasses mTLS entirely.
CPM supports two trust models for mTLS on a proxy host:
Select individual certificates or roles. CPM derives the CAs automatically and pins to the selected leaf certificates. This is more restrictive — only the explicitly selected certificates pass the TLS handshake.
Since v1.13.1, hosts get separate TLS client-authentication policies when their trusted CAs or their pinned certificates differ. Two hosts that pin different certificates from the same CA therefore each accept only their own certificates in the handshake. In v1.12.0 and earlier, hosts with the same CA set shared one policy, which trusted the certificates pinned by all of them.
Select entire CAs. Any non-revoked certificate signed by those CAs passes the TLS handshake. RBAC rules then control path-level access.
The cert-based model is recommended for new setups.
When a client certificate is revoked:
- The certificate is removed from the active leaf cert list.
- Caddy config is regenerated and applied immediately.
- The revoked certificate can no longer complete the TLS handshake.
Fail-closed: If all certificates for a CA are revoked, all connections to that domain are rejected. CPM does not silently downgrade to no-mTLS.
mTLS RBAC is fully manageable via the REST API (admin only):
-
GET /api/v1/mtls-roles— List all roles -
POST /api/v1/mtls-roles— Create a role -
GET /api/v1/mtls-roles/:id— Get a role with the IDs of its certificates -
PUT /api/v1/mtls-roles/:id— Update a role -
DELETE /api/v1/mtls-roles/:id— Delete a role -
POST /api/v1/mtls-roles/:id/certificates— Add a certificate to a role -
DELETE /api/v1/mtls-roles/:id/certificates/:certId— Remove a certificate from a role -
GET /api/v1/proxy-hosts/:id/mtls-access-rules— List access rules for a host -
POST /api/v1/proxy-hosts/:id/mtls-access-rules— Add an access rule -
GET|PUT|DELETE /api/v1/proxy-hosts/:id/mtls-access-rules/:ruleId— Read, update or delete a rule
See /api-docs for full schemas.
- Check the certificate's fingerprint matches an allowed role or direct cert in the rule.
- Verify rule priority — a higher-priority deny rule may be matching first.
- Confirm the certificate is assigned to the correct role on the Roles tab.
This is expected (fail-closed). Re-issue a certificate or change the proxy host's trust configuration.
Only non-revoked certificates from managed CAs appear. Check the certificate's status on the CA / mTLS tab.
If issuing fails with "The CA private key cannot be decrypted with the current SESSION_SECRET. Restore the previous secret via SESSION_SECRET_PREVIOUS or create a new CA.", or if the CA offers no option to issue (a CA imported without its key, or any CA on an Instance Sync slave), see Certificate Management.
- Certificate Management - CA and certificate operations
- Feature Guide Proxy Hosts - Proxy host configuration
- Feature Guide Instance Sync - What slaves receive of your CAs
- Security Configuration - Production security hardening
Need help? Open an issue with your mTLS configuration and Caddy logs.