Skip to content

[proxy] Add mTLS auth support for reverse proxy services#6048

Open
marcschwaiger wants to merge 6 commits intonetbirdio:mainfrom
marcschwaiger:feature/mtls-auth
Open

[proxy] Add mTLS auth support for reverse proxy services#6048
marcschwaiger wants to merge 6 commits intonetbirdio:mainfrom
marcschwaiger:feature/mtls-auth

Conversation

@marcschwaiger
Copy link
Copy Markdown

@marcschwaiger marcschwaiger commented May 1, 2026

Describe your changes

Add mTLS authentication for reverse proxy services

Issue ticket number and link

#5364 mTLS Auth for Proxy Services

Stack

Checklist

  • Is it a bug fix
  • Is a typo/documentation fix
  • Is a feature enhancement
  • It is a refactor
  • Created tests that fail without the change (if possible)

By submitting this pull request, you confirm that you have read and agree to the terms of the Contributor License Agreement.

Documentation

Select exactly one:

  • I added/updated documentation for this change
  • Documentation is not needed for this change (explain why)

Docs PR URL (required if "docs added" is checked)

Paste the PR link from https://github.com/netbirdio/docs here:

netbirdio/docs#720

See also: Dashboard PR URL

netbirdio/dashboard#628

Summary by CodeRabbit

  • New Features

    • Per-domain mutual TLS (mTLS) support with configurable client CA pools and server TLS behavior.
    • Service configuration, API, and proto now accept mTLS auth settings.
  • Bug Fixes

    • Preserve existing mTLS CA certificate when updating a service without providing a new CA PEM.
  • Tests

    • Added extensive mTLS unit/integration tests covering validation, middleware, and TLS configuration.
  • Documentation

    • OpenAPI/types updated to expose mtls_auth fields.

@CLAassistant
Copy link
Copy Markdown

CLAassistant commented May 1, 2026

CLA assistant check
All committers have signed the CLA.

@coderabbitai
Copy link
Copy Markdown
Contributor

coderabbitai Bot commented May 1, 2026

Note

Reviews paused

It looks like this branch is under active development. To avoid overwhelming you with review comments due to an influx of new commits, CodeRabbit has automatically paused this review. You can configure this behavior by changing the reviews.auto_review.auto_pause_after_reviewed_commits setting.

Use the following commands to manage reviews:

  • @coderabbitai resume to resume automatic reviews.
  • @coderabbitai review to trigger a single review.

Use the checkboxes below for quick actions:

  • ▶️ Resume reviews
  • 🔍 Trigger review
📝 Walkthrough

Walkthrough

Adds mutual TLS (mTLS) support across management and proxy: new MTLS types and API/proto fields, service-side CA PEM validation and preservation, per-domain mTLS enforcement and client cert validation in the proxy, TLS SNI-based client-CA selection, and related tests.

Changes

mTLS Authentication Support (End-to-End)

Layer / File(s) Summary
Data Shape & Types
management/internals/modules/reverseproxy/service/service.go, shared/management/http/api/types.gen.go, shared/management/proto/proxy_service.proto, proxy/auth/auth.go, proxy/internal/auth/mtls.go
Introduces MTLSAuthConfig/MTLSAuth in service types, API DTOs, and protobuf; adds MethodMTLS constant; introduces MTLSConfig with CA pool in proxy.
Validation & Parsing
management/internals/modules/reverseproxy/service/service.go, proxy/internal/auth/mtls.go
Service validation now validates enabled mTLS requires non-empty valid CA PEM; proxy provides NewMTLSConfig and parseClientCAPEM to build CA pools and produce descriptive parse/validation errors.
Manager Preservation & API Mapping
management/internals/modules/reverseproxy/service/manager/manager.go, management/internals/modules/reverseproxy/service/service.go
preserveExistingAuthSecrets now preserves existing MTLSAuth.CACertPEM when update has enabled MTLS but empty PEM; API ↔ internal conversions and proto mappings include mtls fields and redaction rules for API responses.
Proxy Middleware & Domain Wiring
proxy/internal/auth/middleware.go, proxy/internal/auth/mtls.go
DomainConfig gains MTLS *MTLSConfig; Middleware.AddDomain refactored to AddDomainOptions including MTLS; Protect now runs checkMTLS after IP checks and before auth schemes; GetClientCAPool exposes per-host CA pool; validateClientCertificate implements verification.
Server TLS SNI Behavior
proxy/server.go
configureTLS adds GetConfigForClient hook to select per-SNI client CA pools (requests client certs for mTLS-enabled SNI); mapping updates create MTLSConfig and pass it into domain registration.
Tests / Integration
management/internals/modules/reverseproxy/service/manager/manager_test.go, management/internals/modules/reverseproxy/service/service_test.go, proxy/internal/auth/middleware_test.go, proxy/server_test.go, proxy/management_integration_test.go
Adds PEM-generating helpers and extensive tests: manager preserves CA PEM, service validation/redaction/proto mapping, middleware mTLS success/failure cases, server TLS per-SNI client CA behavior, and many tests adapted to AddDomainOptions.

