# Cert-Manager — Windows-Zertifikatsmanagement für IKK Kliniken

> Zentrales Zertifikatsmanagement mit Ampel-Dashboard, Agent-basierter Discovery, Mail-Alerts und Auto-Renew für alle Windows-Server.

## Was ist das?

Cert-Manager ist ein Hybrid-System zur Überwachung und Verwaltung von Windows-Zertifikaten in Klinikumgebungen. Ein leichtgewichtiger PowerShell-Agent läuft auf jedem Windows-Server, sammelt Zertifikate aus dem Zertifikatsspeicher und meldet sie an das zentrale Dashboard. Dort zeigt eine Ampel-Übersicht (Grün/Gelb/Rot) sofort, welche Zertifikate bald ablaufen oder bereits abgelaufen sind. Konfigurierbare Mail-Alerts warnen rechtzeitig, und per Klick kann eine Erneuerung angefordert werden.

Features:
- **Zertifikats-Discovery** — PowerShell-Agent scannt automatisch alle Zertifikate inkl. Subject, SAN, Aussteller, Template und Bindungen (IIS, RDP, SQL, Exchange)
- **Ampel-Dashboard** — Übersichtliche Darstellung: Grün (>30 Tage), Gelb (14–30 Tage), Rot (<14 Tage), Schwarz (abgelaufen)
- **Mail-Alerts** — Konfigurierbare Regeln (z.B. 30, 14, 7 Tage vor Ablauf) mit E-Mail-Benachrichtigung
- **CA-Profile** — Ordnet Zertifikate anhand des Issuers AD CS, ACME oder manuellen Public-CAs zu
- **AD-CS Renew** — Erneuerung per Klick mit expliziter `certreq -config "CAHOST\CAName"`-Zuordnung
- **Remote-Agent-Deployment** — Interner Deploy-Runner installiert den PowerShell-Agent per WinRM oder SMB/Scheduled Task
- **CSV-Export** — Alle Zertifikate als CSV für Audits und Dokumentation
- **Multi-Server** — Beliebig viele Windows-Server, gruppiert nach Standort und Rolle
- **Dienst-Bindungen** — Erkennt automatisch welche Dienste (IIS, LDAPS, RDP, SQL, SMTP) ein Zertifikat nutzen
- **SSE Live-Updates** — Echtzeit-Aktualisierung im Browser bei Agent-Reports
- **2 Rollen** — Admin (volle Verwaltung) und Viewer (nur lesen)

## Architektur

```
┌──────────────────────────────────────────────────────────────────┐
│   Cert-Manager Dashboard (FastAPI)                               │
│              localhost:8960                                       │
├──────────┬──────────────┬──────────────┬───────────────────────┤
│  Auth    │  Dashboard   │  Agent-API   │   Static              │
│ /api/    │  /api/       │  /api/agent/ │   /static/            │
│ auth/*   │  dashboard   │  report      │   index.html          │
│          │  zertifikate │  renew-result│   produkt.html        │
│          │  server      │              │                       │
│          │  alerts/*    │              │                       │
│          │  export/csv  │              │                       │
├──────────┴──────────────┴──────────────┴───────────────────────┤
│                                                                  │
│  ┌──────────────────────────────────────────────────────────┐   │
│  │           SQLite (aiosqlite)                             │   │
│  │                                                          │   │
│  │  server ──< zertifikat ──< bindung                      │   │
│  │                        ──< erneuerung                   │   │
│  │  alert_regel, alert_log                                 │   │
│  │  benutzer (JWT + bcrypt)                                │   │
│  └──────────────────────────────────────────────────────────┘   │
└──────────────────────────────────────────────────────────────────┘

┌──────────────────────────────────────────────────────────────────┐
│   PowerShell Agent (agent.ps1)                                   │
│   Läuft auf jedem Windows-Server (Scheduled Task / manuell)      │
│                                                                  │
│   1. Liest Zertifikate aus LocalMachine\My                       │
│   2. Prüft Bindungen (IIS, RDP, SQL, LDAPS)                     │
│   3. POST /api/agent/report → Dashboard                          │
│   4. Lauscht auf Renew-Anforderungen                             │
└──────────────────────────────────────────────────────────────────┘
```

