Skip to navigation

APF Gateway Interceptor for OpenShell

View as Markdown

APF’s gateway interceptor puts OpenShell’s control plane under signed policy. It injects the signed sandbox policy at admission, refreshes it on running sandboxes, and refuses direct policy edits, agent-authored proposals, draft approvals, and provider and profile changes outside the bundle. It does not bind every OpenShell RPC that can affect a sandbox. Refer to Enforcement Coverage and Limitations. It runs inside apf-policy-gateway and implements OpenShell’s openshell.gateway_interceptor.v1.GatewayInterceptor service.

Manifest

APF returns this manifest from Describe:

FieldValue
nameapf/policy-adapter
failure_policyfail_closed
provider_profilestrue. APF implements SnapshotProviderProfiles.
expected_audienceThe audience in the listener’s trust profile, or empty in insecure mode.
Extension protocol1.0, requiring openshell.gateway-interceptor.contract.

Bindings

APF declares 14 bindings. Every governance binding fails closed. The two post-commit bindings are observational and fail open, as OpenShell requires.

BindingRPCPhaseFailure policyAPF behavior
sandbox-policy-injectCreateSandboxModifyFail closedInjects the signed sandbox policy and provenance annotations.
sandbox-policy-verifyCreateSandboxValidateFail closedRe-verifies provenance and the spec digest.
sandbox-policy-post-commitCreateSandboxPost-commitFail openLogs the committed admission. No audit record is written.
sandbox-policy-refreshUpdateConfigModifyFail closedInjects the current signed policy into a refresh, and denies direct policy edits and approval-mode changes.
config-policy-verifyUpdateConfigValidateFail closedVerifies the injected provenance and rejects post-injection changes.
config-policy-post-commitUpdateConfigPost-commitFail openLogs the committed configuration change. No audit record is written.
provider-instance-create-verifyCreateProviderValidateFail closedAllows only provider types the bundle manages.
provider-instance-update-verifyUpdateProviderValidateFail closedAllows only provider types the bundle manages.
provider-profile-import-verifyImportProviderProfilesValidateFail closedAllows only bundle-managed profiles whose content matches the bundle.
provider-profile-update-verifyUpdateProviderProfilesValidateFail closedAllows only a bundle-managed profile whose content matches the bundle.
provider-profile-delete-verifyDeleteProviderProfileValidateFail closedAlways denies.
policy-analysis-verifySubmitPolicyAnalysisValidateFail closedDenies agent-authored proposals. Allows mechanistic proposals so OpenShell can collect denial telemetry.
draft-chunk-approve-verifyApproveDraftChunkValidateFail closedAlways denies.
draft-chunk-approve-all-verifyApproveAllDraftChunksValidateFail closedAlways denies.

Every RPC uses the openshell.v1.OpenShell/ service prefix. Register APF with OpenShell’s default binding_policy = "dynamic". OpenShell’s allowlist and exact policies accept only one binding per configured RPC, and APF declares three each on CreateSandbox and UpdateConfig, so exact stops the OpenShell gateway from starting and allowlist cannot include admission. Refer to OpenShell gateway interceptors.

Governance Decisions

Governance decisions write an audit record to apf-policy-gateway-interceptor-audit.jsonl. A few outcomes write none: a refresh denied because the served projection has no provenance token, a sandbox creation or refresh that fails because the policy service is unreachable, a successful configuration validation, an allowed settings-only update, and post-commit calls. Provider operations do record an unreachable policy service, as interceptor.govern_denied.policy_service_unavailable. Admission decisions are listed on Sandbox Admission. The others are:

Reason codeOperationMessage returned to OpenShell
interceptor.govern_denied.direct_policy_mutationUpdateConfig with a policy or merge operationsdirect policy mutation not permitted; policy is managed by APF
interceptor.govern_denied.approval_mode_changeUpdateConfig that changes the proposal approval modeapproval mode is managed by APF
interceptor.govern_denied.body_digest_mismatchRefresh where the served body does not match its tokenpolicy body digest mismatch
interceptor.govern_denied.policy_identity_mismatchRefresh where the response disagrees with its tokenresponse policy identity disagrees with the token
interceptor.validate_denied.post_injection_mutationRefresh that gained merge operations or approval settings after APF injected policy, or a settings-only update that still carries APF’s provenance annotationconfig policy integrity check failed
interceptor.validate_denied.spec_digest_mismatchRefresh whose policy changed or was removed after APF injected itconfig policy integrity check failed
interceptor.validate_denied.provenance_missing, interceptor.validate_denied.provenance_invalidRefresh whose provenance annotations are missing or do not verifyconfig policy integrity check failed
interceptor.validate_denied.approval_mode_changeSettings-only update that changes the approval mode, in the validate phaseapproval mode is managed by APF
interceptor.govern_denied.unmanaged_provider_typeCreateProvider, UpdateProviderprovider type '<type>' is not a bundle-managed profile
interceptor.govern_denied.unmanaged_provider_profileImportProviderProfiles, UpdateProviderProfilesprovider profile '<id>' is not managed by the APF bundle
interceptor.govern_denied.profile_content_mismatchImportProviderProfiles, UpdateProviderProfilesprovider profile '<id>' content does not match the APF bundle
interceptor.govern_denied.profile_deleteDeleteProviderProfileprovider profiles are bundle-managed; delete is not permitted
interceptor.govern_denied.agent_authored_proposalSubmitPolicyAnalysisagent-authored policy proposals are not permitted; policy is managed by APF
interceptor.govern_denied.draft_approvalApproveDraftChunk, ApproveAllDraftChunkspolicy proposal approval is not permitted; policy is managed by APF
interceptor.govern_denied.policy_service_unavailableProvider operations when the bundle’s profiles cannot be read... governance check failed: policy service unavailable

Allowed governance operations are recorded too, for example with interceptor.provider_type_allowed, interceptor.provider_profiles_allowed, and interceptor.policy_analysis_allowed. Every denial also carries the correlation ID in OpenShell’s log annotations under apf.nvidia.com/correlation-id, so OpenShell’s log entry and APF’s audit record join on it.

Provider Profile Snapshots

When OpenShell lists APF’s interceptor in provider_profile_sources, it calls SnapshotProviderProfiles to read the bundle’s provider catalog. APF builds the snapshot from the policy service’s openshell.provider-profile.v1 documents and verifies each one:

  • The provenance token’s signature verifies, and its signer is the configured document key ID.
  • The token names a bundle and a non-zero version, and the version and digest match the response.
  • The body hashes to the digest.
  • Every document comes from the same bundle and version. If the policy changes during the snapshot, the snapshot fails rather than mix identities.

The snapshot revision is a hash of the verified content, the bundle identity and version, and the verifier identity, so it changes when the catalog, the bundle revision, or the verifying key changes. Any invalid profile fails the whole snapshot.

Caller Authentication

Only the OpenShell gateway may call the interceptor. In authenticated mode, every call must carry a valid OpenShell extension JWT for the interceptor’s audience, and APF rejects supervisor credentials. Refer to Configure Service Authentication.

The interceptor accepts gRPC messages up to 8 MiB.

Failure Behavior

FailureResult
The policy service is unreachable during admission or refresh.APF returns an error, and OpenShell applies the binding’s failure policy. APF declares these bindings fail-closed, so the operation is refused.
APF is unreachable.OpenShell applies each binding’s failure policy. Governance bindings are fail-closed, so governed operations are refused. Post-commit bindings are fail-open.
A provenance or digest check fails.APF returns a deny with a reason. A deny always refuses the operation, regardless of failure policy.
A post-commit observation fails.Logged. The committed operation stands.

Next Steps