Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
37 changes: 20 additions & 17 deletions .github/dependabot.yml
Original file line number Diff line number Diff line change
Expand Up @@ -6,38 +6,41 @@ updates:
schedule:
interval: weekly

# Go - AuthProxy
# Go - authlib (the shared library — pulled in by every cmd/* binary
# via replace directives, so updates here flow into everything).
- package-ecosystem: gomod
directory: /authbridge/authproxy
directory: /authbridge/authlib
schedule:
interval: weekly

# Python - root (tests)
- package-ecosystem: pip
directory: /
# Go - mode-specific binaries
- package-ecosystem: gomod
directory: /authbridge/cmd/authbridge-proxy
schedule:
interval: weekly

# Python - client-registration
- package-ecosystem: pip
directory: /authbridge/client-registration
- package-ecosystem: gomod
directory: /authbridge/cmd/authbridge-envoy
schedule:
interval: weekly
- package-ecosystem: gomod
directory: /authbridge/cmd/authbridge-lite
schedule:
interval: weekly

# Docker - AuthProxy
- package-ecosystem: docker
directory: /authbridge/authproxy
# Go - abctl TUI
- package-ecosystem: gomod
directory: /authbridge/cmd/abctl
schedule:
interval: weekly

# Docker - AuthProxy quickstart demo-app
- package-ecosystem: docker
directory: /authbridge/authproxy/quickstart/demo-app
# Python - root (tests)
- package-ecosystem: pip
directory: /
schedule:
interval: weekly

# Docker - client-registration
# Docker - proxy-init (iptables init container, envoy-sidecar mode)
- package-ecosystem: docker
directory: /authbridge/client-registration
directory: /authbridge/proxy-init
schedule:
interval: weekly
2 changes: 1 addition & 1 deletion .github/workflows/build.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@
# set up traffic redirection. Proxy-sidecar mode does not
# need this (HTTP_PROXY env var routing replaces iptables).
- name: proxy-init
context: ./authbridge/authproxy
context: ./authbridge/proxy-init
dockerfile: Dockerfile.init

# AuthBridge envoy-sidecar combined image —
Expand Down Expand Up @@ -98,7 +98,7 @@
# Always use the computed tag
type=raw,value=${{ steps.tag.outputs.tag }}
# Add 'latest' tag for version tags, workflow_dispatch, and pushes to main
type=raw,value=latest,enable=${{ (github.ref_type == 'tag' && startsWith(github.ref_name, 'v')) || github.event_name == 'workflow_dispatch' || github.ref == 'refs/heads/main' }}

Check warning on line 101 in .github/workflows/build.yaml

View workflow job for this annotation

GitHub Actions / YAML Lint

101:151 [line-length] line too long (189 > 150 characters)

# 7. Build and push image
- name: Build and push ${{ matrix.image_config.name }}
Expand Down
34 changes: 4 additions & 30 deletions .github/workflows/ci.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,7 @@ jobs:

- uses: actions/setup-go@4a3601121dd01d1626a1e23e37211e3254c1c06c # v6
with:
go-version-file: authbridge/authproxy/go.mod
go-version-file: authbridge/authlib/go.mod

- uses: actions/setup-python@a309ff8b426b58ec0e2a45f0f869d46889d02405 # v6
with:
Expand All @@ -40,32 +40,6 @@ jobs:
env:
SKIP: ai-assisted-by-trailer

go-ci:
name: Go CI
runs-on: ubuntu-latest
timeout-minutes: 15
defaults:
run:
working-directory: authbridge/authproxy
steps:
- uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6

- uses: actions/setup-go@4a3601121dd01d1626a1e23e37211e3254c1c06c # v6
with:
go-version-file: authbridge/authproxy/go.mod
cache-dependency-path: authbridge/authproxy/go.sum

- name: Lint
run: |
go fmt ./...
go vet ./...

- name: Build
run: go build -v ./...

- name: Test
run: go test -v -race -cover ./...