## Projektstruktur

```
Cert-Manager/
├── main.py                  # FastAPI-Server (single-file Backend)
├── agent.ps1                # PowerShell-Agent für Windows-Server
├── deploy_runner.ps1        # Interner Runner fuer Remote-Agent-Installation
├── requirements.txt         # Python-Abhängigkeiten
├── cert_manager.db          # SQLite-Datenbank (wird automatisch erstellt)
├── static/
│   ├── index.html           # Dashboard (Dark Cyan Theme, SSE)
│   └── produkt.html         # Produktseite
├── README.md                # Technische Dokumentation
├── BENUTZERHANDBUCH.md      # Benutzerhandbuch
├── CLAUDE.md                # Claude Code Projektkontext
├── install.ps1              # Windows-Einzeiler-Installer (Dashboard)
├── install.sh               # Linux-Einzeiler-Installer (Dashboard)
├── deploy_vps.py            # Deploy auf VPS
└── deploy_downloads.py      # Download-Seite deployen
```

## Schnellstart

```bash
pip install -r requirements.txt
python main.py
```

Der Browser öffnet automatisch `http://localhost:8960`.

**Demo-Zugangsdaten:**

| Benutzer | Passwort | Rolle |
|----------|----------|-------|
| admin | admin | ADMIN |

## Datenmodell

```sql
server (id, hostname, ip, os_version, standort, rollen, agent_key, aktiv, letzter_check, erstellt_am)

ca_profile (id, name, typ, issuer_match, adcs_config, default_template, renewal_mode, aktiv)
    └──< zertifikat (id, server_id, thumbprint, subject, issuer, ca_profile_id, san, serial_number, template,
                      key_length, gueltig_ab, gueltig_bis, store, selbstsigniert, aktualisiert_am)
              └──< bindung (id, zertifikat_id, dienst, detail)

erneuerung (id, server_id, zertifikat_id, aktion, template, ca_profile_id, ca_config, thumbprint,
            renewal_provider, status, ergebnis, erstellt_am)

deployment_job (id, methode, status, dashboard_url, erstellt_von, erstellt_am, aktualisiert_am)
    └──< deployment_target (id, job_id, server_id, hostname, ip, standort, status,
                           runner_hostname, log, fehler, gestartet_am, abgeschlossen_am)

alert_regel (id, tage_vor_ablauf, empfaenger, aktiv)
alert_log (id, zertifikat_id, server_hostname, subject, tage_rest, gesendet_am)

benutzer (id, username, password_hash, name, rolle, aktiv, erstellt_am)
```

- **server** — Überwachte Windows-Server mit Hostname, IP, Standort und Rollen (z.B. Domain Controller, Exchange)
- **ca_profile** — CA-Zuordnung und Renew-Regel pro Issuer-Muster, z.B. interne AD CS oder Public-CA
- **zertifikat** — Einzelnes Zertifikat mit Thumbprint, Subject, SAN, Aussteller, Gültigkeitszeitraum und Template
- **bindung** — Dienst-Bindung eines Zertifikats (IIS, LDAPS, RDP, SQL, Exchange SMTP)
- **erneuerung** — Protokoll einer Zertifikatserneuerung (Status: ANGEFORDERT → ERFOLGREICH/FEHLGESCHLAGEN)
- **deployment_job/deployment_target** — Remote-Agent-Installationen, die ein interner Runner abarbeitet
- **alert_regel** — Konfigurierbare Warnregeln (Tage vor Ablauf + Empfänger)
- **alert_log** — Protokoll gesendeter Alerts (verhindert Doppelversand)
- **benutzer** — Login mit bcrypt-Hash und JWT-Token (8h Gültigkeit), Rollen: ADMIN, VIEWER

## Ampel-Logik

| Farbe | Bedingung | Bedeutung |
|-------|-----------|-----------|
| Grün | > 30 Tage bis Ablauf | Alles in Ordnung |
| Gelb | 14–30 Tage bis Ablauf | Warnung — bald erneuern |
| Rot | < 14 Tage bis Ablauf | Kritisch — sofort erneuern |
| Schwarz | Abgelaufen | Zertifikat ist abgelaufen |

