Skip to content

Commit 238f48e

Browse files
committed
docs: Reflect in-cluster TCP capture; fix proxy-init mode + PR-title notes
proxy-init/README.md: update enforce-redirect to describe in-cluster TCP capture (only in-cluster DNS-over-TCP + non-TCP/UDP left direct via CLUSTER_CIDRS), the AuthBridge->ztunnel composition for re-originated egress, and correct the now-wrong 'add it to CLUSTER_CIDRS to bypass' guidance (CLUSTER_CIDRS is DNS-only, not a TCP bypass). CLAUDE.md + authbridge/CLAUDE.md: proxy-init/init-iptables.sh is no longer 'envoy-sidecar mode only' — enforce-redirect is the proxy-sidecar egress guard. PR Title Convention: the CI check (action-pr-title) is case-sensitive and requires a capitalized prefix (Fix:/Feat:/Docs:), distinct from the lowercase commit-message examples. Assisted-By: Claude (Anthropic AI) <noreply@anthropic.com> Signed-off-by: Hai Huang <huang195@gmail.com>
1 parent 8966c9e commit 238f48e

3 files changed

Lines changed: 48 additions & 30 deletions

File tree

CLAUDE.md

Lines changed: 13 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -44,7 +44,7 @@ kagenti-extensions/
4444
│ │ ├── main.go
4545
│ │ ├── Dockerfile # proxy-sidecar lite combined image
4646
│ │ └── entrypoint.sh
47-
│ ├── proxy-init/ # iptables init container (envoy-sidecar mode only)
47+
│ ├── proxy-init/ # iptables init container (envoy-sidecar + proxy-sidecar enforce-redirect modes)
4848
│ │ ├── init-iptables.sh
4949
│ │ ├── Dockerfile.init
5050
│ │ ├── Makefile
@@ -76,7 +76,7 @@ kagenti-extensions/
7676

7777
**Common:**
7878
- `authlib/` — shared auth library (JWT validation, token exchange, caching, routing, all listener implementations, all plugins).
79-
- `proxy-init/init-iptables.sh` — traffic interception setup (Istio ambient mesh compatible). Used by envoy-sidecar mode only.
79+
- `proxy-init/init-iptables.sh` — traffic interception setup (Istio ambient mesh compatible). Used by envoy-sidecar mode (`redirect`) and by proxy-sidecar mode's `enforce-redirect` egress guard.
8080
- `proxy-init/Dockerfile.init` — proxy-init container image.
8181

8282
**Ports (envoy-sidecar):** 15123 (outbound), 15124 (inbound), 9090 (ext-proc), 9901 (admin)
@@ -149,13 +149,20 @@ Three mode-specific binaries, one Dockerfile per binary:
149149

150150
### PR Title Convention
151151

152-
PRs must follow **conventional commits** format:
152+
PR titles must follow the format:
153153

154154
```
155-
<type>: <Subject starting with uppercase>
155+
<Prefix>: <Subject starting with uppercase>
156156
```
157157

158-
Types: `feat`, `fix`, `docs`, `style`, `refactor`, `perf`, `test`, `build`, `ci`, `chore`, `revert`
158+
The CI title check (`deepakputhraya/action-pr-title`) is **case-sensitive** and
159+
requires a **capitalized** prefix from this set: `Build`, `Chore`, `CI`, `Docs`,
160+
`Feat`, `Fix`, `Perf`, `Refactor`, `Revert`, `Style`, `Test`, `Feature`,
161+
`Bug fix`, `Proposal`, `Breaking change`, `Other`, `Other/Misc`.
162+
163+
Note: commit *message* examples elsewhere in this doc use lowercase
164+
(`feat:` / `fix:`) — that is fine for commits, but the PR *title* check rejects
165+
lowercase prefixes. Use `Fix:` / `Feat:` / `Docs:` in PR titles.
159166

160167
## Container Images
161168

@@ -167,7 +174,7 @@ All images are pushed to `ghcr.io/kagenti/kagenti-extensions/` from
167174
| **`authbridge`** | **`authbridge/cmd/authbridge-proxy/Dockerfile`** | **proxy-sidecar combined image (default mode): authbridge-proxy (full plugin set incl. parsers) + spiffe-helper. No Envoy.** |
168175
| `authbridge-envoy` | `authbridge/cmd/authbridge-envoy/Dockerfile` | envoy-sidecar combined image: Envoy + authbridge-envoy (ext_proc, full plugin set) + spiffe-helper |
169176
| `authbridge-lite` | `authbridge/cmd/authbridge-lite/Dockerfile` | proxy-sidecar lite combined image: authbridge-lite (auth gates only, parsers dropped) + spiffe-helper. Same listener layout as `authbridge`; not yet referenced by the operator's default config |
170-
| `proxy-init` | `authbridge/proxy-init/Dockerfile.init` | Alpine + iptables init container (envoy-sidecar mode only) |
177+
| `proxy-init` | `authbridge/proxy-init/Dockerfile.init` | Alpine + iptables init container (envoy-sidecar + proxy-sidecar enforce-redirect modes) |
171178

