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
29 changes: 13 additions & 16 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,37 +1,34 @@
# Cortex

Cortex is a sidecar framework that **secures and observes the traffic of AI agents and Kubernetes workloads**. It sits in the request path — as a local forward/reverse proxy, an Envoy `ext_proc` filter, or a mesh waypoint — and adds:
Cortex delivers easy-to-use platform services to agentic workloads. It runs in a workload's request path — a sidecar in Kubernetes, or a standalone binary anywhere else — and provides:

- **Identity & tokens** — SPIFFE/SPIRE workload identity, JWT validation, and RFC 8693 token exchange (the original "AuthBridge" capability).
- **Protocol-aware observability** — decrypts egress (TLS bridge) and parses LLM inference, MCP, and A2A calls into a live session view (`abctl`).
- **Egress control & policy** — guardrails (IBAC / OPA) and per-host routing over a workload's outbound calls.
- **Identity & access** — a verifiable identity for each workload, authentication and authorization of its calls, and the right credentials for each downstream service.
- **Guardrails** — block agent actions that stray from the user's intent or aren't grounded in the conversation.
- **Observability** — decrypt and parse a workload's model, tool, and agent-to-agent traffic into a live view.
- **Egress control** — govern which external services a workload can reach.
- **Optimizations** — trim the model context a workload sends and cap its spend, to cut latency and cost.

It runs the same way **in Kubernetes** (operator-injected sidecar) or **standalone** on a laptop/VM (a single binary, no cluster).

> Formerly **AuthBridge** — the code lives under [`authbridge/`](./authbridge/) and ships as the `authbridge-proxy` binary and the `abctl` session viewer.
It ships as a single binary; the identity and access layer is **AuthBridge**, and the code lives under [`authbridge/`](./authbridge/).

## Quick start (local, no Kubernetes)

See an AI agent's egress — LLM, MCP, and A2A calls — decrypted and parsed live on your laptop. No cluster, no Keycloak, no SPIRE.

