<!-- Copyright (c) 2026 defconxt. All rights reserved. -->
<!-- Licensed under AGPL-3.0 — see LICENSE file for details. -->
---
name: automating-certificate-lifecycle-management
description: >-
  Automate TLS/SSL certificate discovery, expiration monitoring, renewal
  orchestration, and deployment validation across infrastructure using
  ACME protocols, CT log monitoring, and certificate inventory tracking.
domain: cybersecurity
subdomain: security-operations-automation
tags:
  - certificates
  - tls
  - acme
  - pki
  - automation
  - lets-encrypt
version: "1.0"
author: defconxt
license: AGPL-3.0
metadata:
  mitre-attack: ["T1588.004"]
---

# Automating Certificate Lifecycle Management

## Overview

Expired or misconfigured certificates cause outages and security gaps.
This technique automates the full certificate lifecycle: discovery via
CT logs and network scanning, expiration tracking with alerting thresholds,
automated renewal through ACME, and post-deployment validation to confirm
correct chain and cipher configuration.

Mode: `[MODE: BLUE]` — Preventive infrastructure security.

## Prerequisites

| Requirement | Details |
|---|---|
| Python 3.10+ with `cryptography`, `requests` | Required |
| ACME client access (certbot, acme.sh, or custom) | Required |
| Certificate Transparency log API access | Required |
| DNS provider API for ACME DNS-01 challenges | Required |

## Key Concepts

### Certificate Discovery

```python
import ssl
import socket
from datetime import datetime, timezone
from typing import Any


def probe_certificate(hostname: str, port: int = 443) -> dict[str, Any]:
    """Connect to host and extract TLS certificate details."""
    context = ssl.create_default_context()
    with socket.create_connection((hostname, port), timeout=10) as sock:
        with context.wrap_socket(sock, server_hostname=hostname) as ssock:
            cert = ssock.getpeercert()
            not_after = datetime.strptime(
                cert["notAfter"], "%b %d %H:%M:%S %Y %Z"
            ).replace(tzinfo=timezone.utc)
            return {
                "hostname": hostname,
                "subject": dict(x[0] for x in cert["subject"]),
                "issuer": dict(x[0] for x in cert["issuer"]),
                "not_before": cert["notBefore"],
                "not_after": cert["notAfter"],
                "serial": cert.get("serialNumber", ""),
                "days_until_expiry": (not_after - datetime.now(timezone.utc)).days,
                "san": [
                    entry[1] for entry in cert.get("subjectAltName", [])
                ],
            }
```

### Expiration Monitoring

```python
def check_expiration(
    certs: list[dict[str, Any]],
    warn_days: int = 30,
    critical_days: int = 7,
) -> dict[str, list[dict[str, Any]]]:
    """Classify certificates by expiration urgency."""
    result: dict[str, list[dict[str, Any]]] = {
        "critical": [],
        "warning": [],
        "healthy": [],
        "expired": [],
    }
    for cert in certs:
        days = cert.get("days_until_expiry", 0)
        if days < 0:
            result["expired"].append(cert)
        elif days <= critical_days:
            result["critical"].append(cert)
        elif days <= warn_days:
            result["warning"].append(cert)
        else:
            result["healthy"].append(cert)
    return result
```

### ACME Renewal Orchestration

```python
import subprocess


def renew_certificate_acme(domain: str, method: str = "dns-01") -> dict[str, Any]:
    """Trigger ACME certificate renewal via certbot."""
    cmd = [
        "certbot", "certonly", "--non-interactive",
        "--agree-tos", "--preferred-challenges", method,
        "-d", domain,
    ]
    result = subprocess.run(cmd, capture_output=True, text=True, check=False)
    return {
        "domain": domain,
        "method": method,
        "success": result.returncode == 0,
        "stdout": result.stdout[-500:] if result.stdout else "",
        "stderr": result.stderr[-500:] if result.stderr else "",
    }
```

## Workflow

### Step 1: Scan Certificate Inventory

```bash
node scripts/agent.js --action scan --targets hosts.txt
```

### Step 2: Check Expirations

```bash
node scripts/agent.js --action check-expiry --warn-days 30
```

### Step 3: Trigger Renewal

```bash
node scripts/agent.js --action renew --domain app.corp.com
```

## Detection

```yaml
title: Automating Certificate Lifecycle Management Detection
id: 3518dab6-543a-4c0b-9ebc-4ff68910f9af
status: experimental
description: Detects suspicious activity related to automating certificate lifecycle management techniques in security operations automation context
logsource:
  category: process_creation
  product: linux
detection:
  selection:
    CommandLine: "*automating*certificate*"
  condition: selection
level: medium
tags:
  - attack.t1588.004
  - attack.discovery
falsepositives:
  - Orchestration platform executing approved automation workflows
```


**Detection Opportunities**

| Indicator | Source | Detection Logic |
|---|---|---|
| Automating Certificate Lifecycle Management Detection | linux/process_creation | Sigma rule (medium) |
| ATT&CK Coverage | MITRE ATT&CK | T1588.004 |

## Verification

- [ ] All public-facing certificates discovered and inventoried
- [ ] Expiration alerts fire at configured thresholds
- [ ] ACME renewal completes without manual intervention
- [ ] Post-renewal validation confirms correct chain installation

## References

- [RFC 8555 — ACME Protocol](https://www.rfc-editor.org/rfc/rfc8555)
- [Certificate Transparency](https://certificate.transparency.dev/)
- [CIS Control 3.10 — Encrypt Sensitive Data in Transit](https://www.cisecurity.org/controls)
