Skip to content

feat: support downstream TLS for Web App resources - #422

Merged
clement0010 merged 6 commits into
masterfrom
feat/ct/webapp-downstream-tls
Aug 26, 2026
Merged

feat: support downstream TLS for Web App resources#422
clement0010 merged 6 commits into
masterfrom
feat/ct/webapp-downstream-tls

Conversation

@clement0010

@clement0010 clement0010 commented Jul 24, 2026

Copy link
Copy Markdown
Contributor

Related Tickets & Documents

Changes

  • Parse the tls flag in the GAT token's gateway_metadata.downstream; tokens without the flag keep today's plaintext behavior.
  • Terminate TLS at the Gateway for Web App connections when the GAT enables it: the connection goes through the same inner TLS upgrade Kubernetes connections use today, presenting the gateway certificate.
  • Set X-Forwarded-Proto with the downstream scheme before forwarding the request
  • Local dev tooling: the fake Twingate client gains a WithDownstreamTLS() option and tools/local runs an extra Web App client with it, testable via curl --cacert ./test/data/proxy/tls.crt https://<client-address>.

@codecov

codecov Bot commented Jul 24, 2026

Copy link
Copy Markdown

Codecov Report

✅ All modified and coverable lines are covered by tests.
✅ Project coverage is 90.70%. Comparing base (1d408f8) to head (fb053cf).
✅ All tests successful. No failed tests found.

Additional details and impacted files

Impacted file tree graph

@@            Coverage Diff             @@
##           master     #422      +/-   ##
==========================================
+ Coverage   90.63%   90.70%   +0.07%     
==========================================
  Files          41       41              
  Lines        2903     2915      +12     
==========================================
+ Hits         2631     2644      +13     
+ Misses        180      177       -3     
- Partials       92       94       +2     
Flag Coverage Δ
integration 57.70% <76.92%> (+0.07%) ⬆️
unit 85.79% <100.00%> (+0.09%) ⬆️

Flags with carried forward coverage won't be shown. Click here to find out more.

Files with missing lines Coverage Δ
internal/token/gat_claims.go 100.00% <100.00%> (ø)
internal/webapphandler/handler.go 100.00% <100.00%> (ø)

... and 2 files with indirect coverage changes

🚀 New features to boost your workflow:
  • 📦 JS Bundle Analysis: Save yourself from yourself by tracking and limiting bundle sizes in JS merges.

Parse the tls flag in the GAT token's gateway_metadata.downstream and run
the inner TLS upgrade for Web App connections when it is set, presenting
the gateway certificate — the same mechanism Kubernetes connections use.
The fake Twingate client gains a WithDownstreamTLS option and tools/local
runs an extra Web App client with it for local HTTPS testing.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01X9Z4JjodvSrpkMw964Lcgx
@clement0010
clement0010 force-pushed the feat/ct/webapp-downstream-tls branch from 2fd6a3b to 35f17f5 Compare July 24, 2026 08:15
@clement0010
clement0010 requested a lite review from Copilot July 24, 2026 08:49

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Pull request overview

Adds support for terminating downstream TLS for Web App resources based on a new gateway_metadata.downstream.tls flag carried in the GAT, aligning Web App handling with the existing “inner TLS upgrade” path used for Kubernetes connections. Also extends local dev tooling to exercise both plaintext and TLS-enforced Web App flows.

Changes:

  • Extend GAT claims with gateway_metadata.downstream.tls and include Web App resources in ShouldUpgradeTLS() when the flag is set.
  • Add a WithDownstreamTLS() option to the fake client and run an additional local Web App client configured for HTTPS testing.
  • Fix local gateway config template to use webApp.requestHeaders (matching the existing config schema).

Reviewed changes

Copilot reviewed 4 out of 4 changed files in this pull request and generated 1 comment.

File Description
tools/local/main.go Runs an additional fake Web App client for downstream TLS and updates local config/output instructions accordingly.
test/fake/client.go Adds a client option to mark downstream TLS in the generated GAT and switch the downstream port to 443.
internal/token/gat_claims.go Adds Downstream.TLS to GAT claims and updates TLS-upgrade decision logic for Web App resources.
internal/token/gat_claims_test.go Expands unit tests to cover the new Web App TLS-upgrade behavior and JSON unmarshalling of the new flag.

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

Comment thread internal/token/gat_claims.go
@github-actions

github-actions Bot commented Aug 8, 2026

Copy link
Copy Markdown

This pull request is stale because it has been open 5 days with no activity. Remove stale label or comment or this will be closed in 5 days.

@github-actions github-actions Bot added the wontfix This will not be worked on label Aug 8, 2026
@clement0010 clement0010 removed the wontfix This will not be worked on label Aug 10, 2026

