Pular para o conteúdo

Observabilidade: log SIEM com encadeamento por hash e relatórios de renderização

O módulo Observability fornece a implementação do estado de runtime: um log SIEM encadeado por hash e à prova de adulteração, a agregação de relatórios de renderização e piloto, um log de auditoria de módulo de segurança de hardware (HSM) e implementações no-op completas de métricas e rastreamento, para que a instrumentação esteja sempre disponível para ser chamada.

Uma página canônica por tema. Os contratos de observabilidade — ContextAwareExceptionInterface, SpectrumInterface, JobNotificationInterface e o enum DegradationPolicy — são documentados em Contracts / Observability. Esta página documenta a implementação concreta do estado de runtime. As páginas são complementares, não duplicadas: use a página de contratos para a interface do provedor de serviço (SPI) e esta página para o log SIEM, os relatórios e as superfícies de auditoria.

Terminal window
composer require nextpdf/core:^3

Este módulo transforma o estado de runtime do engine em saída durável e verificável.

HashChainSiemEventLog é a superfície de segurança. Ele implementa o contrato SiemEventEmitter e grava um log JavaScript Object Notation (JSON) Lines em que o hash de cada registro é SHA-256(prev_hash_bytes || canonical_event_bytes). Esse encadeamento linear por hash torna o log à prova de adulteração: se qualquer byte for alterado, uma linha for excluída ou as linhas forem reordenadas, a cadeia se rompe. verifyIntegrity() percorre o arquivo e retorna o índice do primeiro registro inconsistente, ou null quando a cadeia está íntegra. readAll() transmite os registros por streaming. Um flock(LOCK_EX) consultivo por processo protege a seção crítica de ler o final e anexar, para que processos PHP concorrentes no mesmo arquivo não intercalem registros. O limite é explícito: trata-se de um encadeamento linear por hash, não de uma árvore de Merkle do Request for Comments (RFC) 6962. Ele é suficiente para prova de adulteração, mas não para provas de inclusão eficientes. O código-fonte declara isso. SiemEvent carrega o evento tipado com toCanonicalJson(). SiemEventSeverity e SiemEventType o classificam. CorrelationContext e CorrelationIdGenerator carregam um id de correlação entre eventos relacionados.

RenderReportBuilder, RenderReport, PilotReportAggregator e PilotSummary compõem a superfície de relatórios (@since 5.1.0). O agregador coleta RenderReports e produz um PilotSummary que é renderizado como array, JSON ou Markdown, em um formato utilizável por uma revisão de operações.

HsmAuditLogInterface / HsmAuditEvent registram operações de assinatura apoiadas por HSM para a camada de segurança. As interfaces MetricsCounterInterface, MetricsGaugeInterface, MetricsHistogramInterface e TraceSpanInterface definem os formatos de métricas e rastreamento. As implementações NoOp* fornecem um fallback inerte completo, para que o engine possa emitir métricas e spans sem um backend configurado.

Estabilidade: experimental. O log SIEM é internamente marcado por ciclo, em vez de carregar um @since de versionamento semântico (semver) congelado, e a superfície de relatórios é @since 5.1.0. As superfícies são funcionais e testadas, mas os formatos da interface de programação de aplicações (API) podem evoluir. Trate o formato do log (JSON canônico + encadeamento por hash) como o contrato estável e a API PHP como algo ainda em ajuste.

ClasseMembros principaisFunção
HashChainSiemEventLogemit(SiemEvent), verifyIntegrity(): ?int, readAll(): GeneratorLog SIEM encadeado por hash e à prova de adulteração
SiemEventtoCanonicalJson()Evento SIEM tipado
SiemEventSeverity / SiemEventType (enums)classificaçãoClassifica a severidade e o tipo do evento
CorrelationContext / CorrelationIdGeneratorencadeamento de correlaçãoEncadeia a correlação entre eventos relacionados
RenderReportBuilder / RenderReportmontagem de relatóriosCria relatórios por renderização (@since 5.1.0)
PilotReportAggregatoraddReport(), count(), getSummary(), toJson(), toMarkdown(), exportReportsJson()Agrega relatórios de renderização (@since 5.1.0)
PilotSummarytoArray(), toJson(), toMarkdown()Resume a saída da revisão de operações (@since 5.1.0)
HsmAuditLogInterface / HsmAuditEventRegistro de auditoria HSMRegistra auditorias de operações HSM
NoOpSiemEventEmitter, NoOpMetricsCounter, NoOpTraceSpan, …fallbacks inertesFornece implementações no-op completas