go-ci-authlib:
name: Go CI (authlib)
runs-on: ubuntu-latest
Expand Down Expand Up @@ -107,9 +81,9 @@ jobs:
run:
working-directory: authbridge/cmd/${{ matrix.binary }}
env:
# Disable go.work — the workspace at authbridge/ includes ./authproxy
# which would pull in that module's dependencies. The replace directive
# in go.mod handles the authlib dependency for CI builds.
# Disable go.work so each cmd/* module resolves authlib via its own
# `replace` directive in go.mod (the workspace would otherwise pull
# all sibling modules in and slow down CI).
GOWORK: "off"
steps:
- uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6
Expand Down
2 changes: 1 addition & 1 deletion .github/workflows/security-scans.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -245,7 +245,7 @@ jobs:
scan-type: 'config'
scan-ref: '.'
severity: 'CRITICAL,HIGH,MEDIUM'
skip-dirs: 'authbridge/demos,authbridge/authproxy/quickstart'
skip-dirs: 'authbridge/demos'
exit-code: '0'
format: 'table'

Expand Down
14 changes: 0 additions & 14 deletions .pre-commit-config.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -30,17 +30,3 @@ repos:
- id: ruff-format
files: ^authbridge/

- repo: local
hooks:
- id: go-fmt-authproxy
name: go-fmt (AuthProxy)
entry: bash -c 'cd authbridge/authproxy && go fmt ./...'
language: system
files: ^authbridge/authproxy/.*\.go$
pass_filenames: false
- id: go-vet-authproxy
name: go-vet (AuthProxy)
entry: bash -c 'cd authbridge/authproxy && go vet ./...'
language: system
files: ^authbridge/authproxy/.*\.go$
pass_filenames: false
47 changes: 31 additions & 16 deletions CLAUDE.md
Original file line number Diff line number Diff line change
Expand Up @@ -44,10 +44,12 @@ kagenti-extensions/
│ │ ├── main.go
│ │ ├── Dockerfile # proxy-sidecar lite combined image
│ │ └── entrypoint.sh
│ ├── authproxy/ # iptables init container + standalone quickstart
│ │ ├── quickstart/ # Standalone demo (no SPIFFE)
│ │ └── k8s/ # Standalone K8s manifests
│ ├── demos/ # Demo scenarios (weather-agent, github-issue, webhook, single-target, multi-target)
│ ├── proxy-init/ # iptables init container (envoy-sidecar mode only)
│ │ ├── init-iptables.sh
│ │ ├── Dockerfile.init
│ │ ├── Makefile
│ │ └── README.md
│ ├── demos/ # Demo scenarios (weather-agent, github-issue, token-exchange-routes, mcp-parser)
│ └── keycloak_sync.py # Declarative Keycloak sync tool
├── tests/ # Python tests (keycloak_sync)
├── .github/
Expand All @@ -74,8 +76,8 @@ kagenti-extensions/

**Common:**
- `authlib/` — shared auth library (JWT validation, token exchange, caching, routing, all listener implementations, all plugins).
- `authproxy/init-iptables.sh` — traffic interception setup (Istio ambient mesh compatible). Used by envoy-sidecar mode only.
- `authproxy/Dockerfile.init` — proxy-init container image.
- `proxy-init/init-iptables.sh` — traffic interception setup (Istio ambient mesh compatible). Used by envoy-sidecar mode only.
- `proxy-init/Dockerfile.init` — proxy-init container image.

**Ports (envoy-sidecar):** 15123 (outbound), 15124 (inbound), 9090 (ext-proc), 9901 (admin)
**Ports (proxy-sidecar / lite):** 8080 (reverse proxy), 8081 (forward proxy), 9091 (health), 9093 (stats), 9094 (session API)
Expand Down Expand Up @@ -139,7 +141,7 @@ Three mode-specific binaries, one Dockerfile per binary:

