tests fixes and some product advisories tunes ups

This commit is contained in:
master
2026-01-30 07:57:43 +02:00
parent 644887997c
commit 55744f6a39
345 changed files with 26290 additions and 2267 deletions

View File

@@ -739,54 +739,213 @@ sequenceDiagram
- Health endpoints: `/health/liveness`, `/health/readiness`, `/status`; verification probe `/api/attestations/verify` once demo bundle is available (see runbook).
- Alert hints: signing latency > 1s p99, verification failure spikes, tlog submission lag >10s, key rotation age over policy threshold, backlog above configured threshold.
---
## 17) Rekor Entry Events
> Sprint: SPRINT_20260112_007_ATTESTOR_rekor_entry_events
Attestor emits deterministic events when DSSE bundles are logged to Rekor and inclusion proofs become available. These events drive policy reanalysis.
### Event Types
| Event Type | Constant | Description |
|------------|----------|-------------|
| `rekor.entry.logged` | `RekorEventTypes.EntryLogged` | Bundle successfully logged with inclusion proof |
| `rekor.entry.queued` | `RekorEventTypes.EntryQueued` | Bundle queued for logging (async mode) |
| `rekor.entry.inclusion_verified` | `RekorEventTypes.InclusionVerified` | Inclusion proof independently verified |
| `rekor.entry.failed` | `RekorEventTypes.EntryFailed` | Logging or verification failed |
### RekorEntryEvent Schema
```jsonc
{
"eventId": "rekor-evt-sha256:...",
"eventType": "rekor.entry.logged",
"tenant": "default",
"bundleDigest": "sha256:abc123...",
"artifactDigest": "sha256:def456...",
"predicateType": "StellaOps.ScanResults@1",
"rekorEntry": {
"uuid": "24296fb24b8ad77a...",
"logIndex": 123456789,
"logUrl": "https://rekor.sigstore.dev",
"integratedTime": "2026-01-15T10:30:02Z"
},
"reanalysisHints": {
"cveIds": ["CVE-2026-1234"],
"productKeys": ["pkg:npm/lodash@4.17.21"],
"mayAffectDecision": true,
"reanalysisScope": "immediate"
},
"occurredAtUtc": "2026-01-15T10:30:05Z"
}
```
### Offline Mode Behavior
When operating in offline/air-gapped mode:
1. Events are not emitted when Rekor is unreachable
2. Bundles are queued locally for later submission
3. Verification uses bundled checkpoints
---
## 17) Rekor Entry Events
> Sprint: SPRINT_20260112_007_ATTESTOR_rekor_entry_events
Attestor emits deterministic events when DSSE bundles are logged to Rekor and inclusion proofs become available. These events drive policy reanalysis.
### Event Types
| Event Type | Constant | Description |
|------------|----------|-------------|
| `rekor.entry.logged` | `RekorEventTypes.EntryLogged` | Bundle successfully logged with inclusion proof |
| `rekor.entry.queued` | `RekorEventTypes.EntryQueued` | Bundle queued for logging (async mode) |
| `rekor.entry.inclusion_verified` | `RekorEventTypes.InclusionVerified` | Inclusion proof independently verified |
| `rekor.entry.failed` | `RekorEventTypes.EntryFailed` | Logging or verification failed |
### RekorEntryEvent Schema
```jsonc
{
"eventId": "rekor-evt-sha256:...",
"eventType": "rekor.entry.logged",
"tenant": "default",
"bundleDigest": "sha256:abc123...",
"artifactDigest": "sha256:def456...",
"predicateType": "StellaOps.ScanResults@1",
"rekorEntry": {
"uuid": "24296fb24b8ad77a...",
"logIndex": 123456789,
"logUrl": "https://rekor.sigstore.dev",
"integratedTime": "2026-01-15T10:30:02Z"
},
"reanalysisHints": {
"cveIds": ["CVE-2026-1234"],
"productKeys": ["pkg:npm/lodash@4.17.21"],
"mayAffectDecision": true,
"reanalysisScope": "immediate"
},
"occurredAtUtc": "2026-01-15T10:30:05Z"
}
```
### Offline Mode Behavior
When operating in offline/air-gapped mode:
1. Events are not emitted when Rekor is unreachable
2. Bundles are queued locally for later submission
3. Verification uses bundled checkpoints
4. Events are generated when connectivity is restored
---
## 18) Identity Watchlist & Monitoring
> Sprint: SPRINT_0129_001_ATTESTOR_identity_watchlist_alerting
The Attestor provides proactive monitoring for signing identities appearing in transparency logs. Organizations can define watchlists to receive alerts when specific identities sign artifacts.
### Purpose
- **Credential compromise detection**: Alert when your signing identity appears unexpectedly
- **Third-party monitoring**: Watch for specific vendors or dependencies signing artifacts
- **Compliance auditing**: Track all signing activity for specific issuers
### Watchlist Entry Model
```jsonc
{
"id": "uuid",
"tenantId": "tenant-123",
"scope": "tenant", // tenant | global | system
"displayName": "GitHub Actions Signer",
"description": "Watch for GitHub Actions OIDC tokens",
// Identity fields (at least one required)
"issuer": "https://token.actions.githubusercontent.com",
"subjectAlternativeName": "repo:org/repo:*", // glob pattern
"keyId": null,
"matchMode": "glob", // exact | prefix | glob | regex
// Alert configuration
"severity": "warning", // info | warning | critical
"enabled": true,
"channelOverrides": ["slack-security"],
"suppressDuplicatesMinutes": 60,
"tags": ["github", "ci-cd"],
"createdAt": "2026-01-29T10:00:00Z",
"createdBy": "admin@example.com"
}
```
### Matching Modes
| Mode | Behavior | Example Pattern | Matches |
|------|----------|-----------------|---------|
| `exact` | Case-insensitive equality | `alice@example.com` | `Alice@example.com` |
| `prefix` | Starts-with match | `https://accounts.google.com/` | Any Google OIDC issuer |
| `glob` | Glob pattern (`*`, `?`) | `*@example.com` | `alice@example.com`, `bob@example.com` |
| `regex` | Full regex (with timeout) | `repo:org/(frontend\|backend):.*` | `repo:org/frontend:ref:main` |
### Scope Hierarchy
| Scope | Visibility | Who Can Create |
|-------|------------|----------------|
| `tenant` | Owning tenant only | Tenant admins |
| `global` | All tenants | Platform admins |
| `system` | All tenants (read-only) | System bootstrap |
### Event Flow
```
New AttestorEntry persisted
→ SignerIdentityDescriptor extracted
→ IIdentityMatcher.MatchAsync()
→ For each match:
→ Check dedup window (default 60 min)
→ Emit attestor.identity.matched event
→ Route via Notifier rules → Slack/Email/Webhook
```
### Event Schema (IdentityAlertEvent)
```jsonc
{
"eventId": "uuid",
"eventKind": "attestor.identity.matched",
"tenantId": "tenant-123",
"watchlistEntryId": "uuid",
"watchlistEntryName": "GitHub Actions Signer",
"matchedIdentity": {
"issuer": "https://token.actions.githubusercontent.com",
"subjectAlternativeName": "repo:org/repo:ref:refs/heads/main",
"keyId": null
},
"rekorEntry": {
"uuid": "24296fb24b8ad77a...",
"logIndex": 123456789,
"artifactSha256": "sha256:abc123...",
"integratedTimeUtc": "2026-01-29T10:30:00Z"
},
"severity": "warning",
"occurredAtUtc": "2026-01-29T10:30:05Z",
"suppressedCount": 0
}
```
### API Endpoints
| Method | Path | Description |
|--------|------|-------------|
| `POST` | `/api/v1/watchlist` | Create watchlist entry |
| `GET` | `/api/v1/watchlist` | List entries (tenant + optional global) |
| `GET` | `/api/v1/watchlist/{id}` | Get single entry |
| `PUT` | `/api/v1/watchlist/{id}` | Update entry |
| `DELETE` | `/api/v1/watchlist/{id}` | Delete entry |
| `POST` | `/api/v1/watchlist/{id}/test` | Test pattern against sample identity |
| `GET` | `/api/v1/watchlist/alerts` | List recent alerts (paginated) |
### CLI Commands
```bash
# Add a watchlist entry
stella watchlist add --issuer "https://token.actions.githubusercontent.com" \
--san "repo:org/*" --match-mode glob --severity warning
# List entries
stella watchlist list --include-global
# Test a pattern
stella watchlist test <id> --issuer "https://..." --san "repo:org/repo:ref:main"
# View recent alerts
stella watchlist alerts --since 24h --severity warning
```
### Metrics
| Metric | Description |
|--------|-------------|
| `attestor.watchlist.entries_scanned_total` | Entries processed by monitor |
| `attestor.watchlist.matches_total{severity}` | Pattern matches by severity |
| `attestor.watchlist.alerts_emitted_total` | Alerts sent to notification system |
| `attestor.watchlist.alerts_suppressed_total` | Alerts deduplicated |
| `attestor.watchlist.scan_latency_seconds` | Per-entry scan duration |
### Configuration
```yaml
attestor:
watchlist:
enabled: true
monitorMode: "changefeed" # changefeed | polling
pollingIntervalSeconds: 5 # only for polling mode
maxEventsPerSecond: 100 # rate limit
defaultDedupWindowMinutes: 60
regexTimeoutMs: 100 # safety limit
maxWatchlistEntriesPerTenant: 1000
```
### Offline Mode
In air-gapped environments:
- Polling mode used instead of Postgres NOTIFY
- Alerts queued locally if notification channels unavailable
- Alerts delivered when connectivity restored

