Skip to content

Add support for External Authentication for HTTPRoutes#5145

Merged
salonichf5 merged 8 commits intomainfrom
feat/external-auth
May 6, 2026
Merged

Add support for External Authentication for HTTPRoutes#5145
salonichf5 merged 8 commits intomainfrom
feat/external-auth

Conversation

@salonichf5
Copy link
Copy Markdown
Contributor

Proposed changes

Write a clear and concise description that helps reviewers understand the purpose and impact of your changes. Use the
following format:

Problem: Users want to be able to specify the external authorization backends for their HTTPRoutes

Solution: Adds support for external authentication filter for HTTPRoutes.

Testing: Describe any testing that you did.

Please focus on (optional): If you any specific areas where you would like reviewers to focus their attention or provide
specific feedback, add them here.

Closes #5134

Checklist

Before creating a PR, run through this checklist and mark each as complete.

  • I have read the CONTRIBUTING doc
  • I have added tests that prove my fix is effective or that my feature works
  • I have checked that all unit tests pass after adding my changes
  • I have updated necessary documentation
  • I have rebased my branch onto main
  • I will ensure my PR is targeting the main branch and pulling from my branch from my own fork

Release notes

If this PR introduces a change that affects users and needs to be mentioned in the release notes,
please add a brief note that summarizes the change.

