# System-signed intent configuration

Use this page to understand the configuration and governance steps that support API-only system-signed intent submission. The examples show possible deployment shapes; key storage, certificate handling, service-caller identity, policy design, and rollout sequencing depend on your environment.

This page applies to on-premise deployments only. For current defaults and the full supported schema, use the configuration packaged with your release.

## What this config controls

System-signed intents let an API service caller submit selected proposal types without sending a client-side payload signature. The platform signs the proposal internally, and policy evaluation admits it only when a matching policy uses `intentOrigin: "SystemSigned"`.

Current release packages enable the system-signed intent configuration by default at deployment level. This makes Gateway and Notary capable of processing the flow, but it does not activate system-signed traffic by itself.

System-signed intents remain disabled until Notary is activated through governed state:

- The Gateway system signing public key is registered with `purpose: "SystemSignatures"`.
- `NOTARY_SYSTEM_SIGNED_INTENTS_ENABLED` is set to `enabled: true`.
- At least one policy with `intentOrigin: "SystemSigned"` matches the proposal.


## Typical use cases

System-signed intents are useful for service-to-service automation where a trusted platform service needs to propose a narrow set of repeatable intents, but you do not want that service to hold or manage a user signing key.

Use cases that fit this model include:

| Use case | Example intent types | Why system-signed intents help |
|  --- | --- | --- |
| Omnibus deposit wallet provisioning | `v0_CreateAccount` | Omnibus can create deposit wallets for virtual accounts when they are needed, without asking a user to sign every service-generated wallet creation. |
| Omnibus deposit sweeps | `v0_CreateTransactionOrder` | Omnibus can move funds from deposit wallets into the omnibus wallet after confirmation and quarantine release, while still passing through Notary and policy controls. |
| Omnibus ledger propagation | `v0_AddAccountLedgers` | Omnibus can keep deposit wallet ledger coverage aligned with the omnibus wallet when supported ledgers are added. |
| High-volume operational automation | Explicitly selected intent types | A service can propose routine, policy-approved changes through the normal intent lifecycle without introducing a long-lived bot-user signing key. |


The first documented product use case in this release is Omnibus automation. User-triggered Omnibus flows, such as omnibus creation and withdrawals, still return unsigned Custody intents for the client to sign and submit through the normal user-signed intent flow.

System-signed intents are not a shortcut around governance. Use them only where the service caller, intent type, target domain, and policy conditions can be tightly scoped. Keep policy creation, broad administrative changes, and user-initiated business decisions on the normal user-signed path unless your governance process explicitly approves a different model.

## Control points

| Control | Where it appears | Use |
|  --- | --- | --- |
| Gateway signer wiring | `silo.gateway.system-signed-intents.kms-connect` | Configures Gateway access to the dedicated KMS Connect signing endpoint. |
| Gateway signing key storage | `operations.gateway_system_signing_key` | Stores the Gateway-minted wrapped signing key and public key metadata. |
| System signing key discovery | `GET /v1/system-signing/info` | Returns the Gateway-minted public signing key for Notary registration. |
| Notary config gate | `silo.approval-notary.system-signed-intents.enabled` | Enables the Notary code path for system-signed requests. |
| Runtime system property | `NOTARY_SYSTEM_SIGNED_INTENTS_ENABLED` | Enables or disables processing at runtime through governed system state. |
| Active signing key pointer | `NOTARY_SYSTEM_SIGNING_KEY` | Identifies the public key Notary uses to verify system signatures. Despite the name, this is the Gateway signing key, not a Notary key. |
| Policy origin | `intentOrigin: "SystemSigned"` | Allows a policy to match system-signed proposals. |


## Gateway signing configuration

Location: `silo.gateway.system-signed-intents`

