Response authority service
Run the separate daemon that approves response plans, pinned to the one process allowed to ask it and to one validated deployment digest.
On this page
chio-active-response-authorityd runs on Linux as its own process, serves an immutable reviewed snapshot over a private Unix socket to one pinned client process, and starts only under the deployment digest you reviewed.
A compromised runtime cannot approve its own containment plan: the component that collects suspicious activity and the authority that permits containment hold distinct identities, keys, and stores. The executor consults the authority under the admitted service contract before it applies a response, and the active-defense host waits for the authority's signed health before it serves.
Start1. Build the reviewed snapshot
Start from a reviewed authority bundle and a complete combined deployment draft. The commands take complete documents that conform to the closed authority-bundle and combined-deployment schemas; the uppercase names are file arguments.
chio security authority-store digest --input BUNDLE
chio security authority-deployment digest --input DEPLOYMENT-DRAFT
chio security authority-deployment validate --input DEPLOYMENT
chio security authority-store build \
--input BUNDLE --output STORE --manifest MANIFESTCompute the bundle's content digest and bind it into the draft, then compute the deployment digest, populate the digest fields, validate the final deployment, and build the store. Validation runs before the build, so only a valid deployment yields a snapshot, and the content digest excludes the deployment digest so the bootstrap has no circular hash. The builder creates new private database and manifest files and leaves any existing file in place.
The integration below does the same from Rust, running as the intended service UID with chio-active-response-authority, chio-control-plane, and chio-security-types/std. The draft already carries the independent service and client identities, fresh process pins, separated broker paths, and the final private store path. The expected digest comes from the reviewing owner, never from whatever the builder computes.
Snapshot builder and read-only lookup, review_response_authority.rs
use chio_active_response_authority::{
build_authority_store, compute_authority_store_digest, ActiveDefenseDeploymentConfig,
AuthorityStore, AuthorityStoreBundle, AuthorityStoreManifest, Result,
};
use chio_control_plane::security::ActiveResponseAdmissionArtifactsDraftWire;
use chio_security_types::ports::{AdmissionArtifactRef, Digest32};
use chio_security_types::ResponsePlan;
use std::path::Path;
/// Operator-side build with an independently reviewed expected final digest.
/// Fresh process pins and the intended output paths are already in the draft.
/// Returns the bound configuration and the builder's actual manifest.
pub fn build_reviewed_snapshot(
mut bundle: AuthorityStoreBundle,
mut draft: ActiveDefenseDeploymentConfig,
reviewed_final_digest: Digest32,
database: &Path,
manifest: &Path,
) -> Result<(ActiveDefenseDeploymentConfig, AuthorityStoreManifest)> {
if database != draft.response_authority.store_path
|| bundle.authority_identity != draft.response_authority.authority_identity
{
return Err(
chio_active_response_authority::AuthorityError::InvalidConfig(
"reviewed store path and authority identity must match the draft".into(),
),
);
}
draft.response_authority.store_digest = compute_authority_store_digest(&bundle)?;
let deployment_digest = draft.compute_deployment_digest()?;
if deployment_digest != reviewed_final_digest {
return Err(
chio_active_response_authority::AuthorityError::InvalidConfig(
"computed deployment differs from independently reviewed final digest".into(),
),
);
}
draft.deployment_digest = deployment_digest;
draft.response_authority.deployment_digest = deployment_digest;
bundle.deployment_digest = deployment_digest;
draft.validate()?; // no output mutation until the complete binding validates
let built = build_authority_store(&bundle, database, manifest)?;
Ok((draft, built))
}
/// Validate the exact reviewed deployment and open its private snapshot read-only.
/// The caller is the intended service UID; process startup still verifies Linux
/// custody, inherited signing key and the actual pinned client/service identities.
pub fn inspect_authority_snapshot(
deployment: &ActiveDefenseDeploymentConfig,
reviewed_deployment_pin: Digest32,
store_path: &Path,
original_plan: &ResponsePlan,
artifact: &AdmissionArtifactRef,
) -> Result<ActiveResponseAdmissionArtifactsDraftWire> {
deployment.validate()?;
if deployment.deployment_digest != reviewed_deployment_pin {
return Err(
chio_active_response_authority::AuthorityError::InvalidConfig(
"configuration differs from the independently reviewed deployment".into(),
),
);
}
let config = &deployment.response_authority;
if store_path != config.store_path {
return Err(
chio_active_response_authority::AuthorityError::InvalidConfig(
"inspection must use the configured original store".into(),
),
);
}
let store = AuthorityStore::open(
store_path,
config.trusted_service_uid,
config.deployment_digest,
config.store_digest,
&config.authority_identity,
)?;
store.health()?;
store.load_artifacts(original_plan, artifact)
}
/// In-memory validation control; writes no serving configuration or store.
pub fn refuse_substituted_deployment(reviewed: &ActiveDefenseDeploymentConfig) -> Result<()> {
reviewed.validate()?;
let mut changed = reviewed.clone();
changed.response_authority.timeout_ms = if changed.response_authority.timeout_ms == 5_000 {
6_000
} else {
5_000
};
assert!(changed.validate().is_err());
// Recomputing a digest names a different deployment. It does not approve it.
assert_ne!(
changed.compute_deployment_digest()?,
reviewed.deployment_digest
);
Ok(())
}You should see the bound configuration and the builder's manifest, which carries the content and deployment digests, the authority identity, and record counts; retain both with the reviewed bundle. A lookup of the original plan returns its pre-admitted artifacts and applies no effect, and a plan absent from the snapshot returns NotPreAdmitted. The substituted-timeout control changes one value in memory: validation refuses it, and its recomputed digest names a different deployment for its own review.
2. Bind the deployment digest
ActiveDefenseDeploymentConfig and load_runtime_config revalidate the combined deployment's normalized digest before extracting the runtime projection the daemon serves. The normalized digest clears only its own two digest fields and commits the rest of the configuration.
A store, deployment, authority, or record-count mismatch fails closed, and the daemon stays down. Requests and responses carry the same binding: protocol v2 signs the deployment and store digests into both, with freshness, replay protection, peer credentials, and one absolute I/O deadline. The schema identifiers are code constants, listed in the reference below.
3. Configure independent identities and bounds
The runtime projection declares the service's identity, its one client, the reviewed snapshot, and its resource bounds. Serialized configuration uses camelCase field names.
pub struct AuthorityRuntimeConfig {
pub schema: String,
pub protocol: String,
pub socket_path: PathBuf,
pub store_path: PathBuf,
pub trusted_service_uid: u32,
pub service_identity: PeerIdentity,
pub expected_client_peer: PeerIdentity,
pub trusted_client: PublicKey,
pub authority_identity: PublicKey,
pub deployment_digest: Digest32,
pub store_digest: Digest32,
pub timeout_ms: u64,
pub maximum_clock_skew_seconds: u64,
pub maximum_replay_entries: usize,
pub worker_count: usize,
pub queue_capacity: usize,
}The daemon accepts the pinned broker process as its one client. serviceIdentity and expectedClientPeer name distinct processes with nonzero process IDs, and the authority identity differs from the trusted client signing key. Each pinned identity is an exact PID, UID, and GID that the daemon reads from the kernel over SO_PEERCRED. The launcher binds a fresh PID at every start and the authority pins no binary digest, so after a supervisor restart you correct the trusted deployment binding to the new process identity.
The authority signing key and the dedicated executor key have separate custody and never alias broker, capability, receipt, manifest, or administrative roles. Keep the socket and store paths absolute and distinct. The bounds limit resource use, and an expired or replayed request stays refused under any load.
4. Start the daemon under its own custody
The daemon takes only --config and --signing-key-fd. The trusted supervisor passes the authority's own signing key as a sealed inherited descriptor, following the descriptor supervision procedure with the authority's role:
chio security supervise \
--credential-fd signing-key-fd=SIGNING-KEY \
-- chio-active-response-authorityd \
--config DEPLOYMENTThe daemon hardens its process custody before it loads the runtime configuration or serves a request. It then compares its own PID, UID, and GID with serviceIdentity, opens the reviewed snapshot read-only, recomputes its logical digest, validates every record and lookup key, and loads the immutable image it serves. You should see the daemon serving only once all of these pass.
It needs the combined deployment, since that carries the digest, broker process identity, and privileged path separation it checks at boot; a standalone response-authority subset cannot start it. On an operating system other than Linux it refuses to build its runtime, because it serves only with kernel-authenticated peer credentials.
5. Start the active-defense host after the authority
The host starts in a fixed order:
- Health. It checks the response authority's signed health.
- Park. It parks itself.
- Bind. It binds the dedicated response kernel.
- Drain. It drains durable recovery synchronously.
- Ready. It publishes full readiness, and only then accepts product traffic.
A missing listener, a failed peer check, a failed signature, or an unhealthy authority stops startup before the host publishes. Exhausting a recovery bound holds readiness and keeps the outstanding response state. A snapshot changed after an error never retroactively authorizes an effect already retained as unresolved, so change the deployment through the snapshot workflow and the bounded configuration.
Every refusal stops before a control applies
The daemon closes a connection from any PID, UID, or GID other than the pinned peer, sends no response, and keeps serving its other connections. Two refusals carry a stable code or message:
| Refusal | Condition | Owner |
|---|---|---|
Signed permanent rejection active_ (Authority) | The finding's policy selection or the plan's admission artifacts are absent from the reviewed snapshot | Authority, per request |
"active-response authority configuration is invalid: deployment digest does not match the normalized configuration" on stderr, exit 1 ( Authority) | The recorded deployment digest differs from the normalized contents | Authority, at startup |
For not_pre_admitted, compare the original finding and plan with the reviewed snapshot; when new artifacts are needed, review and build a new bound snapshot and leave the serving image as it is. For InvalidConfig, recompute the content digest and then the deployment digest, populate the final fields, and validate both sides before rebuilding or starting. After a process restart, provision and review fresh process pins before readiness.
Before enforcement, test a substituted peer, a wrong deployment digest, and a mismatched snapshot, and confirm that none applies a control. Rollout decides when this service moves from shadow to enforcement, and hardening covers the deployment checks around it.
Runtime configuration bounds and schema identifiers
Search for timeoutMs, workerCount, or bundle.
timeoutMs
The request timeout in milliseconds: positive and at most 30,000.
maximumClockSkewSeconds
The accepted clock skew: positive and at most thirty seconds.
maximumReplayEntries
The replay-protection capacity, between one and 65,536 entries.
workerCount
The number of request workers, between one and sixty-four.
queueCapacity
The request queue: at least the worker count and no greater than 1,024.
socketPath, storePath
The private Unix socket and the immutable snapshot. Both are absolute and distinct, and the store's digest is established before the daemon serves.
chio.active-defense.deployment-config.v1
The combined deployment the daemon requires at boot.
chio.active-response-authority.runtime-config.v1
The runtime projection extracted from the combined deployment.
chio.active-response-authority.bundle.v1
The pre-admission bundle the snapshot is built from.
chio.active-response-authority.store-manifest.v1
The manifest of a built store.
chio.active-response-policy-authority.v2
The signed request and response protocol.