View File

@@ -0,0 +1,237 @@
# Identity Watchlist User Guide
This guide covers how to use the identity watchlist feature in Stella Ops to monitor signing activity in transparency logs.
## Overview
The identity watchlist enables proactive alerting when specific signing identities appear in Rekor transparency log entries. Use cases include:
- **Threat Detection**: Monitor for known malicious or compromised signing identities
- **Compliance Monitoring**: Track when specific OIDC issuers sign artifacts
- **Operational Awareness**: Get notified when CI/CD workflows from specific repositories sign releases
- **Key Tracking**: Monitor usage of specific signing keys across your organization
## Core Concepts
### Watchlist Entries
A watchlist entry defines an identity pattern to monitor and alert configuration:
| Field | Description | Required |
|-------|-------------|----------|
| `displayName` | Human-readable label | Yes |
| `description` | Why this identity is watched | No |
| `issuer` | OIDC issuer URL pattern | At least one |
| `subjectAlternativeName` | Certificate SAN pattern | of these |
| `keyId` | Key identifier for keyful signing | three |
| `matchMode` | Pattern matching mode | No (default: `exact`) |
| `severity` | Alert severity level | No (default: `warning`) |
| `enabled` | Whether entry is active | No (default: `true`) |
| `scope` | Visibility scope | No (default: `tenant`) |
### Match Modes
| Mode | Description | Example Pattern | Matches |
|------|-------------|-----------------|---------|
| `exact` | Case-insensitive equality | `https://accounts.google.com` | Only that exact URL |
| `prefix` | Starts with pattern | `https://token.actions.` | Any GitHub Actions issuer |
| `glob` | Wildcard matching | `*@example.com` | Any email at example.com |
| `regex` | Full regex (advanced) | `user\d+@.*` | user123@domain.com |
> **Note**: Regex mode has a 100ms timeout and pattern validation. Use sparingly for performance-critical environments.
### Severity Levels
| Level | Use Case | Notification Priority |
|-------|----------|----------------------|
| `info` | Informational tracking | Low |
| `warning` | Unexpected but not critical (default) | Medium |
| `critical` | Immediate attention required | High |
### Scope Levels
| Scope | Description | Who Can Create |
|-------|-------------|----------------|
| `tenant` | Visible only to owning tenant | Any user with `watchlist:write` |
| `global` | Shared across all tenants | Administrators only |
| `system` | System-managed entries | System only |
## CLI Usage
### Adding a Watchlist Entry
Monitor a specific OIDC issuer:
```bash
stella watchlist add \
--issuer "https://token.actions.githubusercontent.com" \
--name "GitHub Actions" \
--severity warning \
--description "Track all GitHub Actions signatures"
```
Monitor email patterns with glob matching:
```bash
stella watchlist add \
--san "*@malicious-domain.com" \
--match-mode glob \
--severity critical \
--name "Malicious Domain"
```
### Listing Entries
List all entries including global ones:
```bash
stella watchlist list --include-global
```
Output as JSON for scripting:
```bash
stella watchlist list --format json
```
### Testing Patterns
Test if an identity would trigger an alert:
```bash
stella watchlist test <entry-id> \
--issuer "https://token.actions.githubusercontent.com" \
--san "repo:org/repo:ref:refs/heads/main"
```
### Managing Entries
Update an entry:
```bash
stella watchlist update <entry-id> --enabled false
stella watchlist update <entry-id> --severity critical
```
Delete an entry:
```bash
stella watchlist remove <entry-id>
stella watchlist remove <entry-id> --force # Skip confirmation
```
### Viewing Alerts
List recent alerts:
```bash
stella watchlist alerts --since 24h
stella watchlist alerts --severity critical --limit 50
```
## API Usage
### Create Entry
```http
POST /api/v1/watchlist
Content-Type: application/json
{
"displayName": "GitHub Actions Monitor",
"issuer": "https://token.actions.githubusercontent.com",
"matchMode": "prefix",
"severity": "warning",
"description": "Monitor all GitHub Actions signatures",
"enabled": true,
"suppressDuplicatesMinutes": 60
}
```
### List Entries
```http
GET /api/v1/watchlist?includeGlobal=true
```
### Test Pattern
```http
POST /api/v1/watchlist/{id}/test
Content-Type: application/json
{
"issuer": "https://token.actions.githubusercontent.com",
"subjectAlternativeName": "repo:org/repo:ref:refs/heads/main"
}
```
## Alert Deduplication
To prevent alert storms, the watchlist system deduplicates alerts based on:
1. **Watchlist Entry ID** - Which entry triggered the alert
2. **Identity Hash** - SHA-256 of the matched identity fields
Configure the deduplication window per entry with `suppressDuplicatesMinutes` (default: 60 minutes).
When an alert is suppressed, subsequent alerts will include a `suppressedCount` indicating how many similar alerts were skipped.
## Best Practices
### Pattern Design
1. **Start specific, broaden as needed**: Begin with exact matches before using wildcards
2. **Test before deploying**: Use the test endpoint to validate patterns
3. **Document why**: Always include a description explaining the monitoring purpose
4. **Use appropriate match modes**:
- `exact` for known bad actors
- `prefix` for issuer families (e.g., all Google issuers)
- `glob` for email/SAN patterns
- `regex` only when simpler modes can't express the pattern
### Performance Considerations
- Limit regex patterns to < 256 characters
- Avoid catastrophic backtracking patterns (e.g., `(a+)+`)
- Monitor the `attestor.watchlist.scan_latency_seconds` metric
- Keep watchlist size reasonable (< 1000 entries per tenant)
### Alert Management
1. **Set appropriate severity**: Reserve `critical` for genuine emergencies
2. **Configure dedup windows**: Use shorter windows (5-15 min) for critical entries
3. **Review suppressed counts**: High counts may indicate a pattern is too broad
4. **Route appropriately**: Use channel overrides for sensitive entries
## Monitoring & Metrics
The following OpenTelemetry metrics are exposed:
| Metric | Description |
|--------|-------------|
| `attestor.watchlist.entries_scanned_total` | Total Rekor entries processed |
| `attestor.watchlist.matches_total{severity}` | Pattern matches by severity |
| `attestor.watchlist.alerts_emitted_total` | Alerts sent to notification system |
| `attestor.watchlist.alerts_suppressed_total` | Alerts suppressed by deduplication |
| `attestor.watchlist.scan_latency_seconds` | Per-entry scan duration |
## Troubleshooting
### Entry Not Matching Expected Identity
1. Verify the match mode is appropriate for your pattern
2. Use the test endpoint with verbose output
3. Check if the entry is enabled
4. Verify case sensitivity (all modes are case-insensitive)
### Too Many Alerts
1. Increase `suppressDuplicatesMinutes`
2. Narrow the pattern (more specific issuer, SAN prefix)
3. Consider if the pattern is too broad
### Missing Alerts
1. Verify the entry is enabled
2. Check if alerts are being suppressed (view suppressed count)
3. Verify notification routing is configured
4. Check service logs for matching errors
## Related Documentation
- [Attestor Architecture](../architecture.md)
- [Notification Templates](../../notify/templates.md)
- [Watchlist Monitoring Runbook](../../operations/watchlist-monitoring-runbook.md)