## CA-Profile und Renew

Cert-Manager stellt Zertifikate nicht selbst aus. Der Agent liest den Aussteller aus dem Zertifikat und das Dashboard ordnet ihn einem CA-Profil zu.

Ein CA-Profil definiert:
- **Typ:** `ADCS`, `ACME` oder `MANUAL`
- **Issuer-Match:** Text oder Regex-Fragmente, getrennt mit `|`
- **AD-CS Config:** Ziel-CA im Format `CAHOST\CAName`
- **Renewal Mode:** `approval_required`, `auto` oder `manual`

Automatischer Renew ist fuer AD CS freigegeben, wenn das Zertifikat ein Template hat und das CA-Profil eine `AD-CS Config` enthaelt. Public-CAs, ACME-Zertifikate und selbstsignierte Zertifikate werden erkannt, aber nicht automatisch durch den Windows-Agent erneuert.

Der Renew-Job an den Agent enthaelt die konkrete CA-Config. Der Agent prueft die CA mit `certutil -config "CAHOST\CAName" -ping` und reicht die Anfrage dann mit `certreq -submit -config "CAHOST\CAName"` ein.

## Remote-Agent-Deployment

Der Cert-Manager auf der VPS greift nicht direkt ins interne Kliniknetz. Stattdessen laeuft dort ein `deploy_runner.ps1` auf einem Admin-Server. Dieser Runner verbindet sich aus dem internen Netz aktiv zum Dashboard, holt offene Deployment-Jobs ab und installiert den Agent auf Zielservern.

Unterstuetzte Methoden:
- **WINRM:** Kopiert `agent.ps1` und `agent.json` ueber PowerShell Remoting, registriert den Scheduled Task und startet einen ersten Agent-Lauf.
- **SMB_TASK:** Kopiert Dateien ueber `\\SERVER\C$` und registriert/startet den Task mit `schtasks`.

Das Dashboard speichert keine Domain-Credentials. Der Runner nutzt die Rechte des Kontos, unter dem er ausgefuehrt wird, oder eine lokal uebergebene PowerShell-Credential fuer WinRM.

Runner manuell starten:

```powershell
.\deploy_runner.ps1 -RunOnce -DashboardUrl https://cert-manager.c3po42.de -RunnerKey "<DEPLOY_RUNNER_KEY>"
```

Runner als geplante Aufgabe installieren:

```powershell
.\deploy_runner.ps1 -Install -DashboardUrl https://cert-manager.c3po42.de -RunnerKey "<DEPLOY_RUNNER_KEY>"
```

## API-Endpunkte

### Authentifizierung

| Methode | Pfad | Beschreibung |
|---------|------|-------------|
| POST | `/api/auth/login` | Login (username + password → JWT-Token) |
| GET | `/api/auth/me` | Aktueller Benutzer (Bearer-Token) |

### Dashboard

| Methode | Pfad | Beschreibung |
|---------|------|-------------|
| GET | `/api/dashboard` | Übersicht: Anzahl Server, Zertifikate nach Status, nächste Abläufe |

### Server

| Methode | Pfad | Beschreibung |
|---------|------|-------------|
| GET | `/api/server` | Alle aktiven Server mit Zertifikatsanzahl |
| GET | `/api/server/{id}` | Einzelner Server |
| POST | `/api/server` | Server anlegen (Admin) |
| DELETE | `/api/server/{id}` | Server deaktivieren (Soft-Delete, Admin) |

### Zertifikate

| Methode | Pfad | Beschreibung |
|---------|------|-------------|
| GET | `/api/zertifikate` | Alle Zertifikate (Filter: `server_id`, `status=abgelaufen/kritisch/warnung/ok`) |
| GET | `/api/zertifikate/{id}` | Einzelnes Zertifikat mit Bindungen |

### CA-Profile