| Workflow | Trigger | Purpose |
|----------|---------|---------|
| `ci.yaml` | PR to main/release-* | Go fmt, vet, build, test for authproxy, authlib, and the cmd/authbridge-* binaries; Python tests |
| `ci.yaml` | PR to main/release-* | Pre-commit, Go fmt/vet/build/test for authlib and the cmd/authbridge-* binaries; Python tests |
| `build.yaml` | Tag push (`v*`) or manual | Multi-arch Docker builds for: proxy-init, authbridge (proxy-sidecar combined), authbridge-envoy (envoy-sidecar combined), authbridge-lite (proxy-sidecar lite combined) |
| `security-scans.yaml` | PR to main | Dependency review, shellcheck, YAML lint, Hadolint, Bandit, Trivy, CodeQL |
| `scorecard.yaml` | Weekly / push to main | OpenSSF Scorecard security health metrics |
Expand All @@ -165,7 +167,7 @@ All images are pushed to `ghcr.io/kagenti/kagenti-extensions/` from
| **`authbridge`** | **`authbridge/cmd/authbridge-proxy/Dockerfile`** | **proxy-sidecar combined image (default mode): authbridge-proxy (full plugin set incl. parsers) + spiffe-helper. No Envoy.** |
| `authbridge-envoy` | `authbridge/cmd/authbridge-envoy/Dockerfile` | envoy-sidecar combined image: Envoy + authbridge-envoy (ext_proc, full plugin set) + spiffe-helper |
| `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 |
| `proxy-init` | `authbridge/authproxy/Dockerfile.init` | Alpine + iptables init container (envoy-sidecar mode only) |
| `proxy-init` | `authbridge/proxy-init/Dockerfile.init` | Alpine + iptables init container (envoy-sidecar mode only) |

In all three combined images, `spiffe-helper` is started conditionally
based on the `SPIRE_ENABLED` env var (set by the operator when SPIRE
Expand All @@ -185,7 +187,7 @@ Hooks:
- `trailing-whitespace`, `end-of-file-fixer`, `check-added-large-files` (max 1024KB), `check-yaml`, `check-json`, `check-merge-conflict`, `mixed-line-ending`
- `ai-assisted-by-trailer` — Rewrites `Co-Authored-By` to `Assisted-By` (commit-msg stage)
- `ruff`, `ruff-format` — Python linting/formatting on `authbridge/` files
- `go-fmt`, `go-vet` — Runs on `authbridge/authproxy/` Go files
- `go-fmt`, `go-vet` — Runs on `authbridge/proxy-init/` Go files

## Languages and Tech Stack

Expand Down Expand Up @@ -227,11 +229,25 @@ When the operator injects sidecars, the target namespace needs these resources:

### Building Everything Locally

The repo-root `local-build-and-test.sh` orchestrates every image
the platform needs (`spiffe-idp-setup` from kagenti, plus
`authbridge`, `authbridge-envoy`, `authbridge-lite`, `proxy-init`
from this repo) and loads them into a Kind cluster:

```bash
KAGENTI_DIR=../kagenti ./local-build-and-test.sh
```

To build a single image directly:

```bash
# AuthProxy images
cd authbridge/authproxy && make build-images
# proxy-init (iptables init container, envoy-sidecar mode)
cd authbridge/proxy-init && make docker-build-init

# Client registration (no separate build needed, uses Dockerfile directly)
# Combined sidecars (proxy-sidecar default / envoy-sidecar / lite)
cd authbridge && podman build -f cmd/authbridge-proxy/Dockerfile -t authbridge:latest .
cd authbridge && podman build -f cmd/authbridge-envoy/Dockerfile -t authbridge-envoy:latest .
cd authbridge && podman build -f cmd/authbridge-lite/Dockerfile -t authbridge-lite:latest .
```

### Running the Full Demo
Expand All @@ -241,8 +257,7 @@ cd authbridge/authproxy && make build-images
3. See the [AuthBridge demos index](authbridge/demos/README.md) for a recommended learning path:
- **Getting started**: `authbridge/demos/weather-agent/demo-ui.md` (inbound validation, UI deployment)
- **Full flow**: `authbridge/demos/github-issue/demo-ui.md` (token exchange + scope-based access)
- **Webhook internals**: `authbridge/demos/webhook/README.md`
- **Manual deployment**: `authbridge/demos/single-target/demo.md`
- **Routes config reference**: `authbridge/demos/token-exchange-routes/README.md` (single + multi-target route patterns)

### Adding a New Component Image to CI

Expand Down Expand Up @@ -282,9 +297,9 @@ cd authbridge/authproxy && make build-images

## Gotchas and Known Issues

1. **One Go module:** The repo has a single Go module at `authbridge/authproxy/go.mod` (Go 1.24).
1. **One Go module:** The repo has a single Go module at `authbridge/proxy-init/go.mod` (Go 1.24).

2. **Avoid committing venvs:** Virtual environment directories (e.g. `authbridge/authproxy/quickstart/venv/`) should be gitignored (the repo's `.gitignore` has a `venv` pattern). Do not create and commit new virtual environments under version control.
2. **Avoid committing venvs:** Virtual environment directories (e.g. `authbridge/proxy-init/quickstart/venv/`) should be gitignored (the repo's `.gitignore` has a `venv` pattern). Do not create and commit new virtual environments under version control.

3. **Envoy config not embedded:** The envoy-proxy sidecar mounts `envoy-config` ConfigMap at `/etc/envoy`. This ConfigMap must exist in the target namespace before workloads are created.

Expand Down
6 changes: 4 additions & 2 deletions CONTRIBUTING.md
Original file line number Diff line number Diff line change
Expand Up @@ -31,8 +31,10 @@ cd kagenti-extensions
# Install pre-commit hooks
pre-commit install

# Build AuthProxy images
cd authbridge/authproxy && make build-images
# Build the proxy-init image (one-target Makefile in proxy-init/).
# For the four combined-sidecar images plus this one, use the
# repo-root local-build-and-test.sh.
cd authbridge/proxy-init && make docker-build-init
```

