picatz / picatz/flowstate

Design: the Flowstate control plane — an admin API, tenants as administered objects, ABAC over Temporal RBAC

Open
#107 1 comment 0 reactions 0 assignees View on GitHub

Nobody has claimed this yet.

auth design kind/design-record
Dominant language
Go
Stars
9
Forks
0
Avg merge
3h 3m
Merged PRs (30d)
509

Description

The deliberate irony, named so it can be built on purpose: Flowstate runs on Temporal and is architected like Temporal — a control plane (submit, observe, govern, administer) over a data plane (workers executing steps), in parallel to and on top of Temporal's own pair. The power of the arrangement is that each layer does what it is good at: Temporal provides durability, history, and cluster RBAC; Flowstate provides the workload model, tenancy, ABAC policy, and identity — and a Flowstate user never needs to know Temporal is there, while one who does can reach through deliberately via the temporal plugin (#95) and do self-referential things (a workflow that inspects, terminates, or resets workflows) that no other arrangement offers.

What already exists, control-plane shaped

  • Layer 5 is already named: ARCHITECTURE.md's layer table calls the Connect RPC service the control plane — submit, observe, schedule, govern. The workload half is real: Run/Get/Signal/List/Cancel/Terminate/Validate/Compile/GetCatalog, all authenticated, all tenant-scoped.
  • Tenancy is real at the data path: namespace from the authenticated caller (never the file), memo-based ownership on every run, fairness keys per tenant, and — as of #103 — per-tenant routing onto mapped Temporal namespaces via the client pool. Temporal RBAC applies below that mapping (a Flowstate namespace's runs live in a Temporal namespace whose access Temporal controls); Flowstate ABAC applies above it.
  • The identity machinery is enterprise-grade already: inbound OIDC with discovery, JWKS caching, algorithm confusion defenses, claim rules; outbound minting with key rotation (Issuer.Rotate), retirement windows, and JWKS publishing. What it lacks is administrationRotate has no non-test caller, so key rotation today means restarting with a new --identity-key.
  • Policy surfaces exist and are file-fed (#104): trust, egress, secret access — deployment-wide, startup-loaded.

What an admin API adds, in dependency order

  1. Tenants as administered objects. Today a tenant emerges from a token claim mapping. An enterprise deployment needs tenant CRUD: create a namespace with its Temporal namespace mapping, its policy attachments (#104's scope ladder), its issuer bindings, its fairness weight; list them; retire one. This is Temporal's operator-namespace API paralleled one layer up — and it is what makes "local single-tenant → shared multi-tenant cloud service" one continuum rather than two products: the local deployment simply has one implicit tenant and no admin API configured.
  2. Key lifecycle RPCs. Mint, rotate, retire signing keys through the API with the actor recorded — the machinery exists (Rotate, retirement windows, JWKS serving), only the reachable surface is missing. Same for trusted-issuer management: adding an issuer to the trust policy without restarting the server.
  3. Policy attachment RPCs — #104's get/set/list per scope, with digests in run records for after-the-fact audit.
  4. All of it authenticated by the same OIDC machinery and authorized by CEL ABAC over the operator's verified claims — largely attribute-based, which is the right model for the multi-tenant cloud case (role explosion is what kills RBAC-only systems at tenant scale), while degrading naturally to "the one operator with the one admin audience" locally. One trust model, one condition language, no parallel admin-credential system.
  5. Proto-first, of course: the admin service is a schema service beside WorkflowService (an AdminService or OperatorService), so the CLI (flow tenant, flow policy, flow keys), the MCP surface, and any UI are projections of the same messages — the discipline #99 and the fourth-round CLI doctrine already prescribe.

The self-referential loop, stated as a feature

With the temporal plugin (#95), a Flowstate workflow can administer the substrate it runs on; with the admin API, a Flowstate workflow could administer Flowstate — tenant provisioning as a durable, approval-gated workflow (wait_for_signal: before creating the namespace, compensation on failure) is exactly the dogfood that proves the platform: the control plane's own operations become policy-governed, audited, durable workloads. That is the "self-controlling and describing" property — and it must remain optional capability, never a bootstrap dependency: the control plane must come up with no workflows running (invariant 8).

Constraints that keep it honest

  • Invariant 8 rules everything: temporal server start-dev + flow server --insecure-no-auth must keep working with zero admin configuration. The admin API is how a shared deployment is governed, not a prerequisite for a laptop.
  • The scoping ladder (#104) is the authorization model for admin operations too: a tenant-admin administers their namespace; a deployment-admin administers tenants. Both are CEL over claims, not a role table.
  • Fail closed at every rung: an admin RPC with no matching allow is denied; a policy swap that fails compilation is refused while the old policy holds (#104's reload seam).
  • Users who never open this door lose nothing: the whole admin surface is additive beside the workload surface, exactly as Temporal's operator API sits beside its workflow API.

Related: #104 (policy management — this issue is the service that hosts it), #94 (outbound identity — the minting this administers), #95 (temporal plugin — the reach-through), #100 (sandboxing — what tenant policy attaches), #106 (modules — tenant provisioning workflows are natural module exports), #98 (the lab where multi-tenant operation gets proven observable).

Contributor guide

Open the contributing guide

First steps

  1. Read the whole issue, then the project's contributing guide.
  2. Comment on the issue to say you are picking it up — it saves two people doing the same work.
  3. Fork the repository and make your change on a branch.
  4. Open a pull request that references the issue number.

Research direction

Start with ARCHITECTURE.md's layer table and the existing Connect RPC workload service, then read #104, #94, and #95 to understand policy, identity, and Temporal boundaries. A completed design should define the proto-first admin service, tenant and key lifecycle operations, authorization model, and the no-admin-configuration startup constraint; the issue names no implementation files or tests.

Written by the indexing model from the issue text.

Assessment

Tech stack
go
Domain
authentication, authorization, backend-api-design, distributed-systems
Issue type
Feature
Difficulty
5/5
Estimated time
Over a week
Activity status
Active
Clarity
Needs clarification
Newbie friendliness
28/100

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.