| Methode | Pfad | Beschreibung |
|---------|------|-------------|
| GET | `/api/ca-profiles` | Aktive CA-Profile mit zugeordneten Zertifikaten |
| POST | `/api/ca-profiles` | CA-Profil anlegen (Admin) |
| PUT | `/api/ca-profiles/{id}` | CA-Profil aktualisieren (Admin) |
| DELETE | `/api/ca-profiles/{id}` | CA-Profil deaktivieren und Zertifikate neu zuordnen (Admin) |
| POST | `/api/ca-profiles/rematch` | Alle Zertifikate erneut anhand der Issuer-Matches zuordnen (Admin) |

### Erneuerungen

| Methode | Pfad | Beschreibung |
|---------|------|-------------|
| GET | `/api/erneuerungen` | Letzte 50 Erneuerungen |
| POST | `/api/erneuerungen/anfordern` | Erneuerung anfordern (Admin, benachrichtigt Agent per SSE) |

### Agent-Deployment

| Methode | Pfad | Beschreibung |
|---------|------|-------------|
| POST | `/api/deploy/jobs` | Agent-Installationsjob fuer Serverliste anlegen (Admin) |
| GET | `/api/deploy/jobs` | Letzte Deployment-Jobs anzeigen |
| GET | `/api/deploy/jobs/{id}` | Jobdetails inkl. Zielserver-Logs |
| GET | `/api/deploy/runner/jobs` | Deploy-Runner holt offene Ziele ab (`X-Deploy-Runner-Key`) |
| POST | `/api/deploy/runner/result` | Deploy-Runner meldet Zielstatus zurueck |
| GET | `/api/deploy/runner/agent-script` | Deploy-Runner laedt `agent.ps1` herunter |

### Alert-Regeln

| Methode | Pfad | Beschreibung |
|---------|------|-------------|
| GET | `/api/alerts/regeln` | Alle Alert-Regeln |
| POST | `/api/alerts/regeln` | Neue Regel anlegen (Admin) |
| DELETE | `/api/alerts/regeln/{id}` | Regel löschen (Admin) |
| GET | `/api/alerts/log` | Letzte 50 versendete Alerts |

### Agent-API

| Methode | Pfad | Beschreibung |
|---------|------|-------------|
| POST | `/api/agent/report` | Agent meldet Server + Zertifikate + Bindungen (X-Agent-Key Header) |
| GET | `/api/agent/jobs?hostname=...` | Agent ruft offene Renew-Jobs inkl. `ca_config` ab |
| POST | `/api/agent/renew-result` | Agent meldet Ergebnis einer Erneuerung |

### Export & Status

| Methode | Pfad | Beschreibung |
|---------|------|-------------|
| GET | `/api/export/csv` | CSV-Export aller Zertifikate (Semikolon-separiert) |
| GET | `/api/events` | Server-Sent Events (Live-Updates) |
| GET | `/api/health` | Health-Check (Version, Status) |

### Dokumentation

| Methode | Pfad | Beschreibung |
|---------|------|-------------|
| GET | `/docs/readme` | README als text/markdown |
| GET | `/docs/handbuch` | Benutzerhandbuch als text/markdown |
| GET | `/produkt` | Produktseite (HTML) |

## Agent-API Protokoll

### Report (Agent → Dashboard)

```json
POST /api/agent/report
Header: X-Agent-Key: cert-agent-2026

{
  "hostname": "DC01",
  "ip": "10.0.1.10",
  "os_version": "Windows Server 2022",
  "standort": "Ilmenau",
  "rollen": "Domain Controller, AD CS",
  "zertifikate": [
    {
      "thumbprint": "AABB1122...",
      "subject": "CN=DC01.ikk.local",
      "issuer": "IKK-CA",
      "san": "DC01.ikk.local",
      "serial_number": "1234ABCD",
      "template": "DomainController",
      "key_length": 2048,
      "gueltig_ab": "2025-06-01",
      "gueltig_bis": "2026-06-01",
      "store": "LocalMachine\\My",
      "selbstsigniert": false,
      "bindungen": [
        {"dienst": "LDAPS", "detail": "Port 636"}
      ]
    }
  ]
}
```