## Issues
Expand Down
21 changes: 20 additions & 1 deletion LOCAL_TESTING_GUIDE.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,24 @@
# Local Testing Guide for JWT-SVID Authentication

> **⚠️ This guide is stale after kagenti-extensions#411.** It was written
> for the pre-#411 multi-sidecar shape (separate `client-registration`,
> `envoy-with-processor`, and standalone `spiffe-helper` containers) and
> several of its YAML examples reference images that no longer publish.
> The image inventory at the top, the in-line pod spec, and the
> "Check ... logs" sections all assume the legacy shape.
>
> **What still works**: the script invocation in §1 — `local-build-and-test.sh`
> has been updated to build the three combined images (`authbridge`,
> `authbridge-envoy`, `authbridge-lite`) plus `proxy-init`. The rest of
> the guide needs a re-author against the operator-injected combined
> sidecar shape; track via a follow-up issue.
>
> **Working alternatives in the meantime**:
> - `authbridge/demos/weather-agent/demo-ui-advanced.md` — current
> reference for the combined-sidecar flow with SPIFFE.
> - `authbridge/demos/github-issue/demo-ui.md` — full token-exchange
> flow with scope-based access control.

This guide walks you through testing JWT-SVID authentication using local images (no push to ghcr.io).

## ⚠️ Important: Use the Build Script
Expand Down Expand Up @@ -452,7 +471,7 @@ For testing the complete AuthBridge flow with automatic sidecar injection:

**Manual Demo:** Follow [authbridge/demos/github-issue/demo-manual.md](authbridge/demos/github-issue/demo-manual.md)

**Webhook Demo:** Follow [authbridge/demos/webhook/README.md](authbridge/demos/webhook/README.md)
**Token-Exchange Routes:** Follow [authbridge/demos/token-exchange-routes/README.md](authbridge/demos/token-exchange-routes/README.md)

---

Expand Down
12 changes: 8 additions & 4 deletions Makefile
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
# Root Makefile for kagenti-extensions monorepo
# Orchestrates linting and formatting across all sub-projects

.PHONY: lint fmt pre-commit build-images help
.PHONY: lint fmt pre-commit build-proxy-init help

help: ## Display this help
@awk 'BEGIN {FS = ":.*##"; printf "\nUsage:\n make \033[36m<target>\033[0m\n"} /^[a-zA-Z_0-9-]+:.*?##/ { printf " \033[36m%-20s\033[0m %s\n", $$1, $$2 } /^##@/ { printf "\n\033[1m%s\033[0m\n", substr($$0, 5) } ' $(MAKEFILE_LIST)
Expand All @@ -12,13 +12,17 @@ lint: ## Run all linters (pre-commit hooks)
pre-commit run --all-files

fmt: ## Run formatters across all sub-projects
cd authbridge/authproxy && go fmt ./...
cd authbridge/authlib && go fmt ./...
cd authbridge/cmd/abctl && go fmt ./...
cd authbridge/cmd/authbridge-proxy && go fmt ./...
cd authbridge/cmd/authbridge-envoy && go fmt ./...
cd authbridge/cmd/authbridge-lite && go fmt ./...
ruff format authbridge/

pre-commit: ## Install pre-commit hooks (including commit-msg)
pre-commit install --hook-type pre-commit --hook-type commit-msg

##@ Sub-project Targets