172179
In all three combined images, `spiffe-helper` is started conditionally
173180
based on the `SPIRE_ENABLED` env var (set by the operator when SPIRE

authbridge/CLAUDE.md

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -62,7 +62,7 @@ authbridge/
6262
│ ├── Dockerfile # proxy-sidecar lite combined image
6363
│ └── entrypoint.sh
6464
65-
├── proxy-init/ # iptables init container (envoy-sidecar mode only)
65+
├── proxy-init/ # iptables init container (envoy-sidecar + proxy-sidecar enforce-redirect modes)
6666
│ ├── init-iptables.sh # iptables setup script
6767
│ ├── Dockerfile.init # proxy-init container image
6868
│ ├── Makefile # docker-build-init + load-image targets
@@ -350,7 +350,7 @@ without needing a CR.
350350
### Build images locally
351351

352352
```bash
353-
# Build the proxy-init iptables init container (envoy-sidecar mode only)
353+
# Build the proxy-init iptables init container (envoy-sidecar + proxy-sidecar enforce-redirect modes)
354354
cd authbridge/proxy-init
355355
make docker-build-init
356356
make load-image # Uses KIND_CLUSTER_NAME env var (default: kagenti)

authbridge/proxy-init/README.md

Lines changed: 33 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@ env var:
88
| `MODE` | Used by | What it does |
99
|---|---|---|
1010
| `redirect` (default) | `envoy-sidecar` | Transparently **REDIRECT**s pod traffic to the Envoy listeners. |
11-
| `enforce-redirect` | `proxy-sidecar`, `lite` | Fail-closed egress guard that **captures**: REDIRECTs external TCP that bypasses the forward proxy to AuthBridge's transparent listener; DROPs non-TCP external egress. |
11+
| `enforce-redirect` | `proxy-sidecar`, `lite` | Fail-closed egress guard that **captures**: REDIRECTs bypassing TCP — external **and** in-cluster (except in-cluster DNS) — to AuthBridge's transparent listener; DROPs non-TCP external egress; leaves in-cluster non-TCP (DNS/UDP) direct. |
1212

1313
## `redirect` mode (envoy-sidecar)
1414

@@ -48,39 +48,50 @@ nat-table target but the nat table forbids `DROP` (`iptables` errors with
4848

4949
- **`nat` OUTPUT / `AB_REDIRECT`** (position 1): `RETURN` ztunnel mark
5050
`0x539`, the proxy UID (`--uid-owner $PROXY_UID`, avoids the loop),
51-
loopback, and `CLUSTER_CIDRS`; then `REDIRECT` external **TCP** to
52-
`TRANSPARENT_PORT`.
51+
loopback, and in-cluster **DNS-over-TCP** (`-p tcp --dport 53` to
52+
`CLUSTER_CIDRS`, so cluster name resolution stays direct); then
53+
`REDIRECT` all remaining **TCP** — external **and** in-cluster — to
54+
`TRANSPARENT_PORT`, so agent→in-cluster calls (e.g. agent→tool) are
55+
captured by the egress pipeline too.
5356
- **`mangle` OUTPUT / `AB_NOTCP`** (position 1): the same exemptions
5457
(plus `ESTABLISHED,RELATED` first, so UDP conntrack replies like DNS
55-
pass), then `-p tcp -j RETURN` (TCP is handled by the nat REDIRECT) and
56-
a terminal `DROP` for external **non-TCP** (UDP/QUIC), so HTTP/3 cannot
57-
bypass — well-behaved clients fall back to TCP and get captured.
58+
pass), **including the full `CLUSTER_CIDRS` `RETURN`** so in-cluster
59+
non-TCP (DNS-over-UDP and any other in-cluster UDP) stays direct; then
60+
`-p tcp -j RETURN` (TCP is handled by the nat REDIRECT) and a terminal
61+
`DROP` for external **non-TCP** (UDP/QUIC), so HTTP/3 cannot bypass —
62+
well-behaved clients fall back to TCP and get captured.
5863

5964
Because the OUTPUT hook order is `raw → mangle → nat → filter`, the
6065
mangle chain drops non-TCP on its original destination while TCP falls
6166
through to the nat REDIRECT. Both chains are inserted at position 1,
62-
ahead of Istio's appended (`-A`) chains, so they preempt ambient's nat
63-
redirect for external destinations — exactly as `redirect` mode does for
64-
the Envoy path. IPv6 mirrors apply the same rules. See
67+
ahead of Istio's appended (`-A`) chains. The proxy's own re-originated
68+
egress (`--uid-owner $PROXY_UID`, `RETURN`ed) falls through to
69+
`ISTIO_OUTPUT` → ztunnel for transport mTLS under Istio ambient, and goes
70+
out plain without a mesh — so capturing in-cluster TCP **composes with**
71+
the mesh (AuthBridge does L7, ztunnel does transport) rather than
72+
bypassing it. IPv6 mirrors apply the same rules. See
6573
[`test-enforce-redirect.sh`](./test-enforce-redirect.sh), which proves
6674
the capture, the preemption, and the non-TCP drop via packet counters.
6775

68-
> **`CLUSTER_CIDRS` is Kind-shaped by default.** The `10.0.0.0/8` default
69-
> covers Kind (pods `10.244.0.0/16` + services `10.96.0.0/16`). Other
70-
> distros differ — **OpenShift** uses services `172.30.0.0/16` and pods
71-
> `10.128.0.0/14`, and `172.30.0.0/16` is **outside** `10/8`, so the
72-
> default would drop in-cluster service traffic. On OCP/EKS/etc. you
73-
> **must** override `CLUSTER_CIDRS` with the cluster's real pod+service
74-
> ranges. The script logs the resolved value at startup, and the
75-
> operator sets it from the cluster's CIDRs.
76+
> **`CLUSTER_CIDRS` is Kind-shaped by default.** It now governs only what
77+
> stays **direct**: in-cluster DNS-over-TCP (`tcp/53`) and in-cluster
78+
> non-TCP (so cluster DNS keeps working). The `10.0.0.0/8` default covers
79+
> Kind (pods `10.244.0.0/16` + services `10.96.0.0/16`). Other distros
80+
> differ — **OpenShift** uses services `172.30.0.0/16` and pods
81+
> `10.128.0.0/14`, and `172.30.0.0/16` is **outside** `10/8`, so with the
82+
> default, cluster DNS (CoreDNS on `172.30.x`) is no longer left direct and
83+
> **resolution breaks**. On OCP/EKS/etc. you **must** override
84+
> `CLUSTER_CIDRS` with the cluster's real pod+service ranges. The script
85+
> logs the resolved value at startup, and the operator sets it from the
86+
> cluster's CIDRs.
7687
7788
> **`enforce-redirect` intentionally ignores `OUTBOUND_PORTS_EXCLUDE`** (a
7889
> `redirect`-mode knob). Any destination previously bypassed that way —
7990
> e.g. a direct LLM endpoint at `host.docker.internal:11434` — is now
80-
> captured (external TCP) or dropped (external non-TCP) unless it falls
81-
> within `CLUSTER_CIDRS`. That is the point: `enforce-redirect` closes
82-
> direct-egress holes. Operators relying on a bypass for an in-cluster
83-
> target must include it in `CLUSTER_CIDRS`.
91+
> captured (external TCP) or dropped (external non-TCP). In-cluster TCP is
92+
> captured as well (only in-cluster DNS stays direct), so `CLUSTER_CIDRS`
93+
> is **not** a TCP bypass — it only keeps cluster DNS and in-cluster UDP
94+
> direct. That is the point: `enforce-redirect` closes direct-egress holes.
8495
8596
## iptables backend
8697

@@ -100,7 +111,7 @@ whichever the host kernel exposes. Override with `IPTABLES_CMD` (and
100111
| `OUTBOUND_PORTS_EXCLUDE` | (empty) | redirect | Comma-separated outbound port list to skip (e.g. `8080`) |
101112
| `INBOUND_PORTS_EXCLUDE` | (empty) | redirect | Comma-separated inbound port list to skip |
102113
| `POD_IP` | (required in `redirect`) | redirect | Set via Downward API; DNAT target for ambient-mesh inbound. Not used by `enforce-redirect`. |
103-
| `CLUSTER_CIDRS` | `10.0.0.0/8` | enforce-redirect | Comma-separated in-cluster CIDRs allowed direct (pods/services/DNS) |
114+
| `CLUSTER_CIDRS` | `10.0.0.0/8` | enforce-redirect | Comma-separated in-cluster CIDRs kept direct **for DNS only**: DNS-over-TCP (`tcp/53`) + all in-cluster non-TCP (UDP). Other in-cluster TCP is captured. |
104115
| `CLUSTER_CIDRS6` | (empty) | enforce-redirect | IPv6 in-cluster CIDRs (dual-stack); empty drops all external v6 egress |
105116
| `IPTABLES_CMD` | auto-detected | all | Override iptables binary (`iptables-legacy` / `iptables-nft`) |
106117
| `IP6TABLES_CMD` | derived from `IPTABLES_CMD` | enforce-redirect | Override ip6tables binary |

0 commit comments

Comments
 (0)