Skip to content

Latest commit

 

History

History
507 lines (411 loc) · 14.8 KB

POLICY.md

File metadata and controls

507 lines (411 loc) · 14.8 KB

TAS Policy Management Guide

This guide explains how to create, sign, and register security policies in the TEE Attestation Service (TAS).

Table of Contents

Overview

TAS policies define the security requirements that TEE attestation evidence must meet. Policies consist of:

  • Metadata: Descriptive information about the policy
  • Validation Rules: Specific attestation requirements (measurements, versions, etc.)
  • Digital Signature: Optional but recommended for integrity verification

Policies are stored in Redis and referenced during attestation validation to determine if TEE evidence meets the required security standards.

Policy Structure

Example Policy Format

{
  "metadata": {
    "name": "SEV Example Policy",
    "version": "1.0",
    "description": "Policy description",
    "policy_type": "SEV",
    "policy_id": "my-sev-policy-001",
    "key_id": "my-secret-id",
    "created_date": "2024-09-09",
    "last_updated": "2024-09-09"
  },
  "validation_rules": {
    "measurement": {
      "exact_match": "a1b2c3d4e5f6789..."
    },
    "vmpl": {
      "exact_match": 0
    },
    "policy": {
      "migrate_ma_allowed": false,
      "debug_allowed": false,
      "smt_allowed": true
    },
    "platform_info": {
      "ecc_enabled": {
        "boolean": true
      },
      "tsme_enabled": {
        "boolean": true
      },
      "alias_check_complete": {
        "boolean": true
      },
      "smt_enabled": {
        "boolean": true
      }
    },
  },
  "signature": {
    "algorithm": "SHA384",
    "padding": "PSS",
    "value": "base64-encoded-signature"
  }
}

Required Fields

Field Type Required Description
metadata object Yes Policy metadata (must include policy_type, policy_id, and key_id)
validation_rules object Yes Attestation validation criteria
components object No Additional attestable component policies (e.g. GPUs). See Component Policies (GPU Attestation)
signature object No Digital signature for integrity

Metadata Fields

Field Type Required Description
name string Yes Human-readable policy name
policy_type string Yes TEE type (e.g. SEV, TDX)
policy_id string Yes Unique identifier for this policy (alphanumeric, hyphens, underscores, dots only)
key_id string Yes The secret ID this policy is used to release (must match the secret registered in KMS or HSM)
version string No Policy version
description string No Policy description
created_by string No Policy creator
created_date string No Creation date (ISO format)
last_updated string No Last update date (ISO format)

Signature Fields

Field Type Required Description
algorithm string Yes Algorithm used
padding string Yes Padding (either PSS or PKCS1v15)
value string Yes Base64 encoded signature

Deprecation Notice: The signed_data field previously allowed specifying which fields are covered by the signature. This field is no longer supported. The signature must always cover all top-level fields except signature. Policies using signed_data must be re-signed.

TDX Specific Fields

TCB

The tcb item within validation_rules is a special case for TDX policies. It is used to require specific TCB levels or better for various components, along with an update field to require a minimum TCB-R freshness. See the example policy tdx_example_policy.json or the excerpt below for an example.

