Add Delegated User Access and Private Connectivity
Let a user approve one source action while the broker reaches the source through a route that is not public.
System map · Day 09
Whole-system design
Five stable layers. Today's work is expanded and linked; the rest stays in context.
Product and authority
Covered — HelixWorks control plane · Generated application plane
People and product entry points
Design target · not proved
Delegated human authority is a worked design for a separately revocable path; the current source implements authentication only.
Identity and policy
Design target · not proved
The required user, tenant, audience, source, operation, and expiry intersection is specified but not implemented in the repository.
Delivery and desired state
Covered — CI and immutable artifactsAhead — Git desired state · Argo CD reconciliation
Cloud and orchestration
Covered — Terraform and AWS APIs · Kubernetes or EKS control plane
Accounts, VPC, DNS, and private paths
Design target · not proved
Private DNS, transit, VPN or Direct Connect, and source firewall policy are design-only until matching infrastructure exists.
Compute and traffic
Covered — Worker compute · Platform service workloads · Generated app workloadsAhead — Ambient mesh data plane
Storage and evidence
Covered — Evidence and observabilityAhead — Infrastructure state · Cluster desired and live state
Product data and artifacts
Design target · not proved
Delegated-grant revocation metadata is designed here, while the current source provides no durable delegated-grant store.
The enterprise problem and today’s slice
Enterprise problem: A private IP address does not decide whether a person may read a document, and a user token does not make a private route. Treating either as both creates a reachable source with the wrong authority.
Whole-course context: The platform already has an isolated preview and a machine identity for scheduled work. This day adds the optional human-authority path and the network path that the Connector Broker uses when an enterprise source must stay private.
Today’s slice: Implement a delegated read through a broker running in Kubernetes: exchange the user’s short-lived authorization code, intersect it with the workload grant, resolve the source in private DNS, and send the call through a VPC-to-enterprise route. The source remains the final record-level authorizer.
End-of-day evidence: A trace proves an allowed delegated read used the private endpoint; a public-DNS probe, a revoked grant, and an out-of-scope request each fail for different reasons while a scheduled machine-only read remains healthy.
Still unsolved: Generated-app login and sharing roles arrive in later days. The AWS account, VPN/Direct Connect, Transit Gateway, and production EKS details are made concrete in the infrastructure days; this day defines the workload-to-source contract they must satisfy.
Customer outcome and implementation focus
An employee chooses Connect as me only when a request needs that employee’s source permissions; scheduled indexing continues to use the existing workload grant. The implementation decision is to put token exchange, grant state, scope intersection, private DNS lookup, and audit evidence in Connector Broker—not in the generated app and not in the browser. The observable success is a source response tagged with a broker trace; revocation must stop the delegated path before any source call.
| Path | Customer-visible trigger | Decisive result |
|---|---|---|
| Delegated read | Employee approves a documents.read request | Broker obtains a short-lived source token, uses the private route, and returns only allowed documents. |
| Scheduled read | Refresh job runs without a person | Broker uses its workload grant only; it never inherits a prior employee’s access. |
| Revoked or out-of-scope read | Employee has revoked consent or requests an excluded collection | Broker returns 403 before calling the source and records a denial trace. |
Components in focus
Private connectivity is a chain of independent responsibilities. A failure at one link must not be reported as an authorization decision at another.
| Component or layer | Owner | Responsibility in this day |
|---|---|---|
| Generated application API | Application team | Starts a delegated action and receives a broker result; it stores no source refresh token. |
| Connector Broker Deployment | Connector platform | Exchanges authorization codes, calculates effective scope, calls the source, and emits audit events. It runs as bounded pods on EKS worker-node CPU and memory. |
| Kubernetes ServiceAccount and workload identity | Runtime platform | Gives Broker its own cloud/secret access; it is separate from the employee and from generated-app membership. |
| Authorization server | Enterprise identity team | Authenticates the employee and issues a short-lived authorization code/token with consented scopes. |
| Grant database | Connector platform | PostgreSQL stores encrypted grant metadata, subject, source tenant, scope set, expiry, and revocation version. It is authoritative for broker-side consent state. |
| Token cache | Connector platform | Redis caches only short-lived exchanged access tokens keyed by grant version; a revocation deletes this cache key. Redis is not the authority. |
| Secrets manager | Runtime platform | Holds the OAuth client secret and encryption key reference; pods fetch them through workload identity. |
| Private DNS and resolver | Network platform | Resolves source.corp.example to a private address only from approved VPC subnets. |
| VPN/Direct Connect, Transit Gateway, route table, firewall | Network platform and enterprise network team | Carries packets from EKS private subnets to the enterprise source and permits only Broker-to-source TCP 443. |
| Enterprise source API | Source owner | Applies its own tenant and record-level policy after transport succeeds. |
| Evidence store | Audit platform | Persists immutable trace, DNS answer class, route identity, grant version, source decision, and denial reason. |
Generated-application database: Not involved in this slice — the generated app receives an opaque broker operation ID, while grant and evidence state stay with their respective owning services.
Build the delegated-grant boundary
The browser must never hand a reusable source token to the generated app. Instead, it receives a one-time authorization code after user consent and sends that code to Broker over the existing authenticated application session. Broker performs the OAuth authorization-code exchange server-side, encrypts the refresh material if the source requires it, and returns an opaque operation result.
The employee starts an application action; Broker is the only component that talks to the authorization server and source API. The source API is deliberately shown before any network detail: it is the final authority, not a database that Broker can bypass.
def effective_scope(workload: set[str], delegated: set[str]) -> set[str]:
# A delegated request may use only permissions granted to both identities.
return workload & delegated
if grant.revoked_at or grant.expires_at <= now():
raise Forbidden("delegated consent is no longer active")
scope = effective_scope(workload_grant.scopes, grant.scopes)
if requested_scope not in scope:
raise Forbidden("requested source scope is outside the intersection")
Connector Broker evaluates this intersection before creating a source request. It reads the grant row from PostgreSQL and either derives the effective scope or emits a denial; it can never turn the two grants into a union. On denial, the trace records the workload grant, delegated-grant version, requested scope, intersection result, and source_call=false, proving that no source connection was opened.
Give the broker a private path to the source
The private route begins before TLS: Broker’s pod asks cluster DNS for the source name, CoreDNS forwards the private zone to the VPC resolver, and the resolver returns a private address. Packets then leave the pod through the CNI, traverse the EKS private subnet route table, Transit Gateway, and VPN or Direct Connect, and reach the source firewall. The firewall allows only Broker’s security group or egress address on TCP 443. TLS still verifies the source certificate; private routing is not a substitute for encryption.
The first four boxes retain their earlier meaning. The added DNS, route, and firewall boxes explain how a permitted request reaches the same source without publishing it. A route success proves only transport; source authorization still follows.
apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
name: connector-broker-egress
namespace: connectors
spec:
podSelector:
matchLabels:
app: connector-broker
policyTypes: [Egress]
egress:
- to:
- ipBlock:
cidr: 10.42.18.0/24 # Enterprise source private subnet, not 0.0.0.0/0.
ports:
- protocol: TCP
port: 443
The cluster CNI enforces this rule for Broker pods, while VPC routes and the enterprise firewall enforce the next boundaries. Allowed packets traverse the pod interface, node ENI, private subnet route, and private link; the policy does not create a VPN, DNS zone, or firewall rule. Verify the path with a flow log for Broker-to-10.42.18.0/24:443, then prove the boundary by showing that a public-IP request or a request to another subnet is denied.
Run the proof loop
An implementation is incomplete if it can show only an allowed request. Run the following against a disposable connector and a test source collection; record the exact grant, source, environment, and trace IDs.
kubectl -n connectors exec deploy/connector-broker -- \
getent hosts source.corp.example # The private answer must be in 10.42.18.0/24.
kubectl -n connectors exec deploy/connector-broker -- \
curl --fail --resolve source.corp.example:443:10.42.18.20 https://source.corp.example/health
# Confirms TLS plus the private path from the Broker pod.
kubectl -n connectors exec deploy/connector-broker -- \
curl --connect-timeout 3 https://198.51.100.20/health
# Expected failure: public source address is not reachable from this workload.
| Probe | Expected observation | What it proves |
|---|---|---|
| Active consent, matching workload scope, private DNS | 200 plus source request ID and trace ID | All authority and routing links worked for one bounded resource. |
| Revoke consent, then repeat the same request | 403, grant version changed, source_call=false | Broker enforced revocation before transport or source work. |
| Valid private route with excluded source scope | 403 from Broker or source policy | Reachability did not become permission. |
| Public DNS/address probe | Resolution or connection failure; no source public flow log | The source was not silently made public. |
| Scheduled workload-only refresh | 200 with no delegated grant ID | Machine work remains independent of human authority. |
Before and after, side by side
A direct application-to-source call either exposes the source or leaves consent and route evidence scattered across layers. The new design makes Broker the single place that intersects authority while the network team owns the route.
Key takeaways
- Delegated authority, workload authority, and private reachability are three independent controls; neither one implies either of the others.
- Broker owns token exchange, scope intersection, revocation, and evidence; PostgreSQL is durable authority and Redis is only a short-lived cache.
- Private DNS, routes, and firewalls carry packets to the source, while source policy still decides the record-level request.
- Prove the design with separate allowed, revoked, out-of-scope, public-path-denied, and workload-only checks.
Checklist
- [ ] Broker, not the browser or generated app, performs the authorization-code exchange.
- [ ] Effective scope is an intersection of current workload and delegated grants.
- [ ] Private DNS, route, firewall, TLS, and source policy each have independent evidence.
- [ ] Revocation deletes cache state and prevents the next source call.