Architecture v0.6.0 — real teardown, HTTPS only, env.yaml
Kept as it stood for 0.6.0; the current page describes 0.7.5.
Hierarchy: Group → Environment → Zone → Worker (decision D5). Transport: Streamable HTTP at the edge, gRPC inside (D31; gRPC since D19).
Store: Firestore, DynamoDB or Postgres. Cloud adapter: local, gcp or aws (namespaces, Deployments, routes,
NEG or target groups, Cloud Armor or WAF, IAM). Secrets backend: the store, Secret Manager or Secrets Manager.
The console reaches workers over gRPC on the pod IP (Admin/Reload, Admin/Metrics, Health/Check), never
through the load balancer.
Components
| Dir | What | Tech | Contract |
|---|---|---|---|
console/ |
Manager UI + /api/v1; roles per group (D41), the OAuth 2.1 authorization server (D34), IdP role mapping (D38), scoped service-account policy (D40); gRPC client to workers (ramen_console.grpcclient) |
FastAPI, Jinja2, HTMX (no JS build, no unsafe-eval), argon2, itsdangerous, Fernet, grpcio |
§4, §4a, §9, §11, §16.3 |
node-rs/ |
MCP server node: ramen.v1.Mcp/Call, ramen.v1.Admin, grpc.health.v1.Health on one h2c/TLS port; bearer auth, CIDR allow-lists, blocked names, in-flight limit, access log, sidecar supervisor |
Rust 1.98, tonic, tokio | §11 |
runtime-py/ |
Loads mcp/ packages from the bucket, validates protos, pip-installs requirements, renders mcp/env.yaml from secrets (0.6.0), executes calls, resolves and redacts secrets |
Python 3.12 (pinned, D45), jsonschema, optional NeMo Guardrails | §1, §2, §11 |
ramen-mcp-bridge (own repo, PyPI) |
Stdio MCP server forwarding to Mcp/Call over gRPC with a group key or, since 0.2.0, the person's own OAuth token (PKCE + loopback callback against the console) |
Python, grpcio | §11, §16.3 |
proto/ramen/v1/ |
mcp.proto, admin.proto — single source for Rust (tonic-build) and Python (grpcio-tools) stubs |
protobuf 3 | §11 |
deploy/local |
docker compose: Firestore emulator + console + one worker (gRPC h2c on 8080) | §5, §11 | |
deploy/terraform/gcp, deploy/helm/* |
GKE Autopilot, Firestore, GCS, Artifact Registry, static IP, GSA + Workload Identity (custom role, resource-level IAM), GKE Gateway with header routes + gRPC health | Terraform, Helm 4 | §7, §11 |
deploy/terraform/aws, deploy/cloudformation |
EKS, DynamoDB, S3, Secrets Manager, ECR, IRSA, ALB controller (gRPC target groups, HTTP1 for /mcp and OAuth metadata since 0.6.1), Fluent Bit (exercised on the real account, not at volume) |
Terraform, CloudFormation | §8, §11 |
tests/ |
Black-box conformance + e2e + cloud suites over gRPC, plus the bridge via the official mcp stdio client |
pytest, grpcio, mcp |
§11 |
skills/ |
Cloud-ops agent skills (deploy, rotate, backup, scale) | agentskills SKILL.md |
§10 |
Data model
| Collection | Key fields | Notes |
|---|---|---|
users |
email, memberships: {group: role} (group_admin / viewer / mcp_user), super_admin flag |
role and groups are derived summaries; password hash Fernet-encrypted |
groups |
name, repo_url, ref, mcp_auth, sa_restrictions | one bucket prefix per group |
environments |
group, name, ref, zones[], verbose, blocked[], last_deploy | zone list drives namespaces |
zones |
name, provider (local / gcp / aws), region (cloud zone) |
super admin only |
workers |
group, zone, count, size (s/m/l), allowed_sizes, cidrs, service_account |
live pods come from the adapter |
secrets |
group, name, env?, zone?, kind (secret / mcp_key), value or ref |
value never returned |
api_keys |
name, role, groups, hash | rmn_<id>_<secret>, shown once |
audit / activity |
ts, user, ip, action, target, ok, tags | every mutation; permission requests live in activity |
config, backups |
auth toggles, SA rules; backup metadata | backups exclude secrets |
Request paths
- MCP call: client (
POST /mcpover Streamable HTTP, a gRPC client, or the stdio bridge) → LB matchesramen-group+ramen-zoneheaders → node checks CIDR, Origin (HTTP), then thermk_key or an OAuth token (constant-time) → runtime (spawned on demand) → tool → JSON-RPC result in the reply body. Transport failures are gRPC statuses (UNAUTHENTICATED,PERMISSION_DENIED,RESOURCE_EXHAUSTED) or their HTTP twins (401, 403, 429); protocol failures stay JSON-RPC errors. One log line per call (ts, ip, transport, group, method, name, status, grpc_code, ms, key_id);RAMEN_VERBOSE=1logs bodies. - Deploy: console job → clone repo (token via git header) → upload bucket → write zone Secret/env file
(
RAMEN_MCP_KEYS,RAMEN_SECRET_*,RAMEN_BLOCKED,RAMEN_ALLOWED_CIDRS) → canary restart →Health/CheckSERVING→Admin/Reload→tools/listsmoke → stable restart. See Deploying. - Rebalance / IP rules: console → cloud API (backend capacity, Cloud Armor / WAF) + node env → worker roll.
Load comes from
Admin/Metrics. See Rebalance.
Decisions
Only the decisions that still shape the code are listed. The gaps are ids that were superseded, or that never left the private workspace.
| ID | Decision |
|---|---|
| D2 | State DB: Firestore on GCP, DynamoDB on AWS, one repository interface. No Postgres. (partly superseded by D37) |
| D3 | Worker pod = Rust node + Python runtime sidecar, 1:1, spawned on demand, idle-terminated. |
| D4 | (superseded by D19) Transport: JSON-RPC 2.0 over HTTP (MCP Streamable HTTP), 0.1.0–0.3.0. |
| D5 | Hierarchy Group → Environment → Zone → Worker. |
| D6 | One zone first; every layer multi-zone capable. |
| D9 | Semver from 0.1.0; tags v* build releases with zips. |
| D11 | Console: FastAPI + Jinja2 + HTMX, server-rendered. |
| D14 | Bucket dir = group repo root; no MCP keys = deny all; node config precedence file < env < deploy file. |
| D17 | (superseded by D36) Console on GCP: static IP + self-signed cert on the global HTTPS LB; managed cert later. |
| D18 | v0.3.0 scope: AWS (untested at the time; applied to a real account from 0.5.6), OAuth polish, SA policy engine, tool blocking, email auth, docs, launch. |
| D19 | v0.3.1: MCP transport is JSON-RPC 2.0 over gRPC (ramen.v1.Mcp/Call); HTTP MCP endpoint removed; ramen-mcp-bridge (stdio) serves standard clients; full security parity on gRPC; LB routes on ramen-group/ramen-zone metadata; carried security mediums fixed; logo v2. |
| D21 | v0.4.0: API keys carry an enforced client type — an agent key is accepted only by workers over gRPC, a devops key only by the console API. |
| D22 | v0.4.0: the autoscale and rebalance stress test runs on a local kind cluster first, then once on a throwaway GKE project. |
| D23 | v0.4.0: independent-client evidence is a real MCP client driven against the bridge, plus an editor configuration the user captures. |
| D31 | v0.5.0: Streamable HTTP at the edge, gRPC inside — every worker serves POST /mcp on the gRPC port through the same guards; the bridge is the stdio-only compatibility path. |
| D32 | v0.5.0: the HTTP handler lives in the node on the same port; never a separate edge service. |
| D33 | v0.5.0: sessions are stateless signed ids (HMAC over nonce, expiry and the credential; per-group secret handed to every zone). |
| D34 | v0.5.0: the console is the OAuth 2.1 authorization server — PKCE S256, pre-registered clients, no dynamic registration. |
| D35 | v0.5.1: cloud runs get their permissions from a rule the human adds; the agent never writes its own permission file. |
| D36 | v0.5.5: the GCP console gets a Google-managed certificate on a free sslip.io hostname derived from the static IP (supersedes D17); no domain to buy, no CA to export. |
| D37 | v0.5.5: Postgres is an optional third RAMEN_STORE for self-hosted deployments; Firestore and DynamoDB stay the cloud defaults (partly supersedes D2). |
| D38 | v0.5.93: IdP role mapping is authoritative on every login, keyed by claim value, never by person; no match means no membership. |
| D39 | v0.5.93: a fourth role, mcp_user, who only signs in to approve MCP clients for their groups' zones; no console, no API. |
| D40 | v0.5.93: a service-account permission carries a scope; empty or * means the group's own prefix and secrets, named resources bind on those alone. |
| D41 | v0.5.95: roles are held per group (user.memberships); one person may be a Group Admin of one group and an MCP User of another. |
Version history
v0.1.0 local core → v0.2.0 GCP → v0.3.0 AWS, auth & policy, docs →
v0.3.1 gRPC transport → v0.4.0 console polish, docs, and proof → 0.5.x Streamable HTTP
at the edge, OAuth, the GKE and AWS runs, per-group roles → 0.6.0 real zone teardown, HTTPS only, env.yaml.
This page describes 0.6.0; the changelog has each
release and Versions tracks them. A drawing of one call end to end, and what protects every hop, is in
Transport and what secures each hop.