Execute composer docs:generate-api-php -- --module=Observability para gerar a tabela PHPDoc completa.

Emita um evento e verifique a integridade do log.

<?php
declare(strict_types=1);
require_once __DIR__ . '/../vendor/autoload.php';
use NextPDF\Observability\Siem\HashChainSiemEventLog;
use NextPDF\Observability\Siem\SiemEvent;
$log = new HashChainSiemEventLog('/var/log/nextpdf/siem.jsonl');
$log->emit(new SiemEvent(/* type, severity, payload */));
$firstBroken = $log->verifyIntegrity();
echo $firstBroken === null
? "SIEM chain intact.\n"
: "Tamper detected at record {$firstBroken}.\n";

Encapsule o emissor para que uma falha de gravação de log no caminho crítico de assinatura continue sendo uma decisão local, em vez de se tornar uma exceção não tratada.

<?php
declare(strict_types=1);
require_once __DIR__ . '/../vendor/autoload.php';
use NextPDF\Observability\Siem\HashChainSiemEventLog;
use NextPDF\Observability\Siem\Exception\SiemEmitterException;
use NextPDF\Observability\Siem\SiemEvent;
use Psr\Log\LoggerInterface;
final readonly class AuditedSiemSink
{
public function __construct(
private HashChainSiemEventLog $log,
private LoggerInterface $fallback,
) {}
public function record(SiemEvent $event): void
{
try {
$this->log->emit($event);
} catch (SiemEmitterException $e) {
// Do not let SIEM I/O abort the signing path; record and continue.
$this->fallback->critical('SIEM emit failed; event not chained.', [
'error' => $e->getMessage(),
]);
}
}
}
  • emit() lança SiemEmitterException em erros de gravação. Um chamador no caminho crítico de assinatura deve encapsulá-lo e decidir localmente se vai suprimir, repetir ou abortar. O emissor não decide por você.
  • verifyIntegrity() retorna o índice do primeiro registro corrompido, ou null. Um resultado não nulo significa que o log está comprometido a partir daquele ponto. Não confie nos registros naquele ponto nem depois dele.
  • O flock consultivo é por processo e no mesmo arquivo. A concorrência entre hosts exige um sink fora de banda, como o encaminhamento de syslog. Não presuma que o bloqueio de arquivo coordene máquinas diferentes.
  • Trata-se de um encadeamento linear por hash, não de uma árvore de Merkle. Ele fornece prova de adulteração, não provas de inclusão eficientes. Não o divulgue como tal.
  • Os fallbacks NoOp* são completos e inertes. Não crie ramificações com base na disponibilidade do backend para “economizar trabalho”. O no-op já não custa nada.

emit() lê o hash do registro anterior e anexa uma linha sob um bloqueio de arquivo: O(1) por evento mais o bloqueio. verifyIntegrity() é O(n) na contagem de registros porque percorre toda a cadeia. Execute-o de forma agendada, não no caminho crítico. A agregação de relatórios é linear no número de relatórios. O perfil de reprodutibilidade é structural: eventos e relatórios carregam timestamps e IDs de correlação, de modo que duas execuções diferem nesses campos enquanto a estrutura da cadeia permanece determinística.

O log SIEM é um controle de segurança. Sua prova de adulteração depende da proteção tanto do arquivo de log quanto da etapa de verificação: armazene o arquivo em um armazenamento com controle de acesso e apropriado para anexação, execute verifyIntegrity() de forma agendada e encaminhe os registros fora de banda para que o comprometimento de um host não possa reescrever o histórico silenciosamente. Os eventos podem carregar contexto sensível. Aplique a obrigação de limpeza de logs do projeto antes de construir o evento, não depois de encadeá-lo, porque uma reescrita de limpeza romperia a cadeia. O log de auditoria HSM registra operações de assinatura e também é relevante para a segurança. Trate-o com as mesmas proteções. Consulte o modelo de ameaças do engine em /modules/core/security/.

Este módulo não faz nenhuma afirmação normativa sobre especificações de PDF. Ele implementa mecanismos de integridade de log e observabilidade cujo design se alinha às práticas de gerenciamento de logs e verificação de integridade do NIST SP 800-92. Esse alinhamento com o framework de controles está documentado no código-fonte; não é uma citação de PDF fixada em chunk. A conformidade dos documentos que o engine produz é validada pelo oráculo e pelas suítes golden descritas em /modules/core/conformance/.