Skip to content

Feat: Select active proxies via listener.roles - #709

Open
huang195 wants to merge 1 commit into
rossoctl:mainfrom
huang195:feat/proxy-roles
Open

Feat: Select active proxies via listener.roles#709
huang195 wants to merge 1 commit into
rossoctl:mainfrom
huang195:feat/proxy-roles

Conversation

@huang195

@huang195 huang195 commented Jul 28, 2026

Copy link
Copy Markdown
Member

Summary

proxy-sidecar mode always started BOTH the reverse proxy (:8080, inbound) and the forward proxy (:8081, outbound), and validate.go unconditionally required reverse_proxy_backend. Real deployments come in three shapes — pods want both, a laptop/demo wants forward-only (egress TLS-bridge), and some cases want reverse-only — but only "both" was expressible, forcing egress-only users into a dummy reverse_proxy_backend: http://127.0.0.1:9 plus a reverse_proxy_addr override (the default :8080 collides with the kind cluster's port-forward).

Change

Add listener.roles — a list of reverse and/or forward. Empty (the default) = both, so pods and every existing config (and the operator path) are unchanged. A subset runs a single shape:

Deployment Config Listeners
Pod (default) (omit roles) reverse + forward + transparent + session API — as today
Laptop listener: {roles: [forward]} forward :8081 (+ transparent :8082, session API :9094)
Reverse-only listener: {roles: [reverse], reverse_proxy_backend: ...} reverse :8080 (+ session API)
  • presets: fills an addr default only for an active role — forward-only never binds :8080; reverse-only never binds :8081/:8082.
  • validate: rejects unknown roles; requires reverse_proxy_backend only when the reverse role is active; rejects tls_bridge enabled without the forward role (it only affects outbound).
  • main: starts each proxy (and the transparent listener, which rides with forward) only when its role is active, mirroring the existing empty-addr-skip pattern for the transparent proxy and session API.

This PR is code-only (the 5 Go files below); there's no in-repo demo config to edit — the local forward-proxy setup is an ad-hoc local.yaml. What this feature enables: that config can drop both prior workaround lines (reverse_proxy_backend, reverse_proxy_addr) down to listener: {roles: [forward]} (see Composition).

Testing Instructions

go test ./...                 # full authlib module — pass
go vet ./... (authlib + cmd)  # clean

Unit tests: ActiveRoles default/subset; ApplyPreset fills only active-role addrs; validation for reverse-without-backend, unknown role, and tls_bridge-without-forward. Verified at runtime: forward-only binds :8081/:8082/:9094 and never :8080; reverse-only without a backend fails validation with a clear message.

Composition

Independent of #707 (generate_ca); together the laptop demo is listener: {roles: [forward]} + tls_bridge: {mode: enabled, ca_dir, generate_ca: true}.

Assisted-By: Claude (Anthropic AI) noreply@anthropic.com

proxy-sidecar mode always started BOTH the reverse proxy (:8080, inbound)
and the forward proxy (:8081, outbound), and validation unconditionally
required reverse_proxy_backend. That forces standalone/laptop egress-only
deployments to set a dummy backend and move the reverse proxy off its
colliding :8080 default.

Add listener.roles ([reverse] and/or [forward]); an empty list defaults
to BOTH, so pods and every existing config are unchanged. A subset runs
one shape:
  roles: [forward]   # egress-only TLS-bridge (laptop demo)
  roles: [reverse]   # inbound JWT validation only

- config: ListenerConfig.Roles, RoleReverse/RoleForward, ActiveRoles()
  (empty => both).
- presets: fill an addr default only for an active role (so forward-only
  never binds :8080 and reverse-only never binds :8081/:8082).
- validate: reject unknown roles; require reverse_proxy_backend only when
  the reverse role is active; reject tls_bridge enabled without the
  forward role (it only affects outbound).
- main: start each proxy (and, with forward, the transparent listener)
  only when its role is active — mirroring the existing empty-addr-skip
  pattern for the transparent proxy and session API.

The forward-only demo config drops both prior workaround lines
(reverse_proxy_backend, reverse_proxy_addr): just listener.roles: [forward].

Tests: ActiveRoles default/subset; ApplyPreset fills only active-role
addrs; validation for missing backend (reverse), unknown role, and
tls_bridge-without-forward. Verified at runtime — forward-only binds
:8081 (+:8082,:9094) and never :8080; reverse-only without a backend
fails validation.