...
  "validation_rules": {
    "tcb": {
      "update": "standard",
      "platform_tcb": "UpToDate",
      "tdx_module_tcb": "UpToDate",
      "qe_tcb": "UpToDate"
    },
...

Component Policies (GPU Attestation)

In addition to the CPU TEE rules in validation_rules, a policy may carry an optional top-level components section that defines requirements for other attestable devices alongside the CPU TEE. Today this is used for NVIDIA GPU attestation.

The components section is optional — existing SEV/TDX policies without it continue to work unchanged. When present, it is covered by the policy signature just like every other top-level field.

Structure

components is keyed by component type (gpu). Each component type is keyed by the device type reported by the agent. NVIDIA GPUs report gpu-nvidia:

{
  "components": {
    "gpu": {
      "gpu-nvidia": {
        "version": "4.0",
        "authorization-rules": { ... }
      }
    }
  }
}

The object under gpu-nvidia is an NVIDIA attestation policy consumed by nvidia_pytools. It validates the claims returned by the NVIDIA Remote Attestation Service (NRAS) and has two groups of rules:

  • overall-claims — checks applied to the overall NRAS result (e.g. the attestation succeeded overall).
  • detached-claims — per-GPU checks (measurement result, debug status, secure boot, driver/VBIOS RIM checks, certificate-chain status, etc.).

For each claim, the actual value reported by NRAS must match the value in the policy. Nested objects (such as certificate-chain status) are matched field by field.

Example

{
  "metadata": {
    "name": "AMD SEV-SNP + GPU Security Policy",
    "policy_type": "SEV",
    "policy_id": "sev-gpu-policy-001",
    "key_id": "test-key-gpu-1",
    "version": "1.0"
  },
  "validation_rules": {
    "vmpl": { "exact_match": 0 },
    "policy": { "debug_allowed": false, "smt_allowed": true }
  },
  "components": {
    "gpu": {
      "gpu-nvidia": {
        "version": "4.0",
        "authorization-rules": {
          "type": "JWT",
          "overall-claims": {
            "x-nvidia-overall-att-result": true,
            "x-nvidia-ver": "3.0"
          },
          "detached-claims": {
            "measres": "success",
            "dbgstat": "disabled",
            "secboot": true,
            "x-nvidia-gpu-arch-check": true,
            "x-nvidia-gpu-attestation-report-cert-chain": {
              "x-nvidia-cert-status": "valid",
              "x-nvidia-cert-ocsp-status": "good"
            }
          }
        }
      }
    }
  },
  "signature": { "...": "..." }
}

Signing Policies

Why Sign Policies?

Policy signing provides:

  • Integrity: Ensures policy hasn't been tampered with
  • Authentication: Verifies policy creator
  • Non-repudiation: Prevents denial of policy authorship

How Signatures Work

Before signing or verifying, TAS canonicalizes the policy JSON using RFC 8785 (JSON Canonicalization Scheme / JCS). This ensures that logically equivalent JSON objects produce identical byte representations regardless of key ordering or whitespace. The canonicalized bytes are then signed with RSA using SHA-384 and either PSS or PKCS1v15 padding.

The signature covers all top-level fields in the policy (metadata, validation_rules, etc.) except the signature field itself. This means any change to the policy will invalidate the signature.

Note: Policies must be signed using RFC 8785 canonicalization. Any custom signing tool must canonicalize the policy to be signed with JCS before signing.

Step 1: Use TAS Demo Signer

TAS includes a demo signing tool that can generate keys automatically and sign policies. You can use the provided demo_signer.py or generate your own keys.

Option A: Use Demo Signer with Auto-Generated Keys

# Navigate to the policy signing directory
cd certs/policy

# Sign your policy (this auto-generates keys if they don't exist)
python3 demo_signer.py /path/to/your-policy.json

# This creates:
# - policy_key.pem (private key with passphrase "passphrase")
# - policy_public_key.pem (public key for TAS configuration)
# - your-policy.json.sig (signature JSON to add to your policy)

Option B: Generate Your Own Keys

# Generate your own RSA key pair
openssl genrsa -out my-policy-key.pem 4096

# Generate public key
openssl rsa -in my-policy-key.pem -pubout -out my-policy-public.pem

# Secure the private key
chmod 600 my-policy-key.pem

Then modify demo_signer.py to use your custom keys, or create your own signing script based on the demo implementation.

Step 2: Add Signature to Policy

The demo signer creates a separate signature file. You need to manually add the signature to your policy:

# View the generated signature
cat your-policy.json.sig

# Example output:
# {
#   "signature": {
#     "algorithm": "SHA384",
#     "padding": "PSS", 
#     "value": "base64-encoded-signature..."
#   }
# }

# Add this signature object to your policy JSON file manually
# or use jq to merge them:
jq -s '.[0] * .[1]' your-policy.json your-policy.json.sig > your-policy-signed.json

Step 3: Configure TAS for Signature Verification

# Copy all your public keys and certs for policies to the default folder
cp public_key.pem /tas/certs/policy/

# Or alternatively configure TAS to trust your generated public key/cert
export TAS_POLICY_TRUST='/path/to/policy/public_key.pem'

Alternative: Certificate-based Signing

The demo signer can also generate certificates instead of just public keys:

# Generate certificate instead of public key
python3 demo_signer.py --cert your-policy.json

# This creates:
# - policy_key.pem (private key) 
# - policy_cert.pem (certificate for TAS configuration)
# - your-policy.json.sig (signature JSON)

# Then add the certificate to your configured policy trust directory

Registering Policies

To register a policy with TAS, POST the policy JSON directly to the store endpoint. The policy_id, policy_type, and key_id are read from the policy's metadata section.

Policy registration uses the management API, which requires the X-MANAGEMENT-API-KEY header (separate from the client X-API-KEY).

Registration Payload Format

The request body is the complete signed policy from Step 2 above:

{
  "metadata": {
    "name": "SEV Production Policy",
    "version": "1.0",
    "description": "Production policy for SEV attestation",
    "policy_type": "SEV",
    "policy_id": "my-sev-policy-001",
    "key_id": "my-secret-id",
    "created_date": "2024-09-09"
  },
  "validation_rules": {
    "measurement": {
      "exact_match": "a1b2c3d4e5f6789..."
    },
    "policy": {
      "debug_allowed": false,
      "migrate_ma_allowed": false
    }
  },
  "signature": {
    "algorithm": "SHA384",
    "padding": "PSS",
    "value": "base64-encoded-signature..."
  }
}

Required Metadata Fields for Registration

Field Type Required Description
metadata.policy_type string Yes TEE type: either "SEV" or "TDX"
metadata.policy_id string Yes Unique identifier for this policy (alphanumeric, hyphens, underscores, dots only)
metadata.key_id string Yes The secret ID that this policy will be used to release (must match the secret registered in KMS or HSM)

How it works: When a client requests a secret, TAS uses the policy_id to look up the policy and validates the attestation evidence. On success, the key_id from the policy metadata identifies which secret to release from the key manager. The key_id must exist in the key manager that TAS KBM is connected to.

Policy Storage Format: The policy will be stored in Redis using the key format: policy:{policy_id}

Example: policy:my-sev-policy-001

Using curl

# Set your management API key
export TAS_MANAGEMENT_API_KEY="your-management-api-key-here"

# Register the signed policy (management API)
curl -X POST http://localhost:5001/management/policy/v0/store \
  -H "Content-Type: application/json" \
  -H "X-MANAGEMENT-API-KEY: $TAS_MANAGEMENT_API_KEY" \
  -d  '{
    "metadata": {
      "name": "My Policy",
      "policy_type": "SEV",
      "policy_id": "my-sev-policy-001",
      "key_id": "my-secret-id"
    },
    "validation_rules": {...},
    "signature": {...}
  }'