Sequence Diagram

sequenceDiagram
    participant Client
    participant TLS as TLS Handler (SNI)
    participant AuthMW as Auth Middleware
    participant Validator as Cert Validator
    participant App as Request Handler

    Client->>TLS: TCP/TLS ClientHello (SNI)
    TLS->>AuthMW: GetClientCAPool(hello.ServerName)
    AuthMW-->>TLS: CA Pool (if configured)
    TLS->>Client: Server requests client cert (if pool present)
    Client->>TLS: Present Client Certificate
    TLS->>AuthMW: HTTP request + TLS state
    AuthMW->>Validator: validateClientCertificate(req, mtlsConfig)
    alt MTLS not enabled
        Validator-->>AuthMW: OK (pass-through)
        AuthMW->>App: Continue (no mTLS)
        App-->>Client: 200 OK
    else Valid client cert
        Validator-->>AuthMW: OK (verified)
        AuthMW->>App: Continue (record mTLS auth)
        App-->>Client: 200 OK
    else Invalid or missing cert
        Validator-->>AuthMW: Error
        AuthMW-->>Client: 401 Unauthorized
    end
Loading

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~45 minutes

Possibly related PRs

Suggested reviewers

  • lixmal
  • pascal-fischer
  • mlsmaycon

Poem

🐰 A hop, a CA, a cert in hand,

Through SNI the rabbit planned,
Client certs checked, trust pooled tight,
Middleware guards the TLS night,
Hooray—mTLS now guards the land!

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 2.94% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (4 passed)
Check name Status Explanation
Title check ✅ Passed The title clearly and specifically describes the main feature added: mTLS authentication support for reverse proxy services, accurately representing the primary change across all modified files.
Description check ✅ Passed The description includes all required template sections: change description, issue reference, checklist (marked as feature enhancement and tests created), CLA confirmation, documentation update with docs PR link, and related dashboard PR link.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

Copy link
Copy Markdown
Contributor

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 2

🧹 Nitpick comments (1)
shared/management/http/api/openapi.yml (1)

3330-3333: ⚡ Quick win

Mark ca_cert_pem as writeOnly to reflect secret-handling intent.

Given the “cleared in responses” behavior, adding writeOnly: true improves generated client/docs safety and reduces accidental exposure risk.

Proposed OpenAPI update
         ca_cert_pem:
           type: string
+          writeOnly: true
           description: Trusted client CA certificate bundle in PEM format. Required on create when mTLS is enabled. Cleared in responses.
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@shared/management/http/api/openapi.yml` around lines 3330 - 3333, The schema
property ca_cert_pem is marked as sensitive ("cleared in responses") but not
declared writeOnly; update the OpenAPI schema for the ca_cert_pem property to
include writeOnly: true so generated clients/docs won't expose it in responses
or outputs. Locate the ca_cert_pem property in the OpenAPI YAML and add the
writeOnly flag alongside type/description/example for the ca_cert_pem field.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@proxy/server.go`:
- Around line 584-585: The TLS config currently only sets tls.RequestClientCert
which asks for certs but does not advertise acceptable CAs; wire the per-domain
CA pools created in updateMapping back into the TLS handshake by populating
tlsConfig.ClientCAs or by implementing tlsConfig.GetConfigForClient to return a
per-SNI tls.Config that sets ClientCAs and ClientAuth accordingly; locate the
mapping/store that updateMapping populates and use its CA pool for the matching
serverName in GetConfigForClient (or set the global tlsConfig.ClientCAs when a
single CA set is appropriate) so valid clients will see the acceptable CAs and
send certificates (avoid relying on test-injected req.TLS).

In `@shared/management/http/api/openapi.yml`:
- Around line 3330-3338: The schema allows enabled: true without a CA bundle;
update the OpenAPI schema for the object that declares enabled and ca_cert_pem
to add a conditional requirement so that when enabled is true the ca_cert_pem
field is required (use JSON Schema if/then or oneOf pattern): add an "if" that
checks properties.enabled: { const: true } and a corresponding "then" that sets
required: ["ca_cert_pem"], leaving the existing optional behavior when enabled
is false; target the same schema that defines the ca_cert_pem and enabled
properties to implement this validation.

---