| Parameter | Type | Description |
|  --- | --- | --- |
| `kms-connect.enabled` | boolean | Whether Gateway builds the live KMS-backed system signer. If disabled or absent, system-signed proposals fail before signing. |
| `kms-connect.channel.hostname` | string | Hostname for the Gateway-dedicated KMS Connect endpoint. |
| `kms-connect.channel.port` | int | gRPC port for the KMS Connect endpoint. |
| `kms-connect.channel.use-plaintext` | boolean | Whether Gateway uses plaintext transport to the signing endpoint. |
| `kms-connect.channel.trust-store-file-path` | string | Trust-store file path for TLS connections. |
| `kms-connect.channel.client-certificate` | object | Client certificate material used when mutual TLS is configured. |
| `kms-connect.channel.certificate-subject-override` | string | Optional certificate subject override. |
| `kms-connect.channel.keep-alive-interval` | duration | gRPC keep-alive interval. |
| `kms-connect.channel.keep-alive-timeout` | duration | gRPC keep-alive timeout. |
| `kms-connect.channel.max-inbound-message-size` | int | Maximum inbound gRPC message size. |


There is no Gateway `key-material-path` setting for system-signed intents. Gateway does not load a pre-provisioned wrapped signing key from a mounted file. It mints and stores the signing key automatically, as described in [Automatic key provisioning](#automatic-key-provisioning).

## Deployment patterns

| Pattern | Use when | Notes |
|  --- | --- | --- |
| Sidecar signing component | A single Gateway replica uses a local signing component. | The signing endpoint can be bound to loopback inside the Gateway pod. |
| Standalone signing component | Multiple Gateway replicas need to share the same system signing key. | Use a service endpoint, mutual TLS, and network controls so only Gateway can call the signing endpoint. |


The signing component is a dedicated KMS Connect instance for Gateway, commonly configured with `platform: kms_soft`. Do not reuse the Notary KMS Connect instance for system-signed intents. The system signing key must remain separate from Notary collection-signing, messaging, and user API signing keys.

## Chart-level fields

The chart values for this feature may group the related Gateway and signing-component settings under a `systemSignedIntents` section.

| Parameter | Description |
|  --- | --- |
| `systemSignedIntents.enabled` | Chart-side orchestration flag for rendering the related system-signed intent resources. In current release packages this is enabled by default. |
| `systemSignedIntents.sidecar.enabled` | Whether to run the signing component as a Gateway sidecar. |
| `systemSignedIntents.platform` | KMS Connect platform for the Gateway-dedicated signing component. |
| `systemSignedIntents.kms_soft.master` | Master wrapping key material for a `kms_soft` signing component. Use a secret reference in production. |
| `systemSignedIntents.kms_soft.autoGenerate` | Whether the chart generates and preserves a master wrapping key for the signing component. |
| `systemSignedIntents.kms_soft.existingSecret` | Existing secret reference for the master wrapping key. |
| `systemSignedIntents.kmsConnect.hostname` | Gateway-facing signing endpoint hostname. |
| `systemSignedIntents.kmsConnect.port` | Gateway-facing signing endpoint port. |
| `systemSignedIntents.kmsConnect.usePlaintext` | Whether Gateway uses plaintext transport to the signing endpoint. |
| `systemSignedIntents.kmsConnect.tls.existingSecret` | Existing secret containing TLS material for standalone signing deployments. |


## Example

This example shows the shape of a sidecar-style deployment. Use the exact values and secret names from your release package and secret-management process.


```yaml
systemSignedIntents:
  enabled: true
  sidecar:
    enabled: true
  platform: kms_soft
  kms_soft:
    existingSecret:
      name: gateway-system-signing-master
      key: master
  kmsConnect:
    hostname: 127.0.0.1
    port: 10000
    usePlaintext: true
```

This configuration wires Gateway to the dedicated signing component. It does not register the Gateway public key in Notary, enable the runtime system property, or create policies.

## Automatic key provisioning

Gateway provisions the system signing keypair automatically on first boot.

1. Gateway queries `operations.gateway_system_signing_key` for an active key row.
2. If an active row exists, Gateway loads the wrapped key and public key metadata.
3. If no active row exists, Gateway asks the dedicated KMS Connect instance to generate an Ed25519 keypair.
4. Gateway stores the wrapped private key, public key, creation time, and active flag in `operations.gateway_system_signing_key`.
5. On each system-signed proposal, Gateway sends the wrapped key to the dedicated signing component for signing. Gateway does not hold the unwrapped private key.


The dedicated KMS Connect instance does not persist the Gateway signing key. It holds the master wrapping key used to wrap and unwrap the Gateway signing key during generation and signing. The wrapped signing key lives in the Gateway database.

The Gateway-minted public key is not automatically trusted by Notary. Notary trusts only the key referenced by the governed `NOTARY_SYSTEM_SIGNING_KEY` system property. Register the Gateway public key before sending system-signed traffic. Gateway refuses to sign until its key matches the registered `NOTARY_SYSTEM_SIGNING_KEY`.

## System signing info endpoint

Call `GET /v1/system-signing/info` to retrieve the public key that Gateway minted:


```sh
curl -X GET "${CUSTODY_API_URL}/v1/system-signing/info" \
  -H "Authorization: Bearer ${JWT_TOKEN}"
```

The response lists the Gateway signing keys, newest first. The active key is the key with `active: true`.


```json
{
  "signingKeys": [
    {
      "publicKey": "MCowBQYDK2VwAyEA...",
      "createdAt": "2026-06-26T12:00:00.000Z",
      "active": true
    }
  ]
}
```

The endpoint returns only public key material and bookkeeping fields. It never returns the wrapped private key.

This endpoint is for inspection and registration. It does not regenerate or rotate Gateway signing keys.

This release provisions the system signing key automatically and does not provide an API to regenerate or rotate it.

## Activate system-signed intents in Notary

After the deployment can sign system-signed proposals, governance must allow Notary to verify and process them.

1. Retrieve the active Gateway public key with `GET /v1/system-signing/info`.
2. Register the key during [Genesis](/products/custody/governance/genesis/payload-reference#system-signatures-public-key), or after launch with `v0_RegisterTrustedPublicKey` and `purpose: "SystemSignatures"`.
3. Enable the runtime property `NOTARY_SYSTEM_SIGNED_INTENTS_ENABLED`.
4. Create policies with `intentOrigin: "SystemSigned"` for the specific intent types and service callers you want to allow.
5. Submit system-signed proposal bodies with `request.type: "SystemSigned"`.


### Register the Gateway public key

For post-genesis registration, submit a user-signed intent with a payload similar to the following:


```json
"payload": {
  "publicKey": "MCowBQYDK2VwAyEA...",
  "purpose": "SystemSignatures",
  "type": "v0_RegisterTrustedPublicKey"
}
```

When this intent executes, Notary adds the public key to the trusted public key collection and sets `NOTARY_SYSTEM_SIGNING_KEY` to that key. The legacy `v0_AddTrustedPublicKeysForMigration` intent is not a registration path for `SystemSignatures` keys.

### Enable runtime processing

After the signing key is registered, submit a user-signed `v0_SetSystemProperty` intent with a payload similar to the following:


```json
"payload": {
  "value": {
    "type": "NotarySystemSignedIntentsEnabledProperty",
    "value": {
      "enabled": true
    }
  },
  "type": "v0_SetSystemProperty"
}
```

If the deployment configuration is present but this property is absent or set to `false`, system-signed proposals remain disabled.

## Security considerations

System-signed intents let an API service caller submit proposals with a JWT and no client-side user signature. Keep the controls narrow:

- Scope each `SystemSigned` policy to the smallest required set of `intentTypes`.
- Check both `submitter.custodyRoles` and `submitter.subject` in policy conditions, so a role alone is not enough to match the policy.
- Use approval workflows for high-risk intent types. Omit `workflow` only when automatic execution has been assessed and approved.
- Govern identity provider role assignments for service callers with the same change control you apply to custody policies.
- Keep the Gateway signing component separate from Notary KMS Connect.
- Monitor signature verification failures and unusual request rates per service caller.
- For incident response, disable `NOTARY_SYSTEM_SIGNED_INTENTS_ENABLED`, lock or tighten the matching `SystemSigned` policies, or disable the service account at the identity provider.


## Related topics

- [Intent request structure](/products/custody/governance/intents/intent-request-structure#system-signed-proposal-request-body)
- [Manage intents and approvals](/products/custody/governance/intents/manage-intents-and-approvals#submit-a-system-signed-intent-with-the-api)
- [Policies](/products/custody/governance/policies#user-signed-and-system-signed-policies)
- [Policy reference](/products/custody/governance/policies/reference#intent-origin-values)
- [Authenticate API requests](/products/custody/identity-and-access/authentication/authenticate-api-requests#system-signed-intent-request-structure)