### Renew-Job (Dashboard → Agent)

```json
GET /api/agent/jobs?hostname=DC01
Header: X-Agent-Key: cert-agent-2026

[
  {
    "erneuerung_id": 12,
    "aktion": "RENEW",
    "template": "WebServer",
    "ca_config": "CA01\\IKK-CA",
    "renewal_provider": "ADCS",
    "thumbprint": "AABB1122..."
  }
]
```

### Renew-Result (Agent → Dashboard)

```json
POST /api/agent/renew-result
Header: X-Agent-Key: cert-agent-2026

{
  "hostname": "DC01",
  "zertifikat_id": 1,
  "aktion": "RENEW",
  "template": "DomainController",
  "status": "ERFOLGREICH",
  "ergebnis": "Neues Zertifikat: CCDD3344..."
}
```

## Rollen

| Rolle | Rechte |
|-------|--------|
| **ADMIN** | Alles: Server verwalten, Erneuerungen anfordern, Alert-Regeln konfigurieren, Benutzer |
| **VIEWER** | Nur lesen: Dashboard, Zertifikate, Server, Export |

## Alert-System

Der Alert-Checker läuft stündlich im Hintergrund und prüft alle aktiven Alert-Regeln gegen die Zertifikatsdatenbank. Für jede Kombination aus Zertifikat und Regel wird maximal ein Alert gesendet (Duplikat-Erkennung über alert_log).

Standard-Regeln: 30 Tage, 14 Tage, 7 Tage vor Ablauf.

## Demo-Daten

Beim ersten Start werden automatisch Demo-Daten angelegt:

- **5 Server:** DC01, EXCHANGE01, WEB01, RDS01, SQL01 (Ilmenau + Arnstadt)
- **10 Zertifikate** mit verschiedenen Ablaufzeitpunkten (abgelaufen, kritisch, Warnung, OK)
- **9 Dienst-Bindungen** (IIS, LDAPS, RDP, SQL, Exchange SMTP)
- **4 CA-Profile** (interne AD CS, Let's Encrypt, Public/Manual CA, Self-Signed)
- **3 Alert-Regeln** (30, 14, 7 Tage)

## Deployment

### Produktion
- URL: https://cert-manager.c3po42.de
- Port: 8960
- Deploy: `python deploy_vps.py`
- Downloads: `python deploy_downloads.py`

### Umgebungsvariablen

| Variable | Standard | Beschreibung |
|----------|----------|-------------|
| `DB_PATH` | `./cert_manager.db` | Pfad zur SQLite-Datenbank |
| `JWT_SECRET` | (dev-secret) | JWT-Signatur-Schlüssel |
| `PORT` | `8960` | Server-Port |
| `AGENT_API_KEY` | `cert-agent-2026` | API-Key für Agent-Authentifizierung |
| `DEPLOY_RUNNER_KEY` | `cert-deploy-runner-2026` | Separater API-Key fuer interne Deploy-Runner |
| `PUBLIC_BASE_URL` | `https://cert-manager.c3po42.de` | URL, die Agenten und Runner erreichen |
| `SMTP_HOST` | `smtp.gmail.com` | SMTP-Server für Alerts |
| `SMTP_PORT` | `587` | SMTP-Port |
| `SMTP_USER` | `c3po42.bot@gmail.com` | SMTP-Benutzer |
| `SMTP_PASS` | (leer) | SMTP-Passwort (App-Passwort) |
| `ALERT_FROM` | `c3po42.bot@gmail.com` | Absender für Alert-Mails |
| `ALERT_TO` | `andre@astockma.de` | Standard-Empfänger für Alerts |

## Tech-Stack

- **Backend:** Python 3.10+, FastAPI, uvicorn
- **Datenbank:** SQLite mit aiosqlite (WAL-Modus, Foreign Keys)
- **Auth:** JWT (python-jose) + bcrypt
- **Live-Updates:** Server-Sent Events (SSE)
- **Agent:** PowerShell (Windows-nativ, keine Zusatzsoftware nötig)
- **Frontend:** Single-file HTML (static/index.html), Dark Cyan Theme