Nitpick comments:
In `@shared/management/http/api/openapi.yml`:
- Around line 3330-3333: The schema property ca_cert_pem is marked as sensitive
("cleared in responses") but not declared writeOnly; update the OpenAPI schema
for the ca_cert_pem property to include writeOnly: true so generated
clients/docs won't expose it in responses or outputs. Locate the ca_cert_pem
property in the OpenAPI YAML and add the writeOnly flag alongside
type/description/example for the ca_cert_pem field.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: c30ae9f5-0ea5-4a59-b948-13611c159e1d

📥 Commits

Reviewing files that changed from the base of the PR and between c4b2da4 and d07e00e.

⛔ Files ignored due to path filters (1)
  • shared/management/proto/proxy_service.pb.go is excluded by !**/*.pb.go
📒 Files selected for processing (13)
  • management/internals/modules/reverseproxy/service/manager/manager.go
  • management/internals/modules/reverseproxy/service/manager/manager_test.go
  • management/internals/modules/reverseproxy/service/service.go
  • management/internals/modules/reverseproxy/service/service_test.go
  • proxy/auth/auth.go
  • proxy/internal/auth/middleware.go
  • proxy/internal/auth/middleware_test.go
  • proxy/internal/auth/mtls.go
  • proxy/management_integration_test.go
  • proxy/server.go
  • shared/management/http/api/openapi.yml
  • shared/management/http/api/types.gen.go
  • shared/management/proto/proxy_service.proto

Comment thread proxy/server.go Outdated
Comment thread shared/management/http/api/openapi.yml
@marcschwaiger marcschwaiger marked this pull request as ready for review May 2, 2026 17:36
Copy link
Copy Markdown
Contributor

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 1

🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@proxy/server.go`:
- Around line 602-603: The base TLS config currently sets tlsConfig.ClientAuth =
tls.RequestClientCert and calls configureClientCAs globally; remove that global
ClientAuth change (leave default NoClientCert) and stop calling
configureClientCAs at the top-level so non-mTLS domains aren't asked for certs.
Instead, set tlsConfig.ClientAuth = tls.RequestClientCert and call
configureClientCAs only inside the per-SNI logic in GetConfigForClient (the
branch that matches mTLS hosts), so client cert requests are applied only for
matched mTLS hosts.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: 32ee855b-614c-4170-8239-394729690501

📥 Commits

Reviewing files that changed from the base of the PR and between d07e00e and 443a090.

📒 Files selected for processing (6)
  • proxy/internal/auth/middleware.go
  • proxy/internal/auth/middleware_test.go
  • proxy/management_integration_test.go
  • proxy/server.go
  • proxy/server_test.go
  • shared/management/http/api/openapi.yml
🚧 Files skipped from review as they are similar to previous changes (1)
  • shared/management/http/api/openapi.yml

Comment thread proxy/server.go Outdated
@marcschwaiger marcschwaiger changed the title Add mTLS auth support for reverse proxy services [proxy] Add mTLS auth support for reverse proxy services May 2, 2026
Copy link
Copy Markdown
Contributor

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

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

🧹 Nitpick comments (1)
proxy/internal/auth/middleware.go (1)

116-124: 💤 Low value

Consider updating the comment to reflect mTLS check.

The comment on line 120 states domains "pass through after IP checks" but now they also pass through after the mTLS check. This could be clarified for accuracy.

📝 Suggested comment update
-	// Domains with no authentication schemes pass through after IP checks.
+	// Domains with no authentication schemes pass through after IP and mTLS checks.
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@proxy/internal/auth/middleware.go` around lines 116 - 124, Update the inline
comment above the config.Schemes check to accurately reflect that domains with
no authentication schemes are allowed to pass through after both IP and mTLS
checks; specifically edit the comment near mw.checkMTLS(...) and the block that
calls next.ServeHTTP(w, r) when len(config.Schemes) == 0 so it mentions mTLS in
addition to IP checks.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Nitpick comments:
In `@proxy/internal/auth/middleware.go`:
- Around line 116-124: Update the inline comment above the config.Schemes check
to accurately reflect that domains with no authentication schemes are allowed to
pass through after both IP and mTLS checks; specifically edit the comment near
mw.checkMTLS(...) and the block that calls next.ServeHTTP(w, r) when
len(config.Schemes) == 0 so it mentions mTLS in addition to IP checks.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: 910d4947-b599-4224-bec7-b02b0a8d7846

📥 Commits

Reviewing files that changed from the base of the PR and between 611b915 and 4e1f2e0.

📒 Files selected for processing (4)
  • proxy/internal/auth/middleware.go
  • proxy/internal/auth/mtls.go
  • proxy/server.go
  • proxy/server_test.go
✅ Files skipped from review due to trivial changes (1)
  • proxy/server_test.go
🚧 Files skipped from review as they are similar to previous changes (2)
  • proxy/internal/auth/mtls.go
  • proxy/server.go

@sonarqubecloud
Copy link
Copy Markdown

sonarqubecloud Bot commented May 2, 2026

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants