Production Hardening Flags
Production hardening flags control the runtime behaviour of the PostMTA Hybrid appliance. Each flag has a defined risk level, a default value set at install time, and a documented rollback procedure. All flags live under thepmh.runtime Helm values namespace. Changing a flag in production requires a helm upgrade and a subsequent smoke-gate verification pass.
Reference Identifier
The authoritative reference for this page isPMH-SEC-025 — Production Hardening Flags. When opening a related security ticket, always quote PMH-SEC-025 in the subject line.
Flag Overview
Nine runtime flags govern critical subsystems: MIB/SNMP inspection, development seed injection, lab-metrics bypassing, TLS minimum version enforcement, queue drain pacing, bounce classification strictness, credit enforcement, spam-score gating, and WAL archiving. The table below enumerates each flag, its default, its risk classification, and the one-step rollback command.
Flag Reference Table
| Flag Name | Default | Risk Level | Description | Rollback Command |
|---|---|---|---|---|
MIB_CHECK_ONLY | false | MEDIUM | When true, the Kumo MTA runs in MIB-check-only mode: no mail is transmitted, SNMP traps are still evaluated. Used during provisioning to validate the SNMP endpoint before enabling delivery. | |
ALLOW_DEV_SEED | false | HIGH | Permits injection of seed addresses from the pmh.seeds.*values block into the suppression engine. Should never betrue in a production tenant namespace. | |
KUMO_METRICS_LAB_BYPASS | false | MEDIUM | Bypasses the Prometheus metrics scrape path for lab environments where the scrape endpoint is unreachable. Must never be truein production — metrics will silently drop. | |
ENFORCE_TLS12_MIN | true | LOW | Requires TLS 1.2 or higher for all inbound and outbound SMTP connections. Disable only for legacy MTAs that do not support TLS 1.2; doing so voids compliance with PMH-SEC-012. | |
QUEUE_FLUSH_INTERVAL | 30 seconds | MEDIUM | Minimum elapsed time between queue drain batches. Lower values drain faster but increase API pressure on the PostgreSQL credit ledger. Values below 10 are not supported. | |
BOUNCE_CLASSIFICATION_STRICT | true | MEDIUM | When true, every non-2xx SMTP response is classified as a hard bounce and immediately suppresses the recipient. Whenfalse, transient 4xx codes are retried for up to 72 hours before suppression. | |
CREDIT_ENFORCEMENT | true | HIGH | When true, messages are rejected at the shaping layer if the credit balance is zero or negative. When false, the credit check is bypassed and messages are sent on credit float — billing reconciliation will be incorrect. | |
SPAM_SCORE_THRESHOLD | 5.0 | LOW | SA Score above which a message is quarantined rather than delivered. Range is 0.1 – 10.0. Raising above7.0 effectively disables spam filtering. | |
WAL_ARCHIVE_MODE | archive | HIGH | Controls PostgreSQL WAL destination. Legal values: archive(write to S3-compatible path), local (write to/var/lib/postgresql/wal), disabled(no WAL captured). Switching to disabled breaks point-in-time recovery and is not permitted on production tiers. | |
Smoke Gate Procedure
After every flag change you must run the smoke gate. The smoke gate is a four-step manual verification sequence. Do not skip any step. If any step fails, roll back immediately before continuing.
Step 1 — Pod Restart Verification
Confirm the pmh-core Deployment has restarted after the helm upgrade and that all desired replicas are in the Running state.
kubectl rollout status deployment/pmh-core \
--namespace pmh-system --timeout=120sStep 2 — Shaping Endpoint Check
Call the internal shaping health endpoint and confirm it returns200 OK with a JSON body that includes"status": "ok".
kubectl exec -n pmh-system \
$(kubectl get pod -n pmh-system -l app=pmh-core \
-o jsonpath='{.items[0].metadata.name}') \
-- curl -sf http://localhost:8081/health/shapingStep 3 — Queue Depth Sanity
Query the Kumo MTA queue depth via the admin RPC port. The value must be non-negative and less than the configured overflow threshold (pmh.runtime.MAX_QUEUE_DEPTH, default 50 000).
kubectl exec -n pmh-system \
$(kubectl get pod -n pmh-system -l app=pmh-core \
-o jsonpath='{.items[0].metadata.name}') \
-- kumoctl -c /etc/pmh/kumoctl.toml \
queue depth 2>&1 | grep -E '^total'Step 4 — Credit Ledger Sync
Verify the credit ledger is advancing by reading the last_sync_attimestamp from the Caddy-side API and confirming it is within the last two minutes.
curl -sf http://localhost:9080/internal/credits/last_sync \
| python3 -c "import sys,json; t=json.load(sys.stdin)['last_sync_at']; \
import datetime,time; \
age=int(time.time())-int(t); \
assert age<120, f'Credit sync stale: {age}s old'); \
print(f'Credit sync OK: {age}s ago')"Risk Level Definitions
| Level | Colour | Definition | Change Requires |
|---|---|---|---|
| LOW | Green | No impact on deliverability, billing, or compliance. Safe to change during business hours with a single engineer. | One engineer approval |
| MEDIUM | Amber | May affect deliverability rates or cause brief increased API load. Requires two-engineer approval and a 15-minute monitoring window post-change. | Two engineer approvals |
| HIGH | Red | Directly affects billing accuracy, data integrity, or compliance. Requires a change freeze exception approved by the on-call SRE before the maintenance window begins. | SRE on-call approval + change freeze exception |
Related Documentation
- Production Runbook — pre-flight checklists and deployment steps that must accompany any flag change.
- GPG Backup & Restore — WAL archive mode and point-in-time recovery when WAL_ARCHIVE_MODE is active.
- TLS and Security — PMH-SEC-012 TLS compliance that ENFORCE_TLS12_MIN enforces.