Enforce signed backup evidence before migrations

This commit is contained in:
2026-08-03 02:01:13 +02:00
parent 2c515f73c2
commit cbbe08d912
16 changed files with 2157 additions and 52 deletions
+255
View File
@@ -0,0 +1,255 @@
{
"$schema": "https://json-schema.org/draft/2020-12/schema",
"$id": "https://govoplan.add-ideas.de/schemas/backup-evidence-v1.json",
"title": "GovOPlaN coordinated backup and restore evidence",
"type": "object",
"additionalProperties": false,
"required": [
"schema_version",
"evidence_id",
"installation_id",
"deployment_subject",
"release",
"recovery_point",
"components",
"restore_drill",
"issued_at",
"expires_at",
"revoked",
"signatures"
],
"properties": {
"schema_version": { "const": "1" },
"evidence_id": { "$ref": "#/$defs/token" },
"installation_id": { "$ref": "#/$defs/token" },
"deployment_subject": {
"type": "object",
"additionalProperties": false,
"required": ["profile", "topology", "subject_ref"],
"properties": {
"profile": { "enum": ["evaluation", "self-hosted"] },
"topology": { "$ref": "#/$defs/token" },
"subject_ref": { "$ref": "#/$defs/reference" }
}
},
"release": {
"type": "object",
"additionalProperties": false,
"required": [
"channel",
"version",
"manifest_sha256",
"composition_sha256",
"api_image",
"web_image"
],
"properties": {
"channel": { "$ref": "#/$defs/token" },
"version": { "$ref": "#/$defs/token" },
"manifest_sha256": { "$ref": "#/$defs/sha256" },
"composition_sha256": { "$ref": "#/$defs/sha256" },
"api_image": { "$ref": "#/$defs/digest_image" },
"web_image": { "$ref": "#/$defs/digest_image" }
}
},
"recovery_point": {
"type": "object",
"additionalProperties": false,
"required": ["id", "captured_at", "consistency", "rpo_seconds", "write_fence"],
"properties": {
"id": { "$ref": "#/$defs/token" },
"captured_at": { "type": "string", "format": "date-time" },
"consistency": {
"enum": ["provider-atomic", "application-quiesced", "transaction-consistent"]
},
"rpo_seconds": { "$ref": "#/$defs/duration" },
"write_fence": {
"type": "object",
"additionalProperties": false,
"required": ["mode", "token_sha256", "established_at"],
"properties": {
"mode": {
"enum": ["provider-snapshot", "application-quiesce", "transaction-boundary"]
},
"token_sha256": { "$ref": "#/$defs/sha256" },
"established_at": { "type": "string", "format": "date-time" }
}
}
}
},
"components": {
"type": "object",
"additionalProperties": false,
"required": ["database", "objects", "configuration", "key_custody"],
"properties": {
"database": { "$ref": "#/$defs/database" },
"objects": { "$ref": "#/$defs/objects" },
"configuration": { "$ref": "#/$defs/configuration" },
"key_custody": { "$ref": "#/$defs/key_custody" }
}
},
"restore_drill": {
"type": "object",
"additionalProperties": false,
"required": [
"drill_id",
"recovery_point_id",
"started_at",
"completed_at",
"isolated_target_ref",
"release_manifest_sha256",
"migration_heads_sha256",
"representative_object_manifest_sha256",
"database_verified",
"objects_verified",
"configuration_verified",
"key_custody_verified",
"semantic_checks",
"measured_rpo_seconds",
"measured_rto_seconds",
"evidence_ref"
],
"properties": {
"drill_id": { "$ref": "#/$defs/token" },
"recovery_point_id": { "$ref": "#/$defs/token" },
"started_at": { "type": "string", "format": "date-time" },
"completed_at": { "type": "string", "format": "date-time" },
"isolated_target_ref": { "$ref": "#/$defs/reference" },
"release_manifest_sha256": { "$ref": "#/$defs/sha256" },
"migration_heads_sha256": { "$ref": "#/$defs/sha256" },
"representative_object_manifest_sha256": { "$ref": "#/$defs/sha256" },
"database_verified": { "const": true },
"objects_verified": { "const": true },
"configuration_verified": { "const": true },
"key_custody_verified": { "const": true },
"semantic_checks": {
"type": "array",
"minItems": 1,
"maxItems": 128,
"items": {
"type": "object",
"additionalProperties": false,
"required": ["id", "status", "evidence_ref"],
"properties": {
"id": { "$ref": "#/$defs/token" },
"status": { "const": "passed" },
"evidence_ref": { "$ref": "#/$defs/reference" }
}
}
},
"measured_rpo_seconds": { "$ref": "#/$defs/duration" },
"measured_rto_seconds": { "$ref": "#/$defs/duration" },
"evidence_ref": { "$ref": "#/$defs/reference" }
}
},
"issued_at": { "type": "string", "format": "date-time" },
"expires_at": { "type": "string", "format": "date-time" },
"revoked": { "const": false },
"signatures": {
"type": "array",
"minItems": 1,
"maxItems": 16,
"items": { "$ref": "#/$defs/signature" }
}
},
"$defs": {
"token": {
"type": "string",
"minLength": 1,
"maxLength": 128,
"pattern": "^[A-Za-z0-9][A-Za-z0-9._:-]{0,127}$"
},
"sha256": { "type": "string", "pattern": "^[0-9a-f]{64}$" },
"digest_image": {
"type": "string",
"maxLength": 300,
"pattern": "^[^@\\s]+@sha256:[0-9a-f]{64}$"
},
"reference": {
"type": "string",
"minLength": 3,
"maxLength": 2048,
"pattern": "^[A-Za-z][A-Za-z0-9+.-]*:[^\\s]+$"
},
"duration": { "type": "integer", "minimum": 0, "maximum": 2592000 },
"protected_key": {
"type": "object",
"properties": {
"protected": { "const": true },
"encryption_key_ref": { "$ref": "#/$defs/reference" },
"captured_at": { "type": "string", "format": "date-time" }
}
},
"database": {
"type": "object",
"additionalProperties": false,
"required": [
"provider", "artifact_ref", "artifact_sha256", "snapshot_id", "lsn",
"protected", "encryption_key_ref", "captured_at"
],
"properties": {
"provider": { "$ref": "#/$defs/token" },
"artifact_ref": { "$ref": "#/$defs/reference" },
"artifact_sha256": { "$ref": "#/$defs/sha256" },
"snapshot_id": { "$ref": "#/$defs/token" },
"lsn": { "type": "string", "minLength": 1, "maxLength": 256 },
"protected": { "const": true },
"encryption_key_ref": { "$ref": "#/$defs/reference" },
"captured_at": { "type": "string", "format": "date-time" }
}
},
"objects": {
"type": "object",
"additionalProperties": false,
"required": [
"provider", "artifact_ref", "manifest_sha256", "version_id",
"object_count", "total_bytes", "protected", "encryption_key_ref", "captured_at"
],
"properties": {
"provider": { "$ref": "#/$defs/token" },
"artifact_ref": { "$ref": "#/$defs/reference" },
"manifest_sha256": { "$ref": "#/$defs/sha256" },
"version_id": { "$ref": "#/$defs/token" },
"object_count": { "type": "integer", "minimum": 0 },
"total_bytes": { "type": "integer", "minimum": 0 },
"protected": { "const": true },
"encryption_key_ref": { "$ref": "#/$defs/reference" },
"captured_at": { "type": "string", "format": "date-time" }
}
},
"configuration": {
"type": "object",
"additionalProperties": false,
"required": ["artifact_ref", "sha256", "protected", "encryption_key_ref", "captured_at"],
"properties": {
"artifact_ref": { "$ref": "#/$defs/reference" },
"sha256": { "$ref": "#/$defs/sha256" },
"protected": { "const": true },
"encryption_key_ref": { "$ref": "#/$defs/reference" },
"captured_at": { "type": "string", "format": "date-time" }
}
},
"key_custody": {
"type": "object",
"additionalProperties": false,
"required": ["provider", "keyset_ref", "keyset_version", "recoverable", "captured_at"],
"properties": {
"provider": { "$ref": "#/$defs/token" },
"keyset_ref": { "$ref": "#/$defs/reference" },
"keyset_version": { "$ref": "#/$defs/token" },
"recoverable": { "const": true },
"captured_at": { "type": "string", "format": "date-time" }
}
},
"signature": {
"type": "object",
"additionalProperties": false,
"required": ["key_id", "algorithm", "value"],
"properties": {
"key_id": { "$ref": "#/$defs/token" },
"algorithm": { "const": "ed25519" },
"value": { "type": "string", "minLength": 1, "maxLength": 256 }
}
}
}
}