Skip to content

Load Testing

Chris Zinda edited this page Mar 6, 2026 · 1 revision

Load Testing

The load testing harness stress-tests the PKI infrastructure with concurrent certificate operations, measuring throughput, latency, and error rates under load.

Script

python scripts/load-test.py --target rsa --concurrency 10 --duration 60

Usage

python scripts/load-test.py [OPTIONS]
Option Default Description
--target rsa PKI hierarchy to test: rsa, ecc, pqc, all
--concurrency 5 Number of concurrent threads
--count 50 Total number of certificate operations
--mode issuance Operation mode (currently issuance)

Examples

# Test RSA PKI with 10 concurrent threads, 100 certificates
python scripts/load-test.py --target rsa --concurrency 10 --count 100

# Test all three PKI hierarchies
python scripts/load-test.py --target all --concurrency 5 --count 50

# Test post-quantum PKI
python scripts/load-test.py --target pqc --concurrency 3 --count 25

Architecture

ThreadPoolExecutor

The harness uses Python's ThreadPoolExecutor to issue certificates concurrently. Each thread:

  1. Generates a 2048-bit RSA key with openssl genrsa
  2. Creates a CSR with openssl req (CN: load-test-{target}-{seq}-{timestamp}.cert-lab.local)
  3. Submits the CSR to the CA via sudo podman exec ... pki ca-cert-request-submit
  4. Records success/failure and latency

A thread-safe Lock protects the shared LoadTestResult object during concurrent updates.

CA Targets

Each PKI type targets the IoT CA with the appropriate certificate profile:

Target Container Instance Profile
rsa dogtag-iot-ca pki-iot-ca caServerCert
ecc dogtag-ecc-iot-ca pki-ecc-iot-ca caECServerCert
pqc dogtag-pq-iot-ca pki-pq-iot-ca caMLDSAServerCert

Profile auto-selection ensures the correct signing algorithm is used for each hierarchy.

LoadTestResult

The LoadTestResult dataclass captures all metrics for a single test run:

Property Type Description
target str PKI type tested
mode str Operation mode
total_ops int Total operations attempted
successful int Operations that succeeded
failed int Operations that failed
latencies list Per-operation latency measurements (seconds)
errors list Error messages from failed operations
throughput float Successful operations per second
avg_latency float Mean latency across all operations
p50 float 50th percentile (median) latency
p95 float 95th percentile latency
p99 float 99th percentile latency

Output

Console Output

Progress is reported every 10 operations:

============================================================
Load Test: RSA PKI (issuance)
  Concurrency: 10
  Operations:  100
============================================================

  Progress: 10/100 (OK: 9, FAIL: 1)
  Progress: 20/100 (OK: 19, FAIL: 1)
  ...

============================================================
LOAD TEST RESULTS
============================================================

  RSA PKI:
    Total ops:     100
    Successful:    98
    Failed:        2
    Duration:      45.3s
    Throughput:    2.16 ops/s
    Avg latency:   0.432s
    P50 latency:   0.398s
    P95 latency:   0.821s
    P99 latency:   1.204s

JSON Results

Results are saved to:

data/perf-metrics/load-test-latest.json

Format:

{
  "rsa": {
    "total": 100,
    "successful": 98,
    "failed": 2,
    "duration_s": 45.3,
    "throughput_ops_s": 2.16,
    "avg_latency_s": 0.432,
    "p50_s": 0.398,
    "p95_s": 0.821,
    "p99_s": 1.204
  }
}

When testing with --target all, the JSON contains entries for each PKI type (rsa, ecc, pqc).

Notes

  • The harness uses sudo podman exec to submit CSRs, matching the rootful container environment.
  • Temporary key and CSR files are created in /tmp/ and cleaned up on success.
  • Each operation has a 60-second timeout to prevent thread starvation.
  • The default PKI admin password (RedHat123) is used for CA authentication.

Clone this wiki locally