Assisted-By: Claude (Anthropic AI) <noreply@anthropic.com>
Signed-off-by: Hai Huang <huang195@gmail.com>
@coderabbitai

coderabbitai Bot commented Jul 28, 2026

Copy link
Copy Markdown

Review Change Stack

📝 Walkthrough

Walkthrough

Proxy-sidecar listeners now support explicit reverse and forward roles. Presets, validation, and authbridge-proxy startup use active roles to configure and launch only the requested proxy components, while empty roles preserve both-role behavior.

Changes

Proxy-sidecar roles

Layer / File(s) Summary
Listener role contract
authbridge/authlib/config/config.go, authbridge/authlib/config/config_test.go
Adds serialized Roles, reverse/forward role constants, ActiveRoles(), and tests for default, forward-only, and reverse-only selection.
Role-aware presets and validation
authbridge/authlib/config/presets.go, authbridge/authlib/config/validate.go, authbridge/authlib/config/config_test.go
Applies listener address defaults by role and validates allowed roles, reverse backend requirements, and TLS bridge requirements.
Conditional proxy startup
authbridge/cmd/authbridge-proxy/main.go
Creates reverse, forward, and transparent proxy components only when their corresponding roles are active, using a shared session store.

Estimated code review effort: 3 (Moderate) | ~20 minutes

Sequence Diagram(s)

sequenceDiagram
  participant ListenerConfig
  participant AuthbridgeProxy
  participant ReverseProxy
  participant ForwardProxy
  participant TransparentListener
  ListenerConfig->>AuthbridgeProxy: ActiveRoles()
  AuthbridgeProxy->>ReverseProxy: Start when reverse role is active
  AuthbridgeProxy->>ForwardProxy: Start when forward role is active
  AuthbridgeProxy->>TransparentListener: Create when forward role is active
Loading

Suggested reviewers: esnible, ibrahim2595, alan-cha

🚥 Pre-merge checks | ✅ 5
✅ Passed checks (5 passed)
Check name Status Explanation
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.
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.
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title clearly summarizes the main change: selecting active proxy roles via listener.roles.
✨ 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.

@huang195 huang195 added this to the Release v0.8.0 milestone Jul 28, 2026

@mrsabath mrsabath 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. Clean, well-scoped, and backward-compatible — listener.roles is threaded through a single source of truth (ActiveRoles(), empty ⇒ both) that presets, validate, and main all consume identically, so there's no divergent role logic across the three files and existing configs / the operator path are unchanged.

Runtime safety checks out: transparentLn is nil-guarded on shutdown (main.go:466-467), and bridge is only consumed inside the forward branch — with validate.go now rejecting tls_bridge enabled without the forward role, there's no dead-config path. Test coverage is thorough: role defaulting, per-role preset addr-filling, and all four validation cases (reverse-without-backend, unknown role, tls_bridge ± forward).

One non-blocking doc/scope nit inline about the demo-config claim in the description.

Areas reviewed: Go (config, validation, main wiring), Tests, feature-gate parity
Commit: 1, signed-off (DCO pass) · CI: all green
Verdict: APPROVE

// Valid values: "reverse", "forward". The preset fills an addr default
// only for an active role, and reverse_proxy_backend is required only when
// the reverse role is active. Ignored outside proxy-sidecar mode.
Roles []string `yaml:"roles" json:"roles"`

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.

suggestion (non-blocking) — the PR description's "Change" section says "The forward-only demo config now drops both prior workaround lines — just listener: {roles: [forward]}", but no demo/YAML config is in this diff (only the 5 Go files). A reader following the description will go looking for that config edit. Either fold the demo-config change into this PR or reword the body to note it's a follow-up — otherwise the forward-only demo still carries the reverse_proxy_backend: http://127.0.0.1:9 + reverse_proxy_addr workaround this feature is meant to retire. The code itself is complete and correct as-is.

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

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

Dobra uwaga, dzięki Mariusz! 🙂 You're right — the body was writing a check the diff doesn't cash. There's no in-repo demo config for this local forward-proxy setup (it's an ad-hoc local.yaml), so rather than fold a YAML edit in here I reworded the description: this PR is code-only and just enables the slimmer config, and the full one-liner demo (roles: [forward] + generate_ca) composes with #707. Went with the reword per your either/or.

@huang195 huang195 changed the title Feat: select active proxies via listener.roles Feat: Select active proxies via listener.roles Jul 28, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

Status: New/ToDo

Development

Successfully merging this pull request may close these issues.

3 participants