1. **Get the binaries.** Download prebuilt `abctl` and `authbridge-proxy` (linux/macOS, amd64/arm64) from the [Releases page](https://github.com/rossoctl/cortex/releases) and put them on your `PATH`. On macOS, clear the quarantine once: `xattr -dr com.apple.quarantine ./abctl ./authbridge-proxy`.
_(Or build from source: `cd authbridge/cmd/abctl && go build .` then `cd ../authbridge-proxy && go build .`.)_

2. **Start Cortex** with the built-in local preset — a forward-only proxy (loopback-only) with the TLS bridge on and the protocol parsers, no config file needed. On first run it generates a demo CA under `./cortex-ca` (override with `--ca-dir`) and logs the exact `NODE_EXTRA_CA_CERTS=…` line to trust it:
1. **Install and start it.** One line installs the `abctl` and `authbridge-proxy` binaries (macOS/Linux) and starts the local demo. On first run it mints a demo CA under `./cortex-ca` and logs the `NODE_EXTRA_CA_CERTS=…` line to trust it:

```sh
authbridge-proxy --demo
curl -fsSL https://raw.githubusercontent.com/rossoctl/cortex/main/authbridge/install-demo.sh | sh
```

_(It also writes that config to `./cortex-ca/demo.yaml`edit that file and the running proxy hot-reloads it.)_
_(Prefer to inspect first? Read [`install-demo.sh`](./authbridge/install-demo.sh)or build from source: `cd authbridge/cmd/abctl && go build .` then `cd ../authbridge-proxy && go build . && ./authbridge-proxy --demo`.)_

3. **Open the session viewer** in another terminal:
2. **Open the session viewer** in another terminal:

```sh
abctl --endpoint http://localhost:9094
```

4. **Run your agent through it** — e.g. Claude Code (from the same directory, so `./cortex-ca` resolves — or use the absolute path the proxy logged):
3. **Run your agent through it** — e.g. Claude Code (from the same directory, so `./cortex-ca` resolves — or use the absolute path the proxy logged):

```sh
HTTPS_PROXY=http://localhost:8081 \
Expand All @@ -42,7 +39,7 @@ See an AI agent's egress — LLM, MCP, and A2A calls — decrypted and parsed li

Its LLM, MCP, and A2A calls appear live in `abctl`, decrypted and parsed.

> Local / observe-only: the parsers *observe* traffic; nothing is enforced. `generate_ca` and the self-signed CA are for local use — in Kubernetes the CA is a mounted cert-manager Secret.
> Observe-only: the parsers *observe* traffic; nothing is enforced. The self-signed demo CA is for local use — in Kubernetes the CA is a mounted cert-manager Secret.

## Running on Kubernetes

Expand Down
140 changes: 140 additions & 0 deletions authbridge/install-demo.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,140 @@
#!/bin/sh
# install-demo.sh — one-line installer + launcher for the Cortex local demo.
#
# curl -fsSL https://raw.githubusercontent.com/rossoctl/cortex/main/authbridge/install-demo.sh | sh
#
# Detects your OS/arch, downloads the prebuilt `abctl` and `authbridge-proxy`
# binaries for the newest release, verifies their SHA-256 checksums, installs
# them to ~/.local/bin, and starts `authbridge-proxy --demo` (Ctrl-C to stop).
# macOS + Linux, amd64 + arm64. No cluster, Keycloak, or SPIRE needed.
#
# Environment:
# AUTHBRIDGE_VERSION=vX.Y.Z install a specific release tag (default: newest)
# AUTHBRIDGE_INSTALL_ONLY=1 install the binaries but do not start the demo
set -eu
Comment on lines +1 to +14

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

🩺 Stability & Availability | 🟠 Major | ⚡ Quick win

🧩 Analysis chain

🏁 Script executed:

#!/bin/sh
for shell in /bin/sh dash bash; do
  command -v "$shell" >/dev/null 2>&1 || continue
  printf '%s: ' "$shell"
  "$shell" -c 'set -euo pipefail; trap ":" EXIT'
  printf 'status=%s\n' "$?"
done

Repository: rossoctl/cortex

Length of output: 186


🏁 Script executed:

#!/bin/bash
set -euo pipefail

echo "== files =="
git ls-files | rg '(^|/)authbridge/install-demo\.sh$|(^|/)authbridge/' | head -200

echo "== target outline =="
wc -l authbridge/install-demo.sh
ast-grep outline authbridge/install-demo.sh || true

echo "== relevant sections =="
sed -n '1,120p' authbridge/install-demo.sh
sed -n '120,190p' authbridge/install-demo.sh

echo "== pipeline/options references =="
rg -n "set -|pipefail|trap|curl \\| sh|curl.*\\|.*sh|\\| " authbridge/install-demo.sh

Repository: rossoctl/cortex

Length of output: 10032


🏁 Script executed:

#!/bin/bash
set -u

echo "== target exists =="
if [ -f authbridge/install-demo.sh ]; then
  wc -l authbridge/install-demo.sh
else
  echo "missing authbridge/install-demo.sh"
fi

echo "== target relevant lines =="
if [ -f authbridge/install-demo.sh ]; then
  sed -n '1,120p' authbridge/install-demo.sh
  echo "-- later relevant lines --"
  sed -n '120,190p' authbridge/install-demo.sh
fi

echo "== options/pipeline references =="
if [ -f authbridge/install-demo.sh ]; then
  rg -n "set -|pipefail|trap|curl \\| sh|curl.*\\|.*sh|\\| " authbridge/install-demo.sh || true
fi

echo "== shell pipefail/trap support =="
for shell in /bin/sh dash bash; do
  command -v "$shell" >/dev/null 2>&1 || continue
  printf '%s: ' "$shell"
  "$shell" -c 'set -euo pipefail; trap ":" EXIT' >/dev/null 2>&1
  ret=$?
  printf "status=%s\n" "$ret"
done

Repository: rossoctl/cortex

Length of output: 6749


Align the installer shell policy with its advertised sh contract.

Line 14 does not use the required pipefail setting, so the release-resolution pipeline can suppress failures from grep -m1. Enabling it keeps the current #!/bin/sh contract but conflicts with POSIX sh; the documented curl | sh payload should be updated to require Bash, or the script should avoid pipelines and keep pipefail disabled. Also replace trap ... EXIT at Lines 69 and 103 with trap ... 0 for POSIX compatibility.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@authbridge/install-demo.sh` around lines 1 - 14, Keep install-demo.sh
compatible with its advertised POSIX sh and curl | sh contract: avoid relying on
pipefail by rewriting the release-resolution pipeline so grep failures propagate
without it, and replace both EXIT trap conditions with the POSIX-compatible
zero-status condition. Preserve the existing release selection, cleanup, and
installation behavior.

Source: Coding guidelines


REPO="rossoctl/cortex"
BIN_DIR="${HOME}/.local/bin"

info() { printf '%s\n' "$*"; }
warn() { printf 'warning: %s\n' "$*" >&2; }
die() { printf 'error: %s\n' "$*" >&2; exit 1; }

command -v curl >/dev/null 2>&1 || die "curl is required"
command -v tar >/dev/null 2>&1 || die "tar is required"

# Verify the checklist file passed as $1 (run from the directory holding the
# files). shasum is preferred: it's always present on macOS and its -c reads the
# GNU-style checksums.txt reliably, whereas some non-GNU sha256sum builds reject
# -c. Linux without shasum falls back to sha256sum (GNU coreutils).
sha_check() {
if command -v shasum >/dev/null 2>&1; then
shasum -a 256 -c "$1"
elif command -v sha256sum >/dev/null 2>&1; then
sha256sum -c "$1"
else
die "need shasum or sha256sum to verify downloads"
fi
}

# --- detect platform ---
os=$(uname -s)
case "$os" in
Darwin) os=darwin ;;
Linux) os=linux ;;
*) die "unsupported OS: $os (the demo installer supports macOS and Linux)" ;;
esac

