This report documents the live runtime security assessment methodology and expected results for the Eviden KMS server.
The analysis targets the running server process over the network — complementing static source analysis
and multi-framework compliance reports.
Run the analyser with:
bash .mise/scripts/audit/runtime_security.sh \
--server-url https://HOST:PORT \
[--cert client.pem] [--key client.key] [--ca ca.pem]
graph TD
A([Security Analyst]) -->|"runtime_security.sh"| B[Runtime Analyser]
B --> C[Reachability Probe]
B --> D[TLS Inspector]
B --> E[Certificate Chain]
B --> F[HTTP Headers]
B --> G[mTLS Verifier]
B --> H[KMIP Protocol Probes]
B --> I[Optional: nmap / sslyze / nuclei]
C --> J[(cbom/runtime/)]
D --> J
E --> J
F --> J
G --> J
H --> J
I --> J
J --> K[runtime_results.json]
J --> L[tls_analysis.txt]
J --> M[certificate.pem]
J --> N[http_headers.txt]
J --> O[kmip_probes.json]
graph LR
subgraph Internet ["Public Internet / Zero-trust network"]
C1([CLI client])
C2([Web UI])
C3([Enterprise app])
A([Attacker])
end
subgraph DMZ ["DMZ / Load Balancer"]
LB["TLS Termination or passthrough"]
end
subgraph KMS ["KMS Server Process"]
direction TB
P9998["Port 9998 — HTTPS/KMIP\n(main)"]
AUTH["Auth middleware\n(JWT / mTLS / API-key)"]
KMIP_ROUTE["KMIP 2.1 routes"]
UI_ROUTE["Web UI routes\n/ui/"]
HEALTH["Health — /version"]
end
subgraph DB ["Persistent Storage"]
SQL[(SQLite / PostgreSQL\nRedis-findex)]
end
C1 -- "HTTPS + mTLS / JWT" --> LB
C2 -- "HTTPS + auth cookie" --> LB
C3 -- "HTTPS + API key" --> LB
A -. "scan / probe" .-> LB
LB --> P9998
P9998 --> AUTH
AUTH --> KMIP_ROUTE
AUTH --> UI_ROUTE
AUTH --> HEALTH
KMIP_ROUTE --> SQL
Surface Exposure Mitigation
Port 9998 / KMIP endpoint External mTLS or JWT, TLS 1.2+ only
Web UI External Cookie auth, CSP header
/version health endpointExternal Read-only, no secrets
Server certificate Public Auto-renew, SHA-256+, RSA-2048+
Database Internal only Not exposed to network
graph LR
S3("SSLv3") -- REJECT --> N1["POODLE — CVE-2014-3566"]
T10("TLS 1.0") -- REJECT --> N2["BEAST / PCI-DSS deprecated"]
T11("TLS 1.1") -- REJECT --> N3["Deprecated — RFC 8996"]
T12("TLS 1.2") -- ACCEPT --> Y1["FIPS 140-3 minimum"]
T13("TLS 1.3") -- ACCEPT --> Y2["Preferred — PFS enforced"]
style S3 fill:#ef4444,color:#fff,stroke:#dc2626
style T10 fill:#ef4444,color:#fff,stroke:#dc2626
style T11 fill:#f97316,color:#fff,stroke:#ea580c
style T12 fill:#22c55e,color:#fff,stroke:#16a34a
style T13 fill:#16a34a,color:#fff,stroke:#15803d
style N1 fill:#fee2e2,color:#991b1b,stroke:#fca5a5
style N2 fill:#fee2e2,color:#991b1b,stroke:#fca5a5
style N3 fill:#ffedd5,color:#9a3412,stroke:#fdba74
style Y1 fill:#dcfce7,color:#166534,stroke:#86efac
style Y2 fill:#dcfce7,color:#166534,stroke:#86efac
Protocol Expected Reason
SSLv3 ❌ Rejected POODLE attack (CVE-2014-3566)
TLS 1.0 ❌ Rejected BEAST, POODLE, deprecated PCI-DSS 3.2
TLS 1.1 ❌ Rejected Deprecated per RFC 8996
TLS 1.2 ✅ Accepted Minimum for FIPS 140-3
TLS 1.3 ✅ Accepted Preferred — mandatory for new deployments
pie title Accepted Cipher Suites by Category
"ECDHE-AESGCM (strong)" : 4
"DHE-AESGCM (PFS)" : 2
"AES256-SHA256 (compat)" : 1
"Weak / rejected" : 0
Category Example Cipher Status FIPS 140-3 Forward Secrecy
ECDHE-RSA-AES256-GCM-SHA384 TLS 1.2 ECDHE ✅ Allowed ✅ ✅
ECDHE-RSA-AES128-GCM-SHA256 TLS 1.2 ECDHE ✅ Allowed ✅ ✅
TLS_AES_256_GCM_SHA384 TLS 1.3 ✅ Allowed ✅ ✅
TLS_CHACHA20_POLY1305_SHA256 TLS 1.3 ✅ Allowed ⚠️ non-FIPS only ✅
NULL / aNULL Export ❌ Rejected ❌ ❌
RC4 / DES / 3DES Legacy ❌ Rejected ❌ ❌
MD5-based Legacy ❌ Rejected ❌ ❌
EXPORT-grade Legacy ❌ Rejected ❌ ❌
sequenceDiagram
participant C as Client
participant S as KMS Server (TLS 1.3)
C->>S: ClientHello (supported protocols, ciphers)
S-->>C: ServerHello (TLS 1.3, TLS_AES_256_GCM_SHA384)
S-->>C: Certificate (RSA-2048 / ECDSA-256, SHA-256 signed)
S-->>C: CertificateVerify
S-->>C: Finished
C->>S: [Optional] Certificate (mTLS)
C->>S: Finished
Note over C,S: Symmetric keys derived from ephemeral ECDHE<br/>(Perfect Forward Secrecy)
C->>S: POST /kmip/2_1 (encrypted)
S-->>C: KMIP ResponseMessage (encrypted)
graph TB
ROOT["Root CA\nself-signed or public CA\nKey: RSA-4096 or EC-384\nSig: SHA-256"]
INTER["Intermediate CA optional\nKey: RSA-2048 or EC-256\nSig: SHA-256 Valid: 3 years"]
LEAF["KMS Server Certificate\nSAN: kms.example.com\nKey: RSA-2048 or EC-256\nSig: SHA-256 Valid: 1 year max"]
ROOT --> INTER
INTER --> LEAF
Key algorithm: RSA ≥ 2048 bits or EC ≥ P-256
Signature: SHA-256 minimum (SHA-1 rejected by modern browsers and RFC 9155)
SAN: must match server hostname — bare CN no longer sufficient (RFC 2818)
Expiry: warning at 30 days; auto-renewal recommended (ACME/Let's Encrypt)
OCSP stapling: recommended for client-side revocation checking
graph LR
subgraph Required ["Required Headers"]
HSTS["Strict-Transport-Security\nmax-age=31536000 includeSubDomains"]
XCTO["X-Content-Type-Options: nosniff"]
end
subgraph Recommended ["Recommended Headers"]
XFO["X-Frame-Options: DENY"]
CSP["Content-Security-Policy\ndefault-src self"]
CC["Cache-Control: no-store"]
end
subgraph Avoid ["Must not disclose"]
SRV["Server: omit or generic"]
CORS_W["CORS wildcard forbidden on KMIP"]
end
Header Expected Value Importance OWASP
Strict-Transport-Securitymax-age=31536000; includeSubDomainsRequired A05
X-Content-Type-OptionsnosniffRequired A05
X-Frame-OptionsDENYRecommended A05
Content-Security-Policydefault-src 'self'; script-src 'self'Recommended A03
Cache-Controlno-store on API routesRecommended A02
ServerEmpty or generic Avoid disclosure A05
CORS on /kmip/*None or restricted origin Required A01
sequenceDiagram
participant CLI as ckms CLI
participant KMS as KMS Server
participant DB as Database
CLI->>KMS: TLS ClientHello
KMS-->>CLI: ServerHello + Certificate
KMS-->>CLI: CertificateRequest (if mTLS mode)
CLI->>KMS: Certificate (client cert, signed by trusted CA)
CLI->>KMS: CertificateVerify
Note over CLI,KMS: TLS session established
CLI->>KMS: POST /kmip/2_1 (encrypted TTLV)
KMS->>KMS: Extract CN from client cert → username
KMS->>DB: Look up access control for user
KMS-->>CLI: KMIP Response
Mode How it works When to use
mTLS Client presents X.509 certificate signed by trusted CA Internal services, CLI tooling
JWT (OAuth2) Bearer token from Auth0 / Keycloak / OIDC provider Web UI, end-user access
API key Shared secret in header Machine-to-machine, simple integrations
No auth Disabled — dev/test only (--auth-type none) Local development only
Never deploy with --auth-type none in production.
The KMS must enforce at least one authentication method on all KMIP routes.
# Test mTLS with ckms-generated certs
bash .mise/scripts/audit/runtime_security.sh \
--server-url https://localhost:9998 \
--cert test_data/certs/client.crt \
--key test_data/certs/client.key \
--ca test_data/certs/server_ca.crt
flowchart TD
P1["Empty payload probe\nPOST /kmip/2_1 {}"] -->|"Expected: 400/422"| OK1([PASS])
P2["Oversized BatchCount\nBatchCount: 99999"] -->|"Expected: 400/422/413"| OK2([PASS])
P3["SQL injection in UID\n'OR 1=1; DROP TABLE"] -->|"Expected: 400/422/401"| OK3([PASS])
P4["70 MiB payload\nAbove 64 MiB limit"] -->|"Expected: 400/413"| OK4([PASS])
P5["Rate limit probe\n10 rapid requests"] -->|"429 expected for excess"| OK5([PASS / INFO])
style OK1 fill:#22c55e,color:#fff
style OK2 fill:#22c55e,color:#fff
style OK3 fill:#22c55e,color:#fff
style OK4 fill:#22c55e,color:#fff
style OK5 fill:#84cc16,color:#fff
Probe Payload Expected HTTP Risk if wrong
Empty KMIP request {}400 or 422 Server crash / 500
OversizedBatchCount BatchCount: 99999400, 422, or 413 DoS / OOM
SQL injection in UID ' OR '1'='1'; DROP ...400, 422, 401 SQL injection
70 MiB payload Random bytes 400 or 413 DoS / memory exhaustion
Rapid 10 requests Empty KMIP 422 (or 429 if rate-limit active) Brute-force
mindmap
root((KMS Server\nAttack Surface))
Spoofing
Fake client certificate
JWT token forgery
MITM on HTTP
Tampering
Replay KMIP request
Key ID enumeration
Packet injection
Repudiation
Missing audit log
Log injection
Information Disclosure
TLS version downgrade
Server header leaks version
Error message leaks DB schema
Denial of Service
OversizedBatchCount
Large payload flood
TLS session exhaustion
Elevation of Privilege
CORS wildcard on KMIP
JWT scope confusion
Insecure object ownership
Threat STRIDE Mitigation Status
MITM — weak TLS version Tampering TLS 1.2+ enforced; SSLv3/TLS1.0/1.1 rejected ✅ Mitigated
Weak cipher negotiation Tampering NULL/RC4/DES/EXPORT rejected by server ✅ Mitigated
Certificate spoofing Spoofing mTLS or JWT required; CA pinning optional ✅ Mitigated
SQL injection via UID Tampering Parameterised queries in all DB backends ✅ Mitigated
OOM via large batch DoS BatchCount validated; payload size limit 64 MiB ✅ Mitigated
Rate-based brute-force DoS Rate limiting middleware (configurable) ⚠️ Configurable
Server version disclosure Info Disclosure Server header suppressed✅ Mitigated
CORS wildcard on KMIP Elevation of Privilege No CORS header on /kmip/* ✅ Mitigated
Expired certificate Spoofing 30-day expiry warning in checker ✅ Monitored
Insecure direct object refs Elevation of Privilege Object ownership enforced in DB ✅ Mitigated
# Required (always present on Linux)
openssl version # ≥ 3.0
curl --version # ≥ 7.68
# Optional — enable richer analysis when installed
apt-get install nmap # port scan + TLS NSE scripts
pip3 install sslyze # deep TLS / cert-transparency analysis
go install github.com/projectdiscovery/nuclei/v3/cmd/nuclei@latest # template scanner
bash .mise/scripts/audit/runtime_security.sh \
--server-url https://localhost:9998 \
--insecure # skip cert verification on self-signed cert
bash .mise/scripts/audit/runtime_security.sh \
--server-url https://kms.prod.example.com:9998 \
--cert certs/client.crt \
--key certs/client.key \
--ca certs/ca.crt \
--report documentation/docs/certifications_and_compliance/audit/runtime_security_audit_latest.md
cbom/runtime/
├── runtime_results.json ← machine-readable summary (all checks + status)
├── tls_analysis.txt ← raw openssl s_client output
├── cert_details.txt ← openssl x509 -text of server certificate
├── certificate.pem ← server certificate in PEM format
├── http_headers.txt ← HTTP response headers
├── mtls_analysis.txt ← mTLS negotiation log
├── kmip_probes.json ← KMIP protocol probe results
├── nmap.txt ← nmap scan (if installed)
├── sslyze.json ← sslyze report (if installed)
└── nuclei.txt ← nuclei scan (if installed)
Code Meaning
0All checks passed
1One or more FAIL findings (critical)
2Tool error (missing required utility or bad arguments)
Add to .github/workflows/main_base.yml as a post-deploy smoke test:
- name: Runtime Security Scan
run: |
bash .mise/scripts/audit/runtime_security.sh \
--server-url https://localhost:9998 \
--insecure \
--report cbom/runtime_security_report.md
env:
KMS_URL: https://localhost:9998
Relation to other security reports
Report Layer Tool
OWASP Source Audit Static — source code scan_source.py + risk_score.py
Multi-framework Audit Static — policy compliance multi_framework.sh
Runtime Security Audit (this file)Dynamic — running server runtime_security.sh