# Expected response:
# {"message": "Policy 'policy:my-sev-policy-001' stored successfully"}

Validation Rule Types

exact_match

Requires exact value match:

{
  "measurement": {
    "exact_match": "a1b2c3d4e5f6789abcdef0123456789abcdef"
  }
}

min_value / max_value

Numeric range validation:

{
  "version": {
    "min_value": 3,
    "max_value": 10
  }
}

boolean

Boolean flag validation:

{
  "debug": false,
  "migrate_ma": false
}

allow_list

Check if value is in allowed list:

{
  "processor_family": {
    "allow_list": ["EPYC", "Xeon"]
  }
}

deny_list

Ensure value is not in banned list:

{
  "algorithms": {
    "deny_list": [4,5]
  }
}

Best Practices

Security Best Practices

  1. Always Sign Production Policies

    # Never deploy unsigned policies in production
    export TAS_ENFORCE_SIGNED_POLICIES=true
  2. Use Strong Key Management

    # Protect private keys
    chmod 600 policies/keys/*.key
    
    # Use hardware security modules (HSM) for critical keys
    # Store keys separately from policies
  3. Version Control Policies

    # Track policy changes
    git add policies/
    git commit -m "Add production SEV policy v1.0"
    git tag policy-v1.0

Troubleshooting

Common Issues

Policy Registration Fails

Error: Policy signature verification failed

Solutions:

  • Verify the signing key matches the trusted keys in TAS configuration
  • Check that the policy was signed correctly
  • Ensure TAS is configured with the correct public keys

Unsigned Policy Rejected

Error: Unsigned policies are not allowed by configuration

Solutions:

  • Sign the policy before registration
  • For development, disable enforcement: export TAS_ENFORCE_SIGNED_POLICIES=false

Invalid Policy Structure

Error: Policy must contain 'validation_rules' section

Solutions:

  • Verify all required fields are present
  • Check JSON syntax is valid
  • Ensure policy follows the correct structure

Debugging Commands

# Verify policy syntax
python3 -m json.tool my-policy.json

# List registered policies (management API)
curl -H "X-MANAGEMENT-API-KEY: $TAS_MANAGEMENT_API_KEY" http://localhost:5001/management/policy/v0/list

# Get specific policy (management API)
curl -H "X-MANAGEMENT-API-KEY: $TAS_MANAGEMENT_API_KEY" http://localhost:5001/management/policy/v0/get/policy:SNP:my-policy-id