build-images: ## Build AuthProxy Docker images
cd authbridge/authproxy && make build-images
build-proxy-init: ## Build the proxy-init iptables init container
cd authbridge/proxy-init && make docker-build-init
38 changes: 26 additions & 12 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -6,25 +6,39 @@ Kubernetes security extensions for the [Kagenti](https://github.com/kagenti/kage

[AuthBridge](./authbridge/) provides end-to-end authentication for Kubernetes workloads with [SPIFFE/SPIRE](https://spiffe.io) integration. It consists of:

- **[AuthProxy](./authbridge/authproxy/)** — Envoy proxy with a gRPC external processor for inbound JWT validation and outbound OAuth 2.0 token exchange (RFC 8693). Enables secure service-to-service communication by transparently intercepting traffic.
- **[Client Registration](./authbridge/client-registration/)** — Automatically registers Kubernetes workloads as Keycloak OAuth2 clients using their SPIFFE identity, eliminating manual client configuration and static credentials.
- **[Authlib](./authbridge/authlib/)** — shared Go library: JWT validation, RFC 8693 token exchange, plugin pipeline, listener implementations.
- **Mode-specific binaries** under [`authbridge/cmd/`](./authbridge/cmd/):
- [`authbridge-proxy`](./authbridge/cmd/authbridge-proxy/) — proxy-sidecar (default): HTTP forward + reverse proxies, full plugin set.
- [`authbridge-envoy`](./authbridge/cmd/authbridge-envoy/) — envoy-sidecar: ext_proc gRPC server hooked into Envoy, full plugin set.
- [`authbridge-lite`](./authbridge/cmd/authbridge-lite/) — proxy-sidecar with auth-only plugins (no parsers); for size-constrained deployments.
- **[proxy-init](./authbridge/proxy-init/)** — iptables init container used by envoy-sidecar mode for transparent traffic interception.
- **[Keycloak Sync](./authbridge/keycloak_sync.py)** — Declarative tool for synchronizing Keycloak configuration.

Keycloak client registration runs in the [kagenti-operator](https://github.com/kagenti/kagenti-operator) (separate repo, post-#411 / kagenti-operator#361 — no in-pod registration sidecar).

See the [AuthBridge README](./authbridge/README.md) for architecture details and the [demos index](./authbridge/demos/README.md) for getting started.

## Container Images

All images are published to `ghcr.io/kagenti/kagenti-extensions/`:
All images are published to `ghcr.io/kagenti/kagenti-extensions/`. After
kagenti-extensions#411 the unified binary was split into three
mode-specific combined images, and the per-component sidecars
(`client-registration`, standalone `spiffe-helper`) were retired:

| Image | Description |
|-------|-------------|
| `authbridge-unified` | Unified Envoy + authbridge binary (recommended) |
| `authbridge` | Combined sidecar (Envoy + authbridge + spiffe-helper + client-registration) |
| `proxy-init` | Alpine + iptables init container |
| `client-registration` | Python Keycloak client registrar |
| `spiffe-helper` | Fetches SPIFFE credentials from SPIRE |
| `auth-proxy` | Example pass-through proxy (for demos) |
| `demo-app` | Demo target service |
| `authbridge` | proxy-sidecar combined (default): authbridge-proxy + bundled spiffe-helper, full plugin set |
| `authbridge-envoy` | envoy-sidecar combined: Envoy + ext_proc + bundled spiffe-helper, full plugin set |
| `authbridge-lite` | proxy-sidecar shape, auth-only plugins (no parsers) for size-constrained deployments |
| `proxy-init` | Alpine + iptables init container (envoy-sidecar mode only) |

`spiffe-helper` is bundled inside each combined image and gated per
workload by the `SPIRE_ENABLED` env var. Client registration is
handled by the kagenti-operator's `ClientRegistrationReconciler` and
no longer ships as a separate image. The legacy `authbridge-unified`,
`authbridge-light`, `client-registration`, and standalone `spiffe-helper`
images are no longer published; older release tags continue to
publish the previous shape.

## Development

Expand All @@ -35,8 +49,8 @@ make pre-commit
# Run formatters
make fmt

# Build AuthProxy Docker images
make build-images
# Build the proxy-init iptables init container image
make build-proxy-init

# Run local testing (requires Kind cluster)
./local-build-and-test.sh
Expand Down
Loading
Loading