Sari la conținut

Forwarding to MLog — the government register

Acest conținut nu este încă disponibil în limba selectată.

GLog is the gStack ecosystem’s own audit store. MLog is the government-wide register of significant events (eIntegritate / egov.md). This doc covers the feature set that lets GLog forward selected audit events UPSTREAM to MLog over mutual TLS, plus the API and UI that show exactly what was sent.

TL;DR — GLog keeps every event locally (immutable hash chain). A subset — the legally-significant events — is additionally pushed to the government MLog register. Which events go up is decided by three independent triggers (§2). Everything transferred is captured (payload + MLog response) and queryable via GET /api/v1/admin/audit-events/forward.

Related docs: api.md (endpoint reference), integration-guide.md (how producers send events in the first place).


forward/MLogSink.java shapes a GLog AuditEvent into the government MLog register payload and POSTs it to mlog.url over mutual TLS. This is a faithful port of eIntegritate’s spring-boot-starter-mlog: the client certificate is the authentication — no JOSE signing is performed.

  • Transport (forward/MLogClientConfig.java). A PKCS12 keystore is loaded as the client identity; the mTLS RestClient is built with httpclient5 (SSLConnectionSocketFactory), the server’s self-signed leaf is trusted (chain.length == 1), and hostname verification is disabled (NoopHostnameVerifier) — the same permissive posture as the reference integration. The client is built only in default mode; if the keystore can’t be loaded, startup does not break — a plain client is returned so the POST fails and the outbox records the error.
  • The cert is gitignored and baked into the jar (src/main/resources/certs/*.pfx|cer|pem are in .gitignore). GLog reuses eIntegritate’s misda.pfx (alias misda.bns.pki.gov.md).
  • Payload shape = the MLog schema (snake_case), emitted only for present fields: event_type (mandatory) ← actionType/operation, event_time, event_level (ERROR when the audited op failed, else INFO), event_message (<service>:<operation>), user ← userDetails, user_address ← ipAddress, event_details ← details (JSON), subject ← idnp (the natural person acted upon), object ← objectAffected, object_name ← objectType.
  • mock mode (the default) shapes the payload but never sends it — a successful no-op, so the whole outbox pipeline can be exercised without the gov network. default mode does the real mTLS POST.

Configuration (mlog.*, prefix in MLogProperties)

Section titled “Configuration (mlog.*, prefix in MLogProperties)”
env varpropertydefaultnotes
MLOG_MODEmlog.modemockmock = shape-only no-op; default = real mTLS POST
MLOG_URLmlog.urlhttps://mlog.staging.egov.md:8443/registerregister endpoint (mTLS)
MLOG_KEYSTORE_PATHmlog.keystore.pathcerts/misda.pfxfilesystem path or classpath resource
MLOG_KEYSTORE_PASSWORDmlog.keystore.password123456PKCS12 password
MLOG_KEYSTORE_ALIASmlog.keystore.aliasmisda.bns.pki.gov.mdclient-identity alias
—mlog.enabledtruemaster switch; false = no-op success
—mlog.connection-request-timeout5seconds to wait for a pooled connection
—mlog.response-timeout8seconds to wait for the response

The live demo runs mock (no gov connectivity); set MLOG_MODE=default to attempt the real POST.


Deciding which events go up happens in forward/ForwardOutboxService.scheduleForward. There are three independent triggers — if any fires, an MLog outbox entry is created:

  1. Per-action-type strategy — audit_action_type.strategy for the event’s actionType. MLOG forwards to MLog only; ALL forwards to every sink (webhook + MLog); LOCAL/NONE don’t forward at all.
  2. Per-service toggle — audit_service_config.mlog_enabled, the “Trimite la MLog” switch on the Servicii page. When ON, every event of that service forwards to MLog, regardless of action-type strategy. All-or-nothing — use sparingly.
  3. Per-event hint — a truthy details._forwardMlog on the ingested event (hasForwardMlogHint, accepts boolean true or the string "true"). This is how a producing system marks this specific event as legally significant (e.g. drumuri’s per-event “mlog” checkbox).

Policy — send only legally-significant events

Section titled “Policy — send only legally-significant events”

MLog is the legal register, not a debug feed. Forward:

  • personal-data access / interoperability lookups (who read whose data),
  • official decisions with legal effect,
  • security events,
  • cross-institution data exchange.

Do NOT forward:

  • technical / debug / health events,
  • reads or lists of non-personal data,
  • drafts and intermediate states.

The per-event hint (trigger 3) is the precise tool: the producing system marks only its legal subset. The per-service toggle (trigger 2) is the blunt tool: it sends everything a service emits — appropriate only for services whose every event is legally significant.


3. The forward log — “what we sent to MLog”

Section titled “3. The forward log — “what we sent to MLog””

Every transfer is captured. Sinks return a ForwardResult(payload, response), and the outbox row (audit_forward_outbox) gained two columns (changelog 007): payload jsonb (the exact shaped body) and response_body (the sink’s raw response — for MLog, the registration UID). Rows written before this feature have a null payload.

Read it back with:

GET /api/v1/admin/audit-events/forward?sink=MLOG&limit=50

Scope audit:admin. Optional params: sink (e.g. MLOG), eventId (a single event’s forwards — used by the MLog tab, §5), limit (default 50, capped at 500). Without eventId the log is scoped to the caller’s tenant, newest first. Each row returns { id, auditEventId, sink, status, attempts, payload, response, lastError, createdAt, updatedAt }.

Dispatch is async with retry (exponential backoff, 2^attempts minutes capped at 60). Failed entries can be re-dispatched with POST /api/v1/admin/audit-events/forward/replay.


4. The Servicii page (service catalog + toggle)

Section titled “4. The Servicii page (service catalog + toggle)”

The Servicii page lists the full service catalog and carries the per-service MLog switch. Backed by ServiceCatalogService and table audit_service_config.

  • GET /api/v1/app/services → [{ service, mlogEnabled }]. The catalog is the union of (a) the statically configured well-known services (glog.amqp.services — gpay, gpass, gnotify, gsign, gdocs, gregistry, ginterdictii), (b) every distinct service ever seen in the event store, and (c) any service with a config row. This makes the page range-independent — all services are always listed, whether or not they logged in the selected window. Requires an authenticated principal.
  • PUT /api/v1/admin/services/{service}/mlog?enabled=<true|false> → sets (upserts) the toggle. Scope audit:admin. updated_by records the acting admin.

In the journal search UI (frontend/src/app/ui/events-table.ts), each event’s detail panel has an “MLog” tab alongside View / JSON / Integrity. Opening it lazily calls the forward endpoint filtered by that event (listForwards('MLOG', 20, eventId) → GET …/forward?sink=MLOG&eventId=<id>) and shows, per transfer: the status, the MLog response (UID), and the exact payload sent to MLog. If the event was never forwarded, the tab says so; a 403 shows an admin-only notice (the endpoint is audit:admin).


  • Live at https://glog.gstack.esempla.systems (backend-2.8.0 + frontend-2.12.0-dual), running mock mode (no gov MLog connectivity in the demo box).
  • Schema: Liquibase changelog 007-service-config-and-forward-payload.xml (audit_service_config table + payload/response_body columns on audit_forward_outbox).
  • Changelogs are append-only — this one is additive.