# Rekor Transparency Log Budget Policy **Last Updated**: 2025-12-20 **Owner**: Attestor Team **Sprint**: SPRINT_3500_0003_0003 --- ## Overview This document defines the budget policy for Rekor transparency log submissions. The policy balances transparency requirements with rate limits and cost considerations. --- ## Submission Tiers ### Tier 1: Graph-Level Attestations (Default) **Scope**: One DSSE envelope per scan containing the call graph digest. **Frequency**: - Submitted automatically for every completed scan - Includes: `CallGraphSnapshot.GraphDigest`, scan metadata, scanner version **Payload Size**: ~2-5 KB per submission **Rate Budget**: - Default: 100 submissions/hour per tenant - Burst: 200 submissions/hour (10-minute window) **Configuration**: ```yaml attestor: rekor: enabled: true tier: graph-only budget: hourlyLimit: 100 burstLimit: 200 burstWindow: "00:10:00" ``` --- ### Tier 2: Edge Bundle Attestations (On Escalation) **Scope**: Detailed edge bundles submitted for escalated findings. **Triggers**: - CVE with CVSS >= 9.0 and reachable status - Security team escalation request - Policy engine gate failure with `require_proof: true` **Frequency**: - Only on explicit escalation - Subject to daily budget cap **Payload Size**: ~10-50 KB per bundle (varies with graph size) **Rate Budget**: - Default: 50 bundles/day per tenant - No burst allowance **Configuration**: ```yaml attestor: rekor: edgeBundles: enabled: true dailyLimit: 50 triggers: - cvssThreshold: 9.0 - policyGate: require_proof - manualEscalation: true ``` --- ## Budget Enforcement ### Rate Limiting The Attestor module enforces rate limits via the `RekorSubmissionQueue`: 1. **Admission**: Requests exceeding budget are queued with backpressure 2. **Retry**: Failed submissions retry with exponential backoff 3. **Overflow**: Excess requests are stored locally for later submission ### Quota Tracking Quotas are tracked per tenant in `attestor.rekor_quotas`: ```sql CREATE TABLE attestor.rekor_quotas ( tenant_id UUID PRIMARY KEY, hourly_count INT NOT NULL DEFAULT 0, daily_bundle_count INT NOT NULL DEFAULT 0, last_reset_hour TIMESTAMPTZ NOT NULL DEFAULT NOW(), last_reset_day DATE NOT NULL DEFAULT CURRENT_DATE ); ``` ### Alerts | Metric | Threshold | Action | |--------|-----------|--------| | `attestor_rekor_queue_depth` | > 1000 | Page on-call | | `attestor_rekor_submissions_rejected` | > 100/hour | Investigate quota abuse | | `attestor_rekor_budget_utilization` | > 80% | Notify tenant admin | --- ## Air-Gap Considerations In air-gapped deployments, Rekor submissions are: 1. **Queued Locally**: Stored in `attestor.rekor_offline_queue` 2. **Bundled on Export**: Included in offline kit as pending attestations 3. **Submitted on Connect**: When connectivity restored, queue drains ### Offline Queue Schema ```sql CREATE TABLE attestor.rekor_offline_queue ( id UUID PRIMARY KEY DEFAULT gen_random_uuid(), tenant_id UUID NOT NULL, tier TEXT NOT NULL CHECK (tier IN ('graph', 'edge')), payload BYTEA NOT NULL, created_at TIMESTAMPTZ NOT NULL DEFAULT NOW(), priority INT NOT NULL DEFAULT 0 ); ``` --- ## Monitoring ### Key Metrics | Metric | Description | Labels | |--------|-------------|--------| | `attestor_rekor_submissions_total` | Total Rekor submissions | tier, status | | `attestor_rekor_submission_latency_seconds` | Submission latency histogram | tier | | `attestor_rekor_queue_depth` | Current queue depth | tier | | `attestor_rekor_budget_remaining` | Remaining hourly budget | tenant | ### Grafana Dashboard Import dashboard ID: `stellaops-attestor-rekor` from the StellaOps dashboard gallery. --- ## Troubleshooting ### Common Issues **Q: Submissions are being rejected with 429** - Check `attestor_rekor_budget_remaining` metric - Review tenant's hourly submission rate - Consider increasing budget if legitimate spike **Q: Offline queue growing unbounded** - Verify network connectivity to Rekor - Check `attestor_rekor_submission_errors` for root cause - Consider manual drain if transient issue resolved **Q: Edge bundles not being submitted** - Verify escalation triggers are configured - Check policy engine gate configuration - Review `attestor_rekor_edge_bundle_triggers` logs --- ## Configuration Reference ### Full Configuration Schema ```yaml attestor: rekor: # Enable Rekor integration enabled: true # Rekor server URL (default: public Sigstore Rekor) serverUrl: "https://rekor.sigstore.dev" # Submission tier: graph-only | with-edges tier: graph-only # Budget configuration budget: # Hourly limit for graph attestations hourlyLimit: 100 # Burst allowance burstLimit: 200 burstWindow: "00:10:00" # Daily limit for edge bundles edgeBundleDailyLimit: 50 # Retry configuration retry: maxAttempts: 3 initialDelay: "00:00:05" maxDelay: "00:05:00" backoffMultiplier: 2.0 # Offline mode offline: queueEnabled: true maxQueueSize: 10000 drainOnConnect: true # Edge bundle triggers edgeBundles: enabled: true triggers: - cvssThreshold: 9.0 - policyGate: require_proof - manualEscalation: true ``` --- ## Related Documentation - [Attestor AGENTS.md](../../src/Attestor/StellaOps.Attestor/AGENTS.md) - [Scanner Score Proofs API](../api/scanner-score-proofs-api.md) - [Offline Kit Specification](../24_OFFLINE_KIT.md) - [Sigstore Rekor Documentation](https://docs.sigstore.dev/rekor/overview/)