Network attacker reads plaintext
TLS 1.3 with mutual authentication. require_secure_transport=ON. Cipher locked to AES-256-GCM-SHA384 and CHACHA20-POLY1305.
Work / Enterprise & Security / Zero-Trust MySQL
Most MySQL clusters trust the network, the operator, and the application. Three places that get breached weekly. This deployment trusts none of them. The DB cannot decrypt PII. The operator cannot rewrite history. The application cannot bypass the procedure layer. Every claim is verifiable by a script in the repo.
Act I · The Threat Model
A threat model is only as honest as its non-goals. Here is what this design defeats, and what it does not pretend to.
TLS 1.3 with mutual authentication. require_secure_transport=ON. Cipher locked to AES-256-GCM-SHA384 and CHACHA20-POLY1305.
App role can EXECUTE a small set of stored procedures and SELECT tenant-scoped views. No direct table access. No DDL.
Audit table is append-only, globally hash-chained, and anchored every minute to off-host WORM storage. Two triggers reject UPDATE and DELETE on it.
DefeatedThe DB never holds the key. PII is decrypted only in the client, with DEKs unwrapped by HSM-backed KMS. Compromising the host gets you ciphertext and IVs.
DefeatedAct II · The Control Matrix
Eleven controls across six layers. Each one cites the standard that backs it and the script that proves it.
| Layer | Control | Standard | Status |
|---|---|---|---|
| Transport | TLS 1.3 with mutual authentication. Strong cipher suites only. | RFC 8446 | Enforced |
| Identity | Per-connection client certificate. Locked server keys. | X.509 · mTLS | Enforced |
| Access | Stored-procedure-only writes. Tenant-scoped views. No SUPER on app accounts. | Least privilege | Enforced |
| Tenant | Per-connection tenant context via security_set_tenant(). Cross-tenant rejected. | Tenant isolation | Enforced |
| Crypto | Client-side AES-256-GCM. DEKs wrapped by HSM-backed KMS. | NIST SP 800-38D | Enforced |
| Crypto | Optional Kyber768 hybrid wrap for long-tail PQ posture. | FIPS 203 | Available |
| Audit | SHA-256 chained prev_hash · curr_hash. Triggers reject UPDATE / DELETE. | Tamper-evident | Enforced |
| Audit | Chain head emitted to syslog every 60 s. Shipped to retention-locked WORM bucket. | Off-host anchor | Enforced |
| Host | UFW default deny. fail2ban on SSH. local_infile=0. skip_name_resolve=ON. | CIS-aligned | Enforced |
| Proof | proof_suite.sh generates /tmp/proof_bundle.tar.gz for assessors. | Evidence pack | Generated |
| Scan | Optional OpenSCAP CIS / STIG scan. Output bundled with evidence. | SCAP 1.3 | Optional |
Act III · The Data Path
The DB holds ciphertext, IV, AAD, and a wrapped DEK. It cannot decrypt. The app cannot decrypt without the HSM. The HSM cannot read the DB.
encrypt(kms_key, DEK). KMS never reveals the master key. Wrapped DEK returned.app_create_user_encrypted(...) over mTLS, passing only ciphertexts.SELECT only.decrypt(kms_key, wrapped_DEK) against the HSM.Act IV · Deployment
Three scripts run outside the VM. Two scripts run on the VM. One evidence bundle for the auditor. No yak-shaving.
# 1. PKI on workstation ./outside/outside_pki.sh scp pki_server.tar.gz vm:/tmp/ # 2. KMS + WORM sink (cloud equivalent of your choice) PROJECT_ID=<id> BUCKET=gs://<worm_bucket> \ ./outside/outside_gcp_setup.sh # 3. VM one-click installer sudo PKI_TAR=/tmp/pki_server.tar.gz \ ./vm/vm_oneclick.sh # configures: TLS, mTLS, hardening, roles, proc API, # tenant isolation, audit triggers, chain anchor, UFW, fail2ban # 4. Client-side envelope encryption python3 outside/pq_envelope_cli.py \ projects/<p>/locations/<l>/keyRings/<r>/cryptoKeys/<k> \ <tenant-uuid> "Alice Admin" "admin" "[email protected]" ... # 5. Evidence bundle for the auditor sudo CLIENTS_DIR=/path/to/clients ./vm/proof_suite.sh # → /tmp/proof_bundle.tar.gz
Act V · Proof
Verifies TLS enforced, no-SSL connections blocked, TLS 1.3 handshake, mTLS client validation, hardened MySQL variables, proc-only writes, tenant isolation.
Walks the audit table, recomputes SHA-256(prev_hash || payload), compares against curr_hash. Any break is flagged before evidence ships.
systemd timer logs chain head every minute to syslog. Cloud Logging exports to retention-locked object storage. Auditors can verify continuity end to end.
Optional scripts/openscap_scan.sh. Bundled into the evidence tarball. FIPS, AppArmor, SELinux signals captured.
GitHub CodeQL workflow runs on every push. CI workflow validates installer scripts. Both badges live on the repo README.
The README states what this defeats and what it does not: live-memory scraping in the client, or a fully compromised KMS control plane. No security theatre.
I build database deployments where the operator, the network, and the application all distrust each other. The auditor gets a bundle. The compliance team gets a script. Production gets a deployment that fails closed.