Adds support for External Authentication using [HTTPExternalAuthFilter](https://gateway-api.sigs.k8s.io/reference/spec/#httpexternalauthfilter) for HTTPRoutes.

@codecov
Copy link
Copy Markdown

codecov Bot commented Apr 17, 2026

Codecov Report

❌ Patch coverage is 93.68421% with 18 lines in your changes missing coverage. Please review.
✅ Project coverage is 85.83%. Comparing base (e70e93c) to head (4484af4).

Files with missing lines Patch % Lines
internal/controller/state/graph/httproute.go 74.46% 10 Missing and 2 partials ⚠️
internal/controller/state/graph/backend_refs.go 94.93% 2 Missing and 2 partials ⚠️
...ternal/controller/state/dataplane/configuration.go 94.44% 1 Missing and 1 partial ⚠️
Additional details and impacted files
@@            Coverage Diff             @@
##             main    #5145      +/-   ##
==========================================
+ Coverage   85.76%   85.83%   +0.06%     
==========================================
  Files         150      150              
  Lines       20601    20815     +214     
  Branches       35       35              
==========================================
+ Hits        17669    17866     +197     
- Misses       2578     2590      +12     
- Partials      354      359       +5     

☔ View full report in Codecov by Sentry.
📢 Have feedback on the report? Share it here.

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.
  • 📦 JS Bundle Analysis: Save yourself from yourself by tracking and limiting bundle sizes in JS merges.

Copy link
Copy Markdown

Copilot AI left a comment

Choose a reason for hiding this comment

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

Pull request overview

Adds initial support for Gateway API HTTPRoute HTTPExternalAuthFilter by plumbing the filter through graph/state resolution into the dataplane model and NGINX config generation, plus adding tests and examples.

Changes:

  • Add ExternalAuth filter parsing/validation and route backend-ref tracking for HTTPRoutes.
  • Convert resolved ExternalAuth config into dataplane types and render NGINX auth_request plus internal auth subrequest locations.
  • Add unit/integration-style tests and an examples/external-authentication manifest set.

Reviewed changes

Copilot reviewed 22 out of 22 changed files in this pull request and generated 5 comments.

Show a summary per file
File Description
internal/controller/state/graph/route_common.go Adds tracking for ExternalAuth filter backend-ref indices.
internal/controller/state/graph/common_filter.go Introduces ExternalAuth filter type, conversion, validation, and duplicate handling.
internal/controller/state/graph/httproute.go Collects ExternalAuth backendRefs and validates conflicts with ClientSettingsPolicy body sizing.
internal/controller/state/graph/graph.go Invokes ExternalAuth-vs-policy conflict validation during graph build.
internal/controller/state/graph/backend_refs.go Marks external-auth backends and excludes them from certain backend-TLS consistency checks.
internal/controller/state/dataplane/types.go Adds dataplane representation for ExternalAuth filter.
internal/controller/state/dataplane/convert.go Converts Gateway API ExternalAuth filter + resolved backend into dataplane config.
internal/controller/state/dataplane/configuration.go Wires ExternalAuth filter into HTTP filter creation and skips ext-auth backends in backend groups.
internal/controller/nginx/config/http/config.go Extends location model to carry external auth config + body sizing + proxy body forwarding toggle.
internal/controller/nginx/config/servers.go Generates auth_request locations and updates locations with external auth config.
internal/controller/nginx/config/servers_template.go Renders auth_request, auth_request_set, client_max_body_size, and proxy_pass_request_body.
internal/controller/state/graph/*_test.go Adds unit tests for filter validation, duplicates, and route/policy conflicts.
internal/controller/state/dataplane/*_test.go Adds conversion and filter-creation tests for ExternalAuth.
internal/controller/nginx/config/servers_test.go Adds NGINX rendering coverage for ExternalAuth scenarios (headers/body/TLS/mirror).
examples/external-authentication/* Adds example manifests and a short README linking to docs.

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

Comment thread internal/controller/state/graph/common_filter.go
Comment thread internal/controller/state/graph/common_filter.go
Comment thread internal/controller/state/graph/common_filter.go Outdated
Comment thread internal/controller/state/graph/common_filter.go Outdated
Comment thread internal/controller/state/graph/httproute.go Outdated
@salonichf5 salonichf5 force-pushed the feat/external-auth branch 3 times, most recently from 31dfc56 to 5e62429 Compare April 17, 2026 21:45
@salonichf5 salonichf5 marked this pull request as ready for review April 17, 2026 21:45
@salonichf5 salonichf5 requested a review from a team as a code owner April 17, 2026 21:45
Copy link
Copy Markdown
Collaborator

@sjberman sjberman left a comment

Choose a reason for hiding this comment

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

Did you manually verify that BackendTLSPolicy works with the auth server?

Comment thread internal/controller/nginx/config/http/config.go
Comment thread internal/controller/nginx/config/servers_template.go
Comment thread internal/controller/state/dataplane/configuration.go
Comment thread internal/controller/state/dataplane/convert.go Outdated
Comment thread internal/controller/state/dataplane/types.go
Comment thread internal/controller/nginx/config/servers_template.go
Comment thread internal/controller/state/graph/backend_refs.go Outdated
Comment thread internal/controller/state/graph/common_filter.go
Comment thread internal/controller/state/graph/common_filter.go Outdated
Copy link
Copy Markdown
Contributor

@bjee19 bjee19 left a comment

Choose a reason for hiding this comment

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

nice job looks pretty good to me, just one question, and i'll wait for other comments to be resolved, then i'll re-review the changes

Comment thread internal/controller/state/graph/common_filter.go Outdated
Comment thread internal/controller/state/dataplane/configuration.go
@salonichf5
Copy link
Copy Markdown
Contributor Author

salonichf5 commented Apr 21, 2026

@sjberman @bjee19

Follow-up on the BTP verification

I had initially confirmed BTP behavior on the upstream and validated that we could authorize requests against it. Code review feedback surfaced that external auth can also have its own BTP, so I went back and tested this, the same BTP applied to both the secure app and external-auth backends works as expected.
I had misunderstood how subrequests handle inheritance from the main request block they don't automatically inherit everything, as I had assumed

Note: used the same BTP for both services secure-app and external-auth

NGINX conf

server {
    listen 80;
    listen [::]:80;

    server_name secure-app.example.com;

    location /coffee/ {
        client_max_body_size 1024;
        auth_request /_ngf-internal-ext-auth-default_secure-app_rule0;
        auth_request_set $ext_auth_response_x_user_id $upstream_http_x_user_id;
        proxy_set_header X-User-Id $ext_auth_response_x_user_id;
        proxy_pass https://default_secure-app_8443;

        proxy_ssl_server_name on;
        proxy_ssl_verify on;
        proxy_ssl_name secure-app.example.com;
        proxy_ssl_trusted_certificate /etc/nginx/secrets/cert_bundle_default_backend-cert.crt;
    }
    location = /coffee {
        client_max_body_size 1024;
        auth_request /_ngf-internal-ext-auth-default_secure-app_rule0;
        auth_request_set $ext_auth_response_x_user_id $upstream_http_x_user_id;
        proxy_set_header X-User-Id $ext_auth_response_x_user_id;

        proxy_pass https://default_secure-app_8443;
        proxy_ssl_server_name on;
        proxy_ssl_verify on;
        proxy_ssl_name secure-app.example.com;
        proxy_ssl_trusted_certificate /etc/nginx/secrets/cert_bundle_default_backend-cert.crt;
    }
    location = / {
        return 404 "";
       proxy_http_version 1.1;
    }

    location /_ngf-internal-ext-auth-default_secure-app_rule0 {
        internal;
        proxy_http_version 1.1;
        proxy_set_header Host "$host";
        proxy_set_header X-Original-URI "$request_uri";
        proxy_set_header X-Api-Key "$http_x_api_key";
        proxy_pass https://default_ext-auth-server_443/;
        proxy_ssl_server_name on;
        proxy_ssl_verify on;
        proxy_ssl_name secure-app.example.com;
        proxy_ssl_trusted_certificate /etc/nginx/secrets/cert_bundle_default_backend-cert.crt;
    }
}
curl --resolve secure-app.example.com:$GW_PORT:$GW_IP http://secure-app.example.com:$GW_PORT/coffee
Handling connection for 8080
<html>
<head><title>401 Authorization Required</title></head>
<body>
<center><h1>401 Authorization Required</h1></center>
<hr><center>nginx</center>
</body>
</html>


sa.choudhary@N9939CQ4P0 nginx-gateway-fabric % curl --resolve secure-app.example.com:$GW_PORT:$GW_IP http://secure-app.example.com:$GW_PORT/coffee -H "X-Api-Key: my-custom-secret"
Handling connection for 8080
hello from pod secure-app

@sjberman
Copy link
Copy Markdown
Collaborator

@salonichf5 And if you use two different policies, that also works?

@salonichf5
Copy link
Copy Markdown
Contributor Author

salonichf5 commented Apr 21, 2026

@salonichf5 And if you use two different policies, that also works?

yes

These two cases generate the same config

apiVersion: gateway.networking.k8s.io/v1
kind: BackendTLSPolicy
metadata:
  name: backend-tls
spec:
  targetRefs:
  - group: ''
    kind: Service
    name: secure-app
  validation:
    caCertificateRefs:
    - name: backend-cert
      group: ''
      kind: ConfigMap
    hostname: secure-app.example.com
    
apiVersion: gateway.networking.k8s.io/v1
kind: BackendTLSPolicy
metadata:
  name: ext-auth-tls
spec:
  targetRefs:
  - group: ''
    kind: Service
    name: ext-auth-server
  validation:
    caCertificateRefs:
    - name: backend-cert
      group: ''
      kind: ConfigMap
    hostname: secure-app.example.com

and

apiVersion: gateway.networking.k8s.io/v1
kind: BackendTLSPolicy
metadata:
  name: generic
spec:
  targetRefs:
  - group: ''
    kind: Service
    name: ext-auth-server
  - group: ''
    kind: Service
    name: secure-app
  validation:
    caCertificateRefs:
    - name: backend-cert
      group: ''
      kind: ConfigMap
    hostname: secure-app.example.com

Also to note, note both cases hostname is same because according to spec, we pass client hostname to the ext auth server as well

	// AllowedRequestHeaders specifies what additional headers from the client request 
	// will be sent to the authorization server.
	//
	// The following headers must always be sent to the authorization server,
	// regardless of this setting:
	//
	// * `Host`
	// * `Method`
	// * `Path`
	// * `Content-Length`
	// * `Authorization`

Comment thread internal/controller/nginx/config/http/config.go
Comment thread internal/controller/state/graph/httproute.go
@salonichf5 salonichf5 force-pushed the feat/external-auth branch 2 times, most recently from 132ef87 to ba55779 Compare May 5, 2026 20:22
@salonichf5 salonichf5 requested review from Copilot and sjberman May 5, 2026 20:27
Copy link
Copy Markdown

Copilot AI left a comment

Choose a reason for hiding this comment

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

Pull request overview

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


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

Comment thread internal/controller/nginx/config/servers.go Outdated
Comment thread internal/controller/state/graph/common_filter.go
Comment thread internal/controller/state/dataplane/configuration.go
Comment thread internal/controller/state/dataplane/configuration.go
Comment thread examples/external-authentication/cafe-routes.yaml
Comment thread internal/controller/nginx/config/servers.go
Comment thread internal/controller/state/graph/httproute.go
@salonichf5 salonichf5 requested review from bjee19 and shaun-nx May 6, 2026 16:04
Comment thread internal/controller/nginx/config/http/config.go Outdated
Comment thread internal/controller/nginx/config/servers.go Outdated
Comment thread internal/controller/nginx/config/servers.go Outdated
Comment thread internal/controller/nginx/config/servers.go Outdated
Comment thread internal/controller/nginx/config/servers.go
@salonichf5 salonichf5 requested a review from sjberman May 6, 2026 19:54
@salonichf5 salonichf5 force-pushed the feat/external-auth branch from 30c5c20 to e766a70 Compare May 6, 2026 20:38
@salonichf5 salonichf5 enabled auto-merge (squash) May 6, 2026 20:38
Comment thread internal/controller/nginx/config/servers.go Outdated
Copy link
Copy Markdown
Contributor

@bjee19 bjee19 left a comment

Choose a reason for hiding this comment

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

lgtm, just one small comment. nice job!

@salonichf5 salonichf5 disabled auto-merge May 6, 2026 20:58
@salonichf5 salonichf5 enabled auto-merge (squash) May 6, 2026 21:08
@salonichf5 salonichf5 merged commit c5f84b8 into main May 6, 2026
61 of 64 checks passed
@salonichf5 salonichf5 deleted the feat/external-auth branch May 6, 2026 22:50
@github-project-automation github-project-automation Bot moved this from 🆕 New to ✅ Done in NGINX Gateway Fabric May 6, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

documentation Improvements or additions to documentation enhancement New feature or request release-notes

Projects

Status: ✅ Done

Development

Successfully merging this pull request may close these issues.

Support External Auth

6 participants