Forwarding to MLog — the government register
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).
1. What the MLog sink does
Section titled “1. What the MLog sink does”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 mTLSRestClientis 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 indefaultmode; 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|pemare in.gitignore). GLog reuses eIntegritate’smisda.pfx(aliasmisda.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(ERRORwhen the audited op failed, elseINFO),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. mockmode (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.defaultmode does the real mTLS POST.
Configuration (mlog.*, prefix in MLogProperties)
Section titled “Configuration (mlog.*, prefix in MLogProperties)”| env var | property | default | notes |
|---|---|---|---|
MLOG_MODE | mlog.mode | mock | mock = shape-only no-op; default = real mTLS POST |
MLOG_URL | mlog.url | https://mlog.staging.egov.md:8443/register | register endpoint (mTLS) |
MLOG_KEYSTORE_PATH | mlog.keystore.path | certs/misda.pfx | filesystem path or classpath resource |
MLOG_KEYSTORE_PASSWORD | mlog.keystore.password | 123456 | PKCS12 password |
MLOG_KEYSTORE_ALIAS | mlog.keystore.alias | misda.bns.pki.gov.md | client-identity alias |
| — | mlog.enabled | true | master switch; false = no-op success |
| — | mlog.connection-request-timeout | 5 | seconds to wait for a pooled connection |
| — | mlog.response-timeout | 8 | seconds to wait for the response |
The live demo runs mock (no gov connectivity); set MLOG_MODE=default to attempt the real POST.
2. What triggers a forward to MLog
Section titled “2. What triggers a forward to MLog”Deciding which events go up happens in forward/ForwardOutboxService.scheduleForward.
There are three independent triggers — if any fires, an MLog outbox entry is created:
- Per-action-type strategy —
audit_action_type.strategyfor the event’sactionType.MLOGforwards to MLog only;ALLforwards to every sink (webhook + MLog);LOCAL/NONEdon’t forward at all. - 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. - Per-event hint — a truthy
details._forwardMlogon the ingested event (hasForwardMlogHint, accepts booleantrueor 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=50Scope 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 distinctserviceever 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. Scopeaudit:admin.updated_byrecords the acting admin.
5. The MLog tab in Căutare jurnale
Section titled “5. The MLog tab in Căutare jurnale”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).
6. Deployment
Section titled “6. Deployment”- Live at
https://glog.gstack.esempla.systems(backend-2.8.0+frontend-2.12.0-dual), runningmockmode (no gov MLog connectivity in the demo box). - Schema: Liquibase changelog
007-service-config-and-forward-payload.xml(audit_service_configtable +payload/response_bodycolumns onaudit_forward_outbox). - Changelogs are append-only — this one is additive.