@minhtule minhtule left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

LGTM 👍

Comment thread internal/token/gat_claims.go Outdated
Comment thread internal/token/gat_claims.go Outdated
Comment thread tools/local/main.go Outdated
@minhtule
minhtule requested a review from sghiocel August 20, 2026 19:03
Copilot AI review requested due to automatic review settings August 24, 2026 15:40

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

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 4 out of 4 changed files in this pull request and generated 1 comment.

Suppressed comments (1)

internal/token/gat_claims_test.go:48

  • These cases only verify the metadata flag and the ShouldUpgradeTLS boolean; they never exercise a Web App connection through the listener and HTTP proxy with the inner TLS handshake. A regression in the actual termination/routing path could therefore pass these tests. Please add an integration (or equivalent end-to-end) case that uses WithDownstreamTLS, trusts tls.crt, and verifies the proxied response and headers.
			name:          "Web app with downstream TLS should upgrade TLS",
			resourceType:  ResourceTypeWebApp,
			downstreamTLS: true,
			expected:      true,

Comment thread internal/token/gat_claims.go
@sghiocel

Copy link
Copy Markdown
Contributor

It seems that the gateway needs to add X-Forwarded-Proto to solve for this kind of issue:

Without X-Forwarded-Proto:

[1] Browser address bar:  https://grafana.acme.int/
[2] Gateway decrypts TLS, forwards upstream over plain HTTP

[3] App receives, verbatim:
      GET / HTTP/1.1
      Host: grafana.acme.int
      X-Forwarded-Proto: ""      <- the only way it can know
      r.TLS == nil ? true        <- its own leg is plaintext, by design

[4] App concludes scheme="http", replies:
      HTTP/1.1 302 Found
      Location: http://grafana.acme.int/login?redirect_uri=http://grafana.acme.int/callback

[5] Browser receives that Location
[6] Browser obeys it and goes to http://...
[7] That request to the Gateway returns: EOF
    ❌ LOGIN IS DEAD

With:

[3] App receives, verbatim:
      GET / HTTP/1.1
      Host: grafana.acme.int
      X-Forwarded-Proto: "https"    <- now it knows
      r.TLS == nil ? true           <- still plaintext, still by design

[4] App concludes scheme="https", replies:
      HTTP/1.1 302 Found
      Location: https://grafana.acme.int/login?redirect_uri=https://grafana.acme.int/callback

[6] Browser follows over HTTPS -> stays on the working path
    ✅ LOGIN WORKS

Copilot AI review requested due to automatic review settings August 25, 2026 03:38

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

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 7 out of 7 changed files in this pull request and generated no new comments.

Suppressed comments (2)

internal/token/gat_claims.go:98

  • This branch is what makes the existing listener perform the second TLS handshake, but the added tests only assert the boolean/header and the integration test still exercises a plaintext Web App. Add an end-to-end Web App case with downstream.tls=true that sends an inner TLS request and verifies the proxied response; otherwise the actual TLS termination/routing path can regress while these tests pass.
	case ResourceTypeWebApp:
		return p.Resource.GatewayMetadata.Downstream.TLS

test/integration/web_app_test.go:122

  • The new TLS behavior is not exercised by this integration test: it still creates only the plaintext Web App client and only verifies X-Forwarded-Proto: http. A regression in the inner TLS handshake, gateway certificate presentation, or routing of the decrypted request would therefore pass the suite. Add a TLS-enabled fake client and an HTTPS request that trusts test/data/proxy/tls.crt, asserting the response and X-Forwarded-Proto: https.
		// Downstream scheme
		"X-Forwarded-Proto": "http",

Copilot AI review requested due to automatic review settings August 25, 2026 03:46

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

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 7 out of 7 changed files in this pull request and generated 1 comment.

Suppressed comments (1)

internal/token/gat_claims.go:98

  • The new Web App path is only exercised by the ShouldUpgradeTLS and header-rewrite unit tests; the integration test still sends only http://..., so no test drives the listener's second TLS handshake and HTTP server with a GAT containing downstream.tls: true. Please add an HTTPS Web App integration case and assert the proxied response (including X-Forwarded-Proto) to cover the end-to-end behavior advertised by this change.
		return p.Resource.GatewayMetadata.Downstream.TLS

Comment thread test/integration/web_app_test.go
@clement0010

Copy link
Copy Markdown
Contributor Author

@sghiocel I added the X-Forwarded-Proto header in 66f15ac, could you review again?

@clement0010
clement0010 merged commit 5869c81 into master Aug 26, 2026
14 checks passed
@clement0010
clement0010 deleted the feat/ct/webapp-downstream-tls branch August 26, 2026 03:54
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.

Support downstream TLS for Web App resources

5 participants