fix: remove committed private keys and add runtime cert generation (closes #12)
Some checks failed
CI/CD Pipeline / Code Format (push) Successful in 3s
CI/CD Pipeline / Clippy Lints (push) Successful in 43s
CI/CD Pipeline / All Unit Tests (push) Successful in 1m12s
CI/CD Pipeline / Security Audit (push) Successful in 5s
CI/CD Pipeline / Enrollment Tests (push) Successful in 1m12s
CI/CD Pipeline / Build Debian Package (Ubuntu 22.04) (push) Failing after 4s
CI/CD Pipeline / Verify Enrollment CLI Flag (push) Successful in 57s
CI/CD Pipeline / Build Debian Package (push) Failing after 4s
CI/CD Pipeline / Build RPM Package (push) Successful in 2m12s
CI/CD Pipeline / Build Arch Package (push) Successful in 2m18s
CI/CD Pipeline / Build Alpine Package (push) Failing after 3m7s
Some checks failed
CI/CD Pipeline / Code Format (push) Successful in 3s
CI/CD Pipeline / Clippy Lints (push) Successful in 43s
CI/CD Pipeline / All Unit Tests (push) Successful in 1m12s
CI/CD Pipeline / Security Audit (push) Successful in 5s
CI/CD Pipeline / Enrollment Tests (push) Successful in 1m12s
CI/CD Pipeline / Build Debian Package (Ubuntu 22.04) (push) Failing after 4s
CI/CD Pipeline / Verify Enrollment CLI Flag (push) Successful in 57s
CI/CD Pipeline / Build Debian Package (push) Failing after 4s
CI/CD Pipeline / Build RPM Package (push) Successful in 2m12s
CI/CD Pipeline / Build Arch Package (push) Successful in 2m18s
CI/CD Pipeline / Build Alpine Package (push) Failing after 3m7s
- Remove all private key files from git tracking (git rm --cached) - configs/certs/ca.key.pem, server.key.pem, client001.key.pem - tests/e2e/certs/client.key - Also remove public certs from configs/certs/ (generated at runtime) - Add .gitignore patterns for *.key, *.key.pem, configs/certs/*.pem, *.srl - Add scripts/generate-dev-certs.sh for runtime test cert generation - Update Python e2e test to generate certs on demand (ensure_certs()) - Update test_wrong_cert_connection to generate wrong-CA certs at runtime - Add gitleaks secret scanning job to CI workflow - Update SECURITY_FINDINGS_REPORT.md with critical finding for Issue #12 - Update SECURITY_CONTROLS_MATRIX.md evidence references - Add README.md to configs/certs/ and tests/e2e/certs/ Private keys were dev/test only - no production key rotation needed. Git history purge with filter-repo will follow after PR merge. Co-authored-by: git-echo <git-echo@moon-dragon.us>
This commit is contained in:
committed by
GitHub
parent
d0c0790cbf
commit
efaac33c47
@ -16,6 +16,7 @@ Usage:
|
||||
|
||||
import argparse
|
||||
import json
|
||||
import subprocess
|
||||
import sys
|
||||
import time
|
||||
from dataclasses import dataclass, field
|
||||
@ -37,6 +38,19 @@ CA_CERT = CERTS_DIR / "ca.crt"
|
||||
CLIENT_CERT = CERTS_DIR / "client.crt"
|
||||
CLIENT_KEY = CERTS_DIR / "client.key"
|
||||
|
||||
|
||||
def ensure_certs() -> None:
|
||||
"""Generate e2e test certificates at runtime if they do not exist."""
|
||||
if CLIENT_KEY.exists() and CLIENT_CERT.exists() and CA_CERT.exists():
|
||||
return
|
||||
script = Path(__file__).resolve().parent.parent.parent / "scripts" / "generate-dev-certs.sh"
|
||||
if not script.exists():
|
||||
raise FileNotFoundError(
|
||||
f"Certificate generation script not found: {script}. "
|
||||
"Run ./scripts/generate-dev-certs.sh manually."
|
||||
)
|
||||
subprocess.check_call([str(script)], stdout=subprocess.DEVNULL, stderr=subprocess.DEVNULL)
|
||||
|
||||
TARGETS = {
|
||||
"dev": {
|
||||
"name": "linux-patch-manager-dev",
|
||||
@ -537,14 +551,51 @@ def test_wrong_cert_connection(client: PatchAPIClient) -> str:
|
||||
"""Verify that connections with wrong cert are rejected.
|
||||
|
||||
Per spec: invalid/expired certificates should be silently dropped.
|
||||
Uses project test certs (different CA) which should be rejected.
|
||||
Generates a separate "wrong CA" certificate at runtime to test that
|
||||
certificates signed by an untrusted CA are rejected.
|
||||
"""
|
||||
project_ca = "/a0/usr/projects/linux_patch_api/configs/certs/ca.pem"
|
||||
project_cert = "/a0/usr/projects/linux_patch_api/configs/certs/client001.pem"
|
||||
project_key = "/a0/usr/projects/linux_patch_api/configs/certs/client001.key.pem"
|
||||
import tempfile
|
||||
wrong_ca_dir = Path(tempfile.mkdtemp(prefix="lpa-wrong-ca-"))
|
||||
try:
|
||||
# Generate a completely separate CA + client cert (wrong CA)
|
||||
wrong_ca_key = wrong_ca_dir / "ca.key"
|
||||
wrong_ca_cert = wrong_ca_dir / "ca.crt"
|
||||
wrong_client_key = wrong_ca_dir / "client.key"
|
||||
wrong_client_csr = wrong_ca_dir / "client.csr"
|
||||
wrong_client_cert = wrong_ca_dir / "client.crt"
|
||||
|
||||
if not Path(project_ca).exists():
|
||||
return "SKIPPED: Project test certs not available"
|
||||
subprocess.run(
|
||||
["openssl", "genrsa", "-out", str(wrong_ca_key), "2048"],
|
||||
check=True, capture_output=True,
|
||||
)
|
||||
subprocess.run(
|
||||
["openssl", "req", "-x509", "-new", "-nodes", "-key", str(wrong_ca_key),
|
||||
"-sha256", "-days", "1", "-out", str(wrong_ca_cert),
|
||||
"-subj", "/CN=Wrong CA/O=Attacker/C=US"],
|
||||
check=True, capture_output=True,
|
||||
)
|
||||
subprocess.run(
|
||||
["openssl", "genrsa", "-out", str(wrong_client_key), "2048"],
|
||||
check=True, capture_output=True,
|
||||
)
|
||||
subprocess.run(
|
||||
["openssl", "req", "-new", "-key", str(wrong_client_key),
|
||||
"-out", str(wrong_client_csr),
|
||||
"-subj", "/CN=wrong-client/O=Attacker/C=US"],
|
||||
check=True, capture_output=True,
|
||||
)
|
||||
subprocess.run(
|
||||
["openssl", "x509", "-req", "-in", str(wrong_client_csr),
|
||||
"-CA", str(wrong_ca_cert), "-CAkey", str(wrong_ca_key),
|
||||
"-CAcreateserial", "-out", str(wrong_client_cert),
|
||||
"-days", "1", "-sha256"],
|
||||
check=True, capture_output=True,
|
||||
)
|
||||
|
||||
project_cert = str(wrong_client_cert)
|
||||
project_key = str(wrong_client_key)
|
||||
except (subprocess.CalledProcessError, FileNotFoundError):
|
||||
return "SKIPPED: Could not generate wrong-CA test certificates"
|
||||
|
||||
session = requests.Session()
|
||||
session.cert = (project_cert, project_key)
|
||||
@ -559,6 +610,8 @@ def test_wrong_cert_connection(client: PatchAPIClient) -> str:
|
||||
return "Correctly rejected connection with untrusted client certificate"
|
||||
finally:
|
||||
session.close()
|
||||
import shutil
|
||||
shutil.rmtree(wrong_ca_dir, ignore_errors=True)
|
||||
|
||||
|
||||
def test_job_lifecycle(client: PatchAPIClient) -> str:
|
||||
@ -776,7 +829,10 @@ def main():
|
||||
)
|
||||
args = parser.parse_args()
|
||||
|
||||
# Verify certs exist
|
||||
# Generate certs at runtime if missing (private keys are not committed)
|
||||
ensure_certs()
|
||||
|
||||
# Verify certs exist after generation attempt
|
||||
if not CA_CERT.exists():
|
||||
print(f"ERROR: CA cert not found: {CA_CERT}")
|
||||
sys.exit(1)
|
||||
|
||||
Reference in New Issue
Block a user