Chio/Docs
LOGIN · JOIN

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.

Deployment chio@5f63e6e

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.

Start
Authority daemonChoose an outcome.
active-defense hostresponse authority processsigned requestsigned responsesealed descriptorread-onlysigned healthKresponse kernelppinned clientτresponse authorityσsigning keysreviewed snapshotchio-active-response-authorityd✓ peer PID, UID, GID✓ deployment digest✓ pre-admitted plansigned response, bound to one deployment digestactive-defense hostresponse authority processKresponse kernelppinned clientτresponse authorityσsigning keysreviewed snapshot✓ peer PID, UID, GID✓ deployment digest✓ pre-admitted plansigned response, bound to one deployment digest

The pinned client gets a signed answer for a reviewed plan

The daemon reads the caller's PID, UID, and GID with SO_PEERCRED, checks the deployment and store digests the signed request binds, and looks the plan's admission artifacts up in the immutable snapshot it opened read-only. Response authorization.

The response authority as its own Linux process beside the active-defense host: the signing key it inherits, the snapshot it serves, and the one client it answers. The supervisor, the broker's paths, and the protocol's freshness and replay checks are left out.

1. 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.

Terminalbash
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 MANIFEST

Compute 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
security-host/review_response_authority.rsrust
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.

crates/security/chio-active-response-authority/src/config.rs27–44rust
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:

Terminalbash
chio security supervise \
  --credential-fd signing-key-fd=SIGNING-KEY \
  -- chio-active-response-authorityd \
  --config DEPLOYMENT

The 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:

  1. Health. It checks the response authority's signed health.
  2. Park. It parks itself.
  3. Bind. It binds the dedicated response kernel.
  4. Drain. It drains durable recovery synchronously.
  5. 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:

RefusalConditionOwner
Signed permanent rejection active_response.not_pre_admitted (AuthorityError::NotPreAdmitted)
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 (AuthorityError::InvalidConfig)
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

timeoutMs

u641 to 30,000

The request timeout in milliseconds: positive and at most 30,000.

maximumClockSkewSeconds

u641 to 30

The accepted clock skew: positive and at most thirty seconds.

maximumReplayEntries

usize1 to 65,536

The replay-protection capacity, between one and 65,536 entries.

workerCount

usize1 to 64

The number of request workers, between one and sixty-four.

queueCapacity

usizeworkerCount to 1,024

The request queue: at least the worker count and no greater than 1,024.

socketPath, storePath

PathBufAbsolute, distinct

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

schemaCode constant

The combined deployment the daemon requires at boot.

chio.active-response-authority.runtime-config.v1

schemaCode constant

The runtime projection extracted from the combined deployment.

chio.active-response-authority.bundle.v1

schemaCode constant

The pre-admission bundle the snapshot is built from.

chio.active-response-authority.store-manifest.v1

schemaCode constant

The manifest of a built store.

chio.active-response-policy-authority.v2

protocolCode constant

The signed request and response protocol.

Next: bind the plan this authority reviews