The FC Agent is a small service you run in your own environment — typically as a single pod in your Kubernetes cluster. It connects outbound to FixControl over HTTPS and executes signed, expiring, single-use operations: approve or reject a paused CI deployment, promote a paused Argo rollout, or run a validation inside your cluster.
FixControl connects to private customer infrastructure through this outbound agent. Kubernetes, Argo, Jenkins and GitLab do not need to be exposed publicly to FixControl.
The agent is offered as part of pilot onboarding: FixControl provides the install package, the agent identity and the signing keys during enrolment, and the setup is validated together with your team.
Architecture
FixControl Cloud
(gates, approvals, evidence, audit)
▲
│ outbound HTTPS (initiated by the agent)
│
FC Agent ← runs in your environment
/ | \
/ | \
Kubernetes Argo Jenkins / GitLab
(private — none of these are exposed to FixControl)- The agent polls FixControl on a short, server-advertised interval. There is no push channel, no listener, no inbound socket: the agent's manifest ships no Service, no Ingress and no inbound network policy, and its health endpoint binds to localhost.
- FixControl registers an operation — the verdict of a decided gate, or a request to run a validation. The agent fetches it on its next poll, verifies it locally, executes it, and reports the result back — also outbound. Every execution verdict (approve, reject, promote) is a recorded human decision.
- Under the agent connection model FixControl opens no connection toward your network and holds no credential for your infrastructure.
Prerequisites
- A Kubernetes cluster (the agent runs as a Deployment; the install package is plain Kubernetes manifests rendered with Kustomize — no Helm required).
- Outbound HTTPS from the agent's namespace to FixControl (typically port 443), through your existing egress or proxy rules.
- The Kubernetes integration connected first — an agent registration is attached to that connection, and enrolment refuses without one.
- An enrolled agent identity: created under Settings → DevOps → fc-agents (or
POST /api/integrations/devops/agents). Enrolment shows the agent secret once and lists the FixControl signing keys to pin. - The capability armed: agent carriage stays off until an admin arms Hand the verdict to an fc-agent under Settings → Governance → Approvals → Deployment capabilities. Arming asks for a reason and is audited; disarming is one click. Until it is armed, gates open and decisions are recorded, but nothing is registered for the agent.
Networking
The agent's egress, in full:
allow egress agent namespace → FixControl (HTTPS, 443)
(for the hosted service: api.fixcontrol.ai —
the enrolment panel shows the exact URL as
"FixControl URL")
agent namespace → your manifests git remote
(only with the default GitOps promotion path)
agent namespace → your private GitLab / Jenkins
(only with CI verdict carriage)
agent namespace → kube-apiserver + cluster DNS
(the installer's NetworkPolicy adds these itself)
inbound rules needed: noneThe pipeline event still reaches FixControl through the CI host's own signed webhook — the agent carries the verdict back, not the event in. So a private CI host needs outbound HTTPS to FixControl too (or a proxy that provides it).
- The agent refuses to start against a plaintext
http://FixControl URL. TLS is verified; there is deliberately no "skip TLS verification" option. - Standard egress proxies work as long as the agent can reach the FixControl origin; the operation signature covers the request path, so intermediaries cannot repoint a request undetected.
- The agent's own health/metrics endpoint binds to
127.0.0.1and is probed in-pod.
Authentication and operation signing
Two independent mechanisms, with two independent keys:
- Transport authentication — every request the agent makes carries an HMAC-SHA256 signature under the agent's own per-agent secret, plus a timestamp with a bounded skew window. The secret is shown once at enrolment, stored by FixControl only in encrypted form, and can be rotated or revoked at any time; revocation takes effect on the next request.
- Operation authority — every operation is signed by FixControl with an Ed25519 key whose public half you pin in the agent's configuration. The agent contains no signing code for this key — it can verify operations, never mint them. A pinned agent refuses operations signed any other way, so the authority to order an action and the ability to talk to the API are cryptographically separate.
Operation lifecycle
Every operation is single-use, expiring and idempotent:
- Expiry — operations expire minutes after registration (default 5). An approval decided at 10:00 can never promote something at 16:00 because an agent was down; the expired operation is recorded as expired, visibly.
- Replay protection — each operation carries a random nonce. The agent keeps a persistent nonce ledger in its own namespace and refuses a nonce it has seen, reporting the refusal back with reason
replayrather than dropping it. - Idempotent settlement — an operation settles once. A conflicting second result is recorded as a conflict and does not rewrite the first.
- Addressed, not broadcast — an operation names one cluster and one capability, and CI verdicts are additionally pinned to the specific agent named on the connection. The pin travels inside the signature.
Capabilities and local allowlists
The operation vocabulary is closed: approve/reject a CI deployment, promote/abort/read an Argo rollout, run/cancel a validation. There is no "run this command" operation.
What an agent may actually execute is decided in three places, and the last one is entirely yours:
- The registration in FixControl grants the agent a capability set.
- Every poll intersects that grant with what the running agent advertises — neither side can widen the other.
- The agent's local allowlists (
FC_ALLOWED_NAMESPACES,FC_ALLOWED_ROLLOUTS, and theFC_AGENT_CAPABILITIEStoggle set) live in your cluster's configuration. FixControl never sends them and cannot override them. An empty namespace allowlist means nothing is allowed — the installer refuses an install that leaves it empty by accident.
Kubernetes permissions (RBAC)
The agent runs under a minimal Role, and validation runs under a separate ServiceAccount:
- Agent —
get/liston Argo Rollouts in the namespaces you allow, plusget/updateon exactly one named ConfigMap (its nonce ledger). By default it holds no write verbs on rollouts at all: the default promotion path is a GitOps marker commit that your own in-cluster tooling verifies and applies. The pod is hardened (non-root, read-only root filesystem, all capabilities dropped, digest-pinned images). - Validation runner — a separate ServiceAccount in its own namespace that creates short-lived test namespaces, deployments, services and jobs, and cannot reach Argo resources at all. A ValidatingAdmissionPolicy (enforced by the API server, applied by the installer by default) rejects any write by this identity outside its own
fc-test-*namespaces.
Compromising the component that runs test code must never yield rollout control — that is why they are two identities.
Argo and CI connectivity
- Argo Rollouts — the agent observes rollout state and, after an approved gate, promotes through the configured path. The default is a GitOps marker commit verified by your own promotion tooling against the live rollout; granting the agent direct rollout-API access is a separate, off-by-default choice.
- Jenkins / GitLab (private) — the CI credential lives in a secret in your cluster, deliberately separate from the agent's FixControl identity, so the two rotate independently. The operation envelope for CI verdicts carries no target URL — the agent only talks to the CI host address configured on your side, so a compromised cloud cannot point the agent at an arbitrary internal address.
- Details of what a gate does per CI host are in DevOps & CI/CD.
Secrets
| Secret | Lives | Rotated by |
|---|---|---|
| Agent transport secret | Your cluster + encrypted in FixControl | You, via rotate (shown once) |
| FixControl signing keys (public) | Pinned in the agent's config | Updated at enrolment/rotation |
| Kubernetes access | The agent's in-cluster ServiceAccount | Kubernetes |
| GitLab / Jenkins credential | A secret in your cluster | You |
| Validation-run secrets | Referenced by name; bindings are set up during pilot onboarding so values stay in your cluster | You |
Secret values for validation runs never appear in FixControl's stores, operation payloads, logs or evidence.
Evidence and health
- Every operation result — success, failure, refusal, expiry — is reported back and lines up with the approval that caused it in one audit trail.
- Agent connectivity is a first-class health capability: a missed heartbeat shows as degraded within minutes, per agent, rather than hiding behind a generic "connected" state.
- Validation runs report the same evidence contract as FixControl's isolated Docker validation: environment hash, image digests, executed plan, result. See Change validation.
Failure modes
- FixControl unreachable — your workloads keep running; the agent simply collects no new operations. It retries transient failures with backoff and re-signs each attempt with a fresh timestamp; permanent (4xx) failures are not retried blindly.
- Agent down — pending operations expire visibly; the gate's approval stays recorded, and the timeline shows that execution did not happen. Nothing executes late.
- Refusals — an operation outside the local allowlist, an unknown capability, a replayed nonce or a downgrade attempt is refused, and the refusal is reported and recorded as a governance finding.
- Degraded nonce storage — if the agent cannot write its nonce ledger, it falls back to in-memory tracking with a loud warning and a metric; the replay window is then bounded by the operation expiry (minutes).
Install, upgrade, uninstall
The install package (provided at enrolment) contains the manifests, an idempotent install.sh driven by a single values.env, a verify.sh that checks the result, plus rotate/revoke/uninstall scripts. Images are digest-pinned by default. Upgrading is re-running the installer with the new digests; uninstalling is the uninstall script plus revoking the agent in Settings → DevOps, after which its requests are refused.
Troubleshooting
- Agent unhealthy right after install — the health probe reports ready only after the first successful poll; check outbound reachability to FixControl and the enrolment values.
- Operations expire without being executed — the agent is not polling (egress blocked, secret revoked, pod down) or is enrolled against a different cluster ID than the operation targets. Both surface in connectivity health and the audit trail.
- A verdict was approved but nothing moved — check the operation on the approval's timeline: an expiry, a refusal (with its reason) or a delivery retry is recorded there rather than lost.
See also: DevOps & CI/CD · Change validation · Security & audit.