Docs/Authority/Sidecar/Policy Signing

Enterprise Hardening: Ed25519 Policy Signing

In a standard local development deployment, the Predicate sidecar loads plain YAML or JSON policy files without verifying signatures. While this provides a zero-friction developer experience, it presents a risk in shared or production environments: if an attacker gains host access, they could modify the local policy file to bypass restrictions (e.g., modifying a rule to effect: ALLOW).

To neutralize local file tampering, Enterprise deployments should enforce cryptographic policy signing.


The Signature Architecture

┌─────────────────────────────────────────────────────────────────────────────┐
│                           CONTROL PLANE                                     │
│  ┌─────────────────┐    ┌──────────────────┐    ┌────────────────────────┐  │
│  │ Policy Editor   │───>│ Ed25519 Signing  │───>│ Signed Policy Payload  │  │
│  │ (Admin UI/API)  │    │ (Private Key)    │    │ { policy, signature }  │  │
│  └─────────────────┘    └──────────────────┘    └────────────────────────┘  │
└─────────────────────────────────────────────────────────────────────────────┘
                                    │
                                    ▼
┌─────────────────────────────────────────────────────────────────────────────┐
│                           LOCAL HOST / AGENT                                │
│  ┌────────────────────────┐    ┌──────────────────┐    ┌─────────────────┐  │
│  │ Signed Policy File     │───>│ Ed25519 Verify   │───>│ Policy Engine   │  │
│  │ policy.signed.json     │    │ (Public Key)     │    │ (Rules Active)  │  │
│  └────────────────────────┘    └──────────────────┘    └─────────────────┘  │
│                                        │                                    │
│                                        ▼                                    │
│                              ┌──────────────────┐                           │
│                              │ Invalid/Missing? │                           │
│                              │ REFUSE TO START  │                           │
│                              └──────────────────┘                           │
└─────────────────────────────────────────────────────────────────────────────┘

Signed Policy File Format

A signed policy file wraps the raw policy rules with cryptographic metadata.

JSON format (policy.signed.json):

{
  "policy": {
    "rules": [
      {
        "name": "allow-workspace-read",
        "effect": "allow",
        "principals": ["agent:*"],
        "actions": ["fs.read"],
        "resources": ["/home/*/workspace/**"]
      }
    ]
  },
  "signature": "base64-encoded-ed25519-signature",
  "signed_at": "2024-01-15T10:30:00Z",
  "signed_by": "control-plane-v1"
}

YAML format (policy.signed.yaml):

policy:
  rules:
    - name: allow-workspace-read
      effect: allow
      principals:
        - "agent:*"
      actions:
        - fs.read
      resources:
        - "/home/*/workspace/**"

signature: "base64-encoded-ed25519-signature"
signed_at: "2024-01-15T10:30:00Z"
signed_by: "control-plane-v1"

Configuring the Production Sidecar

To enforce signature verification on your production agents, boot the Predicate sidecar with the signature enforcement flags:

predicate-authorityd \
  --require-signed-policy \
  --policy-signing-key <hex-public-key-from-control-plane> \
  --policy-file policy.signed.json \
  run
FlagEnvironment VariableDescription
--require-signed-policyPREDICATE_REQUIRE_SIGNED_POLICYReject unsigned policies
--policy-signing-keyPREDICATE_POLICY_SIGNING_KEYEd25519 public key (hex)

When signature verification is enabled:


Control Plane API Integration

If you are building custom CI/CD deployment pipelines, you can interact directly with the Control Plane signing endpoints to automate policy distribution:

Sign a Policy

# Submit a raw JSON policy to receive the signed policy structure
curl -X POST https://api.predicatesystems.ai/v1/policies/sign \
  -H "Authorization: Bearer $PREDICATE_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "rules": [
      {
        "name": "production-policy",
        "effect": "allow",
        "principals": ["agent:prod-*"],
        "actions": ["fs.read", "http.fetch"],
        "resources": ["/app/**", "https://api.example.com/*"]
      }
    ]
  }'

Response:

{
  "policy": { "rules": [...] },
  "signature": "a1b2c3d4e5f6...",
  "signed_at": "2024-01-15T10:30:00Z",
  "signed_by": "control-plane-v1"
}

Retrieve the Public Key

# Get the hex-encoded public key required for sidecar startup configuration
curl https://api.predicatesystems.ai/v1/signing/public-key \
  -H "Authorization: Bearer $PREDICATE_API_KEY"

Response:

{
  "public_key": "a1b2c3d4e5f6789012345678901234567890123456789012345678901234567890",
  "algorithm": "ed25519",
  "key_id": "cp-signing-key-v1"
}

CI/CD Integration Example

Here's an example GitHub Actions workflow that fetches a signed policy from the Control Plane and deploys it:

name: Deploy Signed Policy

on:
  push:
    paths:
      - 'policies/**'

jobs:
  deploy:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4

      - name: Sign policy via Control Plane
        run: |
          curl -X POST https://api.predicatesystems.ai/v1/policies/sign \
            -H "Authorization: Bearer ${{ secrets.PREDICATE_API_KEY }}" \
            -H "Content-Type: application/json" \
            -d @policies/production.json \
            -o policies/production.signed.json

      - name: Get signing public key
        run: |
          PUBLIC_KEY=$(curl -s https://api.predicatesystems.ai/v1/signing/public-key \
            -H "Authorization: Bearer ${{ secrets.PREDICATE_API_KEY }}" \
            | jq -r '.public_key')
          echo "POLICY_SIGNING_KEY=$PUBLIC_KEY" >> $GITHUB_ENV

      - name: Deploy to production
        run: |
          # Deploy signed policy and public key to your infrastructure
          scp policies/production.signed.json prod-server:/etc/predicate/policy.json
          ssh prod-server "systemctl restart predicate-authorityd"

Security Considerations