arch=$(uname -m)
case "$arch" in
x86_64 | amd64) arch=amd64 ;;
arm64 | aarch64) arch=arm64 ;;
*) die "unsupported architecture: $arch (supported: amd64, arm64)" ;;
esac

# --- resolve the release tag ---
# `releases/latest` excludes prereleases, and the project ships prereleases, so
# list releases (newest first) and take the first tag_name instead.
version="${AUTHBRIDGE_VERSION:-}"
if [ -z "$version" ]; then
info "Resolving newest release..."
version=$(curl -fsSL "https://api.github.com/repos/${REPO}/releases?per_page=1" \
| grep -m1 '"tag_name"' | sed -e 's/.*"tag_name": *"//' -e 's/".*//')
[ -n "$version" ] || die "could not resolve the newest release (set AUTHBRIDGE_VERSION=vX.Y.Z)"
fi
info "Release: $version"

# --- download + verify ---
tmp=$(mktemp -d)
trap 'rm -rf "$tmp"' EXIT

base="https://github.com/${REPO}/releases/download/${version}"
abctl_tgz="abctl_${version}_${os}_${arch}.tar.gz"
proxy_tgz="authbridge-proxy_${version}_${os}_${arch}.tar.gz"

info "Downloading binaries for ${os}/${arch}..."
curl -fsSL "${base}/${abctl_tgz}" -o "${tmp}/${abctl_tgz}" || die "download failed: ${abctl_tgz}"
curl -fsSL "${base}/${proxy_tgz}" -o "${tmp}/${proxy_tgz}" || die "download failed: ${proxy_tgz}"
curl -fsSL "${base}/checksums.txt" -o "${tmp}/checksums.txt" || die "download failed: checksums.txt"

