Введение
CDO Office решает: операционных DQ-прогонов хватает (24 часовых GE-прогона × 8 контролей × 1.2M поездок в день), но реконструкция evidence за Q3 2024 показывает пробелы — 6 из 30 sampled прогонов не могут быть восстановлены (UPDATE Snowflake-таблицы перезаписали старые строки; никто не зафиксировал hash входа). Engineering Lead: «Нужно строить proper pipeline». CDO: «Что значит proper?». Lead: «End-to-end — от DQ engine до auditor view, с неизменяемым архивом посередине».
Этот урок — паттерн архитектуры. M7.1 описал, какие атрибуты должен иметь evidence; M7.2 — как evidence pipeline их физически собирает + хранит.
Пайплайн — 5 стадий
End-to-end:
- DQ engine — выполняет правила (GE / Soda / dbt / custom).
- Metadata emitter — нормализует результаты в структурированную схему; добавляет timestamp, подпись, control_id.
- Неизменяемое хранилище — WORM-персистентность с retention SOX-grade.
- Attestation system — review Business Owner + sign-off; exception management.
- Auditor view — read-only доступ для external + internal audit.
Переключи tooling stack (GE 1.17.1 / Soda 4.0 / Anomalo). Кликни stage → IPE attributes + required artefacts + anti-patterns + SwiftRide example. Storage и auditor stages tool-agnostic by design.
Стек выше — переключаемый: GE 1.17.1, Soda 4.0, Anomalo. Хранилище и стадия auditor — tool-agnostic по дизайну (separation of concerns — целостность evidence не зависит от выбора DQ-инструмента).
Стадия 1 — DQ engine
Согласно M5.5 — правила DQ реализуют контроль-активности. Взгляд M7 — engine выдаёт структурированный вывод, пригодный для эмиссии evidence.
Необходимый вывод per run:
run_id(UUID, сгенерированный engine)rule_idилиexpectation_name(стабильный, версионированный)dataset_identifier(FQN —snowflake.dl_marts.fct_driver_earnings)dataset_snapshot_pointer(timestamp снапшота Snowflake, S3 versionId, dbt manifest SHA)input_metrics(row count, hash sample)rule_logic_version(semantic version или git SHA файла expectations)thresholds(полный снапшот, а не просто указатель — пороги могут меняться между прогонами)observed_values(числитель, знаменатель, вычисленная метрика)result(pass / fail / exception + код причины)execution_metadata(compute resource, идентичность runner’а, runtime в секундах)
Нативный вывод GE 1.17.1:
GE Core 1.17.1 (5 May 2026, Python 3.10-3.13) — Checkpoint API возвращает CheckpointResult
объект с validation_results[] per expectation. Каждый entry содержит expectation_config
(kwargs сериализованы; сохраняет пороги), result (observed_value, element_count,
unexpected_count), success: bool. data_context.checkpoint_store архивирует на
filesystem / S3 (конфигурируемый backend). Data Docs HTML рендерится как вспомогательный
человеко-читаемый вид (не primary evidence). Миграция с legacy 0.x → GX Core 1.x:
доступен инструмент миграции expectation suite; коммерческий GX Cloud версионируется отдельно.
Нативный вывод Soda Core 4.0:
Soda Core 4.0 (2025) — contract-first модель. data_contract.yml определяет проверки через
SodaCL DSL. soda scan возвращает ScanResults JSON: per-check check_name,
metric (наблюдаемое значение), outcome (‘pass’/‘fail’/‘warn’), failed_rows_sample (выборка
нарушающих записей). Soda Cloud (SaaS) добавляет incident workflow; on-prem agent запускает сканы
внутри VPC и emit’ит результаты через webhook. Audit trail через Soda Cloud — retention контрактный;
SOX-grade требует отдельного слоя архива.
Стадия 2 — Metadata emitter
Вывод engine — внутренний для инструмента. Emitter нормализует к организационной evidence-схеме. Три обязанности.
1. Нормализация схемы. Стандартная схема evidence по всем engine; аудитор не должен парсить 3 разных формата. Evidence-схема SwiftRide v1:
{
"evidence_version": "1.0",
"evidence_id": "ev_2026091506000000_ctl-cde-swr-003-002",
"timestamp_utc": "2026-09-15T06:00:00Z",
"control_id": "CTL-CDE-SWR-003-002",
"cde_id": "CDE-SWR-003",
"engine": {
"tool": "great_expectations",
"version": "1.17.1",
"run_id": "ge-uuid-...",
"expectation_suite_version": "v3.2.0"
},
"input_state": {
"dataset_fqn": "snowflake.dl_marts.fct_driver_earnings",
"snapshot_at": "2026-09-15T05:59:00Z",
"input_hash": "sha256:..."
},
"rule": {
"rule_id": "expect_column_values_to_be_between",
"thresholds": {"min": 0, "max": null}
},
"result": "pass",
"observed_values": {...},
"exception": null,
"signature": {
"algorithm": "HMAC-SHA256",
"key_id": "alias/swr-evidence-signing-key",
"value": "hex..."
}
}
2. Подпись. HMAC-SHA256 через AWS KMS-ключ (alias swr-evidence-signing-key); доступ к ключу — IAM-роль, ассамируемая только emitter Lambda; ротация 90 дней; CloudTrail логирует всё использование ключа. Подпись покрывает все поля, кроме самой signature.
3. Emit к downstream sinks. Emitter emit’ит параллельно:
- Неизменяемое хранилище — S3 Object Lock первичная персистентность.
- OpenLineage event — RunEvent с DataQualityFacet в Kafka topic
openlineage.runs→ Marquez consumer + S3 archive consumer. - Operational signal — PagerDuty/Slack при fail (реагирование на инциденты — M7.4).
Архитектурный паттерн — emitter является единой точкой целостности. Если emitter скомпрометирован, цепочка evidence скомпрометирована. Защита:
- Emitter — отдельный AWS-аккаунт (
swr-evidence-prod); минимальный IAM-доступ. - Доступ к KMS-ключу логируется в CloudTrail; алерты на необычные паттерны доступа.
- Code review ужесточён (CODEOWNERS = audit + security + data platform leads).
- Emitter деплоится через GitOps; PR на любое изменение требует одобрения нескольких команд.
Стадия 3 — Неизменяемое хранилище
Выбор хранилища:
| Паттерн | Сильные стороны | Слабые стороны | Случай применения |
|---|---|---|---|
| S3 Object Lock — Compliance Mode | Root-аккаунт не может обойти; сильнейший WORM | Операционная жёсткость — даже легитимная очистка требует legal review | Дефолт для evidence material CDE; паттерн SwiftRide |
| S3 Object Lock — Governance Mode | Root-аккаунт может обойти через s3:BypassGovernanceRetention | Более слабая гарантия WORM | Приемлемо, если IAM жёстко ограничивает обход + алерты на использование; менее зрелые программы |
| Azure Blob — Immutable Storage Policy | Time-based или legal hold | Azure-native; реже встречается в стеке SwiftRide | Преимущественно Azure-организации |
| AWS QLDB | Криптографическая верификация + ledger semantics | Операционные накладные расходы; дорого | High-stakes records (сами attestations, не ежедневные DQ-прогоны) |
| WORM-бакет в отдельном AWS-аккаунте | Defence-in-depth; компрометация основного аккаунта не затрагивает evidence | Накладные расходы на cross-account billing/access | Material CDE + tier-1 финансовая значимость |
Паттерн SwiftRide:
AWS Account: swr-evidence-prod (отдельный от операционных аккаунтов)
Region: eu-west-1 (primary) + репликация в eu-central-1 (DR)
Bucket: swr-evidence-prod-cde-evidence
Configuration:
- Versioning: enabled
- Object Lock: enabled, default retention 7 лет mode COMPLIANCE
- Encryption: SSE-KMS, key alias/swr-evidence-encryption-key
- Lifecycle: transition в Glacier Deep Archive после 1 года; expiration нет (Compliance Mode препятствует)
- Replication: cross-region replication в eu-central-1
- Access logging: enabled, в отдельный logging-бакет
- Public access: blocked
- IAM: write-only Lambda-роль; read-only audit-роль; IAM-разрешение на bypass удалено
Структура ключа:
s3://swr-evidence-prod-cde-evidence/
cde-swr-003/
ctl-cde-swr-003-002/
year=2026/
month=09/
day=15/
ev_2026091506000000_ctl-cde-swr-003-002.json
Партиционирование позволяет эффективные запросы через Snowflake EXTERNAL TABLE / Athena. Аудит, выбирающий выборки per control × period — partition prune высокоэффективен.
Evidence index:
Snowflake-таблица audit.evidence_index — вторичный индекс, указывающий на S3-ключи. Изменяемый для обновлений индекса (например, при добавлении нового evidence), но первичный evidence — неизменяем. Аудитор использует индекс только для discovery; верификация идёт в S3.
CREATE TABLE audit.evidence_index (
evidence_id VARCHAR PRIMARY KEY,
control_id VARCHAR,
cde_id VARCHAR,
timestamp_utc TIMESTAMP_NTZ,
s3_key VARCHAR,
evidence_sha256 VARCHAR,
retention_expires DATE,
signed_by VARCHAR,
result VARCHAR
);
CREATE VIEW audit.evidence_index_audit_view AS
SELECT * FROM audit.evidence_index;
-- Granted SELECT only to AUDIT_AUDITOR_ROLE
Стадия 4 — Attestation system
GRC-платформа интегрирует evidence:
- Workiva — SOX-first; AI-assisted control testing; широко развёрнута в Fortune 500.
- AuditBoard — audit-first; mid-market к large enterprise; SOX + ESG.
- ServiceNow IRM — угол continuous control monitoring (CCM); хорошо интегрируется с существующим стеком ServiceNow ITSM.
- LogicGate Risk Cloud — современный no-code; более быстрый деплой (1-3 месяца).
- Archer (Cinven) — наследие tier-1 банков; глубокая конфигурируемость, долгий деплой.
SwiftRide T+9M — выбран Workiva (SOX-first дорожная карта; pre-IPO timing). Детали в M8.
Attestation system читает evidence index + указатели на S3 payload; Business Owner просматривает per-control квартальный пакет; e-подписывает заявление об эффективности. Вывод attestation — сам по себе evidence (запись sign-off), сохраняемый обратно в неизменяемое хранилище с retention параллельным первичному evidence.
Стадия 5 — Auditor view
Read-only роль провижится для внешнего аудитора (Big 4 senior associate + senior manager). Разрешения роли:
SELECTнаaudit.evidence_indexs3:GetObjectнаswr-evidence-prod-cde-evidence/*kms:Decryptдля KMS-ключа encryption evidencekms:Verify(public-key crypto verification) для KMS-ключа signing evidence
Никаких s3:PutObject, s3:DeleteObject, write в Snowflake. Аудит не может изменить evidence → независимость сохранена.
Audit trail — все запросы аудитора логируются через Snowflake QUERY_HISTORY + CloudTrail S3 access logs. SwiftRide может продемонстрировать audit committee «да, Big 4 обращались к evidence в эти timestamps; покрыли эти выборки».
Требования retention по регуляциям
SOX 404 + AS 1105 устанавливает базовую линию 7 лет для US SOX. Другие регуляции варьируются:
| Регуляция | Retention | Примечания |
|---|---|---|
| SOX 404 / PCAOB AS 1105 | 7 лет от закрытия audit period | Базовая линия для контролей, обусловленных US SOX |
| GDPR Art. 30 records of processing | По политике retention организации (обычно 6 месяцев — 5 лет) | Evidence, связанный с PII; согласно Art. 5(1)(e) storage limitation |
| AMLR / FATF R.11 | 5-7 лет после окончания отношений | Evidence KYC + transaction monitoring |
| EU AI Act Art. 18 | 10 лет от окончания placing on market | Документация high-risk AI-системы |
| PCI-DSS v4.0.1 Req. 10.5 | Минимум 1 год, немедленная доступность 3 месяца | Audit logs cardholder data |
| IRS / national tax | 3-7 лет в зависимости от юрисдикции | Evidence, связанный с налогами (1099, withholding) |
| BCBS 239 / ECB | Конкретно не предписан; согласуется с supervisory framework | Банки обычно 7+ лет |
| DORA Art. 11-12 | На протяжении ICT lifecycle + 5 лет | Evidence операционной устойчивости |
Самое ограничивающее побеждает. Multi-regulator CDE — стандартизируем по самому высокому. CDE-SWR-003 (driver_earnings — SOX + GDPR + IRS 1099 + EU labor + PCI-DSS, если card-linked) — 7 лет SOX доминирует ежедневно; 10 лет EU AI Act применяется, если ценообразование задействует high-risk AI-модель.
Практический паттерн для SwiftRide: дефолт 7 лет; дольше для конкретных CDE согласно retention metadata в реестре (M4.5). Стоимость хранения — Glacier Deep Archive на год 1; ~23/TB/месяц. Годовая стоимость для ~10TB evidence: $1.2K/год. Пренебрежимо vs избегаемые audit costs.
Evidence pipeline SwiftRide — конкретная архитектура
┌──────────────────────────────────────────────────────────────────────┐
│ Engine layer │
│ ├─ GE 1.17.1 Checkpoints (часовые на CDE-колонках) │
│ ├─ Soda Core 4.0 contract scans (ежедневные contract checks) │
│ ├─ dbt 1.9 tests (на каждый build + архив manifest) │
│ └─ Custom Python parity check (per CDE-SWR-003 CTL-004) │
│ │ │
│ ▼ (validation results JSON) │
│ Emitter layer (AWS Account: swr-evidence-prod) │
│ ├─ Lambda swr-evidence-emitter (Python 3.13) │
│ │ ├─ Нормализация в evidence-schema-v1 │
│ │ ├─ Захват input_state (снапшот Snowflake + sha256 hash) │
│ │ ├─ HMAC-SHA256 sign через KMS-ключ │
│ │ └─ Emit в 3 sinks параллельно │
│ │ ├─→ S3 Object Lock (первичный evidence) │
│ │ ├─→ OpenLineage Kafka topic openlineage.runs │
│ │ └─→ Snowflake audit.evidence_index INSERT │
│ │ │
│ ▼ │
│ Неизменяемое хранилище │
│ ├─ S3 bucket swr-evidence-prod-cde-evidence │
│ │ ├─ Object Lock Compliance Mode дефолт 7 лет │
│ │ ├─ SSE-KMS encryption │
│ │ ├─ Cross-region replication в eu-central-1 │
│ │ └─ Lifecycle к Glacier Deep Archive на год 1 │
│ │ │
│ ▼ │
│ Attestation layer │
│ ├─ Workiva connectors пуллят квартально │
│ ├─ Business Owner просматривает + e-подписывает │
│ ├─ Запись attestation архивируется обратно в S3 Object Lock │
│ │ │
│ ▼ │
│ Auditor view │
│ ├─ Snowflake AUDIT_AUDITOR_ROLE — SELECT на audit.evidence_index │
│ ├─ IAM read-only S3 access на evidence-бакет │
│ ├─ KMS Verify permission для проверки подписи │
│ └─ Audit-trail через QUERY_HISTORY + CloudTrail S3 access logs │
└──────────────────────────────────────────────────────────────────────┘
Операционные метрики Q3 2026:
- Эмиссия evidence: ~5.2M / квартал (GE часовые × 30 контролей × 92 дня + Soda ежедневные × 60 контролей × 92 дня + dbt build × ~200 PR + parity check × 92 дня)
- Рост хранилища: ~2.8 TB / квартал (в основном Data Docs HTML + GE validation_results.json)
- Средняя задержка S3 PUT: 180ms p99
- Лаг cross-region replication: < 30 секунд p99
- Верификация целостности evidence (ежедневная пересборка HMAC выборки): 100% совпадение в Q3
- Задержка audit-запроса (audit.evidence_index point query): < 100ms p99
Антипаттерны — детально
Изменяемая Snowflake-таблица = первичный evidence
Паттерн: INSERT INTO audit.control_runs (run_id, timestamp, control_id, result) после каждого прогона.
Почему плохо: Snowflake DML изменяем; DBA с MODIFY permission может UPDATE/DELETE ретроспективно; Time Travel максимум 90+7 дней; не WORM. PCAOB AS 1105 ¶.07-.08 — внутренний источник со слабыми контролями = tier 4 reliability; аудитор хочет минимум tier 3+.
Исправление: Snowflake-таблица — вторичный индекс, указывающий на первичный evidence в S3 Object Lock. Audit.evidence_index — изменяема для INSERT, но никогда UPDATE/DELETE на исторических строках; паттерны доступа принуждаются через stored procedures + RBAC.
Нет хеша входа
Паттерн: payload evidence захватывает timestamp + result; не захватывает sha256 входного rowset.
Почему плохо: аудитор не может независимо пересчитать — даже если снапшот Snowflake доступен, нет уверенности, что снапшот совпадает с тем, на чём работал контроль. Снапшот Time Travel в timestamp X — но контроль мог запуститься в X + 30 секунд на немного более новом состоянии.
Исправление: захватить явный input_hash = sha256 нормализованной проекции входа (отсортированной по primary key + релевантным колонкам, сериализованным в JSON). Тест пересчёта: «захешируйте эту проекцию снапшота Snowflake и подтвердите совпадение с input_hash из evidence».
Нет timestamp от доверенного источника
Паттерн: emitter использует Python datetime.now() без обеспечения NTP-синхронизации.
Почему плохо: контейнеризированные нагрузки часто без NTP-синхронизации; возможен дрейф часов; даже на AWS, system clock без proper sync к AWS time source.
Исправление: AWS Lambda — часы автоматически синхронизированы с AWS time source; используйте встроенный time.time(). Для ECS/EKS — проверить, что NTP daemon работает; алерт при дрейфе > 100ms. Альтернатива — использовать server-side timestamp от S3 PUT (заголовок x-amz-date) как авторитетный; не всегда практично, потому что timestamp emitter захватывается до PUT в S3.
Единая точка отказа хранилища
Паттерн: S3-бакет в одном регионе; основной AWS-аккаунт.
Почему плохо: отключение региона AWS (us-east-1 outage Dec 2021, инциденты в eu-central-1) — evidence недоступен во время отключения; если аккаунт скомпрометирован (insider, украденные credentials), evidence в опасности.
Исправление: cross-region replication (CRR) во вторичный регион; отдельный AWS-аккаунт для evidence-бакета (defence-in-depth). Накладные расходы < 2x; устойчивость значительна.
Retention настроен, но не протестирован
Паттерн: политика бакета говорит 7 лет; никто не верифицирует, что retention применён per-object.
Почему плохо: bucket-default retention применяется только к новым объектам после применения политики; существующие объекты могут иметь более короткий retention или его отсутствие.
Исправление: ежемесячная автоматическая проверка — выборка N=100 случайных объектов по бакету; запрос head-object для Object Lock retention metadata; алерт на объекты с retention < 7 лет. Эксплицитная верификация Q1 каждого года.
Резюме
- Evidence pipeline = 5 стадий: engine → emitter → неизменяемое хранилище → attestation → auditor view. Emitter — единая точка целостности; неизменяемое хранилище — separation of concerns.
- Выбор DQ engine (GE 1.17.1 / Soda 4.0 / Anomalo / dbt tests) — локальный; storage + auditor стадии tool-agnostic.
- S3 Object Lock Compliance Mode = дефолт SwiftRide; Governance Mode приемлем при жёстком IAM; отдельный AWS-аккаунт = defence-in-depth.
- Retention выравнен с регулятором; SOX 7 лет базовая линия; EU AI Act 10 лет для high-risk AI; самое ограничивающее побеждает для multi-regulator CDE.
- Антипаттерны: Snowflake-таблица = первичная (изменяема, максимум 90 дней Time Travel); нет хеша входа (нет пересчёта); нет timestamp от NTP-trusted источника; один регион; retention не протестирован.
- Pipeline SwiftRide — emitter Lambda в отдельном AWS-аккаунте; cross-region replication S3; Snowflake audit.evidence_index вторичный индекс; слой attestation Workiva; роль read-only access Big 4.
В M7.3 разберём OpenLineage и Marquez как слой evidence trail — lineage + run events + dataset events; интеграция с dbt / Spark / Airflow; что аудитор хочет от evidence lineage.
Observability — мониторинг health evidence pipeline Форматы хранения — immutability и retention