info "Verifying checksums..."
# Match exactly the two archives we downloaded (anchored to the end of the line),
# not every entry for this platform — so an unrelated future artifact in
# checksums.txt can't make verification fail on a file we never fetched.
grep -E "(${abctl_tgz}|${proxy_tgz})\$" "${tmp}/checksums.txt" > "${tmp}/checksums.filtered" \
|| die "no checksum entries for ${abctl_tgz} / ${proxy_tgz} in checksums.txt"
( cd "$tmp" && sha_check checksums.filtered ) || die "checksum verification failed"
Comment on lines +76 to +86

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

🔒 Security & Privacy | 🟠 Major | 🏗️ Heavy lift

Authenticate the release artifacts.

The checksum manifest is downloaded from the same mutable release location as both archives. An attacker able to replace release assets can replace all three files with matching hashes, so verification succeeds. Verify a signed manifest/provenance against a pinned trusted key or identity independent of release assets.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@authbridge/install-demo.sh` around lines 76 - 84, Update the checksum
verification flow in install-demo.sh to authenticate checksums.txt using a
pinned trusted signing key or identity obtained independently of the mutable
release assets before running sha_check. Ensure installation aborts when
manifest signature or provenance verification fails, then retain the existing
platform filtering and archive checksum validation.


# --- extract + install ---
info "Installing to ${BIN_DIR}..."
mkdir -p "$BIN_DIR"
tar -xzf "${tmp}/${abctl_tgz}" -C "$tmp"
tar -xzf "${tmp}/${proxy_tgz}" -C "$tmp"
for b in abctl authbridge-proxy; do
[ -f "${tmp}/${b}" ] || die "archive did not contain expected binary: ${b}"
chmod +x "${tmp}/${b}"
mv -f "${tmp}/${b}" "${BIN_DIR}/${b}"
done

# macOS: clear the quarantine flag so Gatekeeper doesn't block the unsigned binaries.
if [ "$os" = "darwin" ] && command -v xattr >/dev/null 2>&1; then
xattr -dr com.apple.quarantine "${BIN_DIR}/abctl" "${BIN_DIR}/authbridge-proxy" 2>/dev/null || true
fi

rm -rf "$tmp"
trap - EXIT

# --- report + next steps ---
proxy="${BIN_DIR}/authbridge-proxy"
case ":${PATH}:" in
*":${BIN_DIR}:"*) abctl_cmd="abctl" proxy_cmd="authbridge-proxy" ;;
*) abctl_cmd="${BIN_DIR}/abctl" proxy_cmd="$proxy" ;;
esac

info ""
info "Installed abctl and authbridge-proxy (${version}) to ${BIN_DIR}"
case ":${PATH}:" in
*":${BIN_DIR}:"*) ;;
*)
warn "${BIN_DIR} is not on your PATH; the commands below use full paths."
warn "Add it for future sessions: export PATH=\"${BIN_DIR}:\$PATH\""
;;
esac
info ""
info "In two more terminals (from this directory, so ./cortex-ca resolves):"
info " View the live session: ${abctl_cmd} --endpoint http://localhost:9094"
info ' Run your agent, e.g. Claude Code:'
# $PWD is intentionally literal here — printed for the user's shell to expand
# when they paste the command, not expanded by this script.
# shellcheck disable=SC2016
info ' HTTPS_PROXY=http://localhost:8081 NODE_EXTRA_CA_CERTS="$PWD/cortex-ca/ca.crt" CLAUDE_CODE_DISABLE_NONESSENTIAL_TRAFFIC=1 claude'
info ""

if [ "${AUTHBRIDGE_INSTALL_ONLY:-}" = "1" ]; then
info "Install-only mode. Start the demo with: ${proxy_cmd} --demo"
exit 0
fi

info "Starting the demo proxy (Ctrl-C to stop)..."
info ""
exec "$proxy" --demo
Loading