Wir werden ein Certificate Transparency Log-System für interne PKIs aufbauen, indem wir Kafka als Nachrichtenwarteschlange und Trillian als unveränderlichen Merkle-Baum verwenden. Diese Konfiguration ermöglicht eine effiziente Überprüfung der Zertifikatsausstellungen, die Erkennung von falsch ausgestellten Zertifikaten und konsistenzbasierte Überprüfungen durch Gossip.

Warum sich mit internen CT-Logs beschäftigen?

Bevor wir in die technischen Details eintauchen, wollen wir die Frage klären: Warum sollten wir uns um die Implementierung von CT-Logs für interne PKIs kümmern?

  • Erkennung unautorisierter Zertifikatsausstellungen
  • Sicherstellung der Einhaltung interner Richtlinien
  • Verbesserung der Reaktionsfähigkeit bei Vorfällen
  • Erhöhung der allgemeinen Sicherheitslage

Betrachten Sie es als eine Vertrauens-, aber Überprüfungsstrategie für Ihre interne CA. Sie vertrauen Ihrer CA, möchten sie aber auch ehrlich halten.

Die Bausteine: Kafka und Trillian

Um unser internes CT-Log-System zu implementieren, verwenden wir zwei leistungsstarke Werkzeuge:

1. Apache Kafka

Kafka dient als unsere Nachrichtenwarteschlange und verarbeitet den hochdurchsatzstarken Eingang von Zertifikatsdaten. Es ist wie ein Förderband für Ihre Zertifikate und stellt sicher, dass sie in der richtigen Reihenfolge und mit hoher Zuverlässigkeit verarbeitet werden.

2. Trillian

Trillian, entwickelt von Google, ist unsere Implementierung eines unveränderlichen Merkle-Baums. Es ist das Rückgrat unseres CT-Logs und bietet kryptografische Garantien für die Integrität des Logs sowie effiziente Nachweise der Einbeziehung.

Architekturübersicht

Werfen wir einen Blick auf unsere Systemarchitektur:


+----------------+     +--------+     +----------+     +---------+
|  Internal CA   | --> | Kafka  | --> | Trillian | --> | Auditor |
+----------------+     +--------+     +----------+     +---------+
        |                                 |
        |                                 |
        v                                 v
+----------------+              +--------------------+
| Monitor/Alert  |              | Gossip Participants|
+----------------+              +--------------------+

1. Die interne CA übermittelt neu ausgestellte Zertifikate an Kafka.

2. Kafka sorgt für eine geordnete und zuverlässige Lieferung an Trillian.

3. Trillian fügt die Zertifikate seinem Merkle-Baum hinzu.

4. Auditoren können die Konsistenz des Logs überprüfen und verdächtige Zertifikate kontrollieren.

5. Überwachungssysteme alarmieren bei Anomalien.

6. Gossip-Teilnehmer stellen die Konsistenz des Logs über mehrere Instanzen hinweg sicher.

Implementierung des Systems

Schritt 1: Einrichtung von Kafka

Zuerst richten wir unseren Kafka-Cluster ein. Wir verwenden Docker zur Vereinfachung:


version: '3'
services:
  zookeeper:
    image: confluentinc/cp-zookeeper:latest
    environment:
      ZOOKEEPER_CLIENT_PORT: 2181
      ZOOKEEPER_TICK_TIME: 2000

  kafka:
    image: confluentinc/cp-kafka:latest
    depends_on:
      - zookeeper
    ports:
      - 9092:9092
    environment:
      KAFKA_BROKER_ID: 1
      KAFKA_ZOOKEEPER_CONNECT: zookeeper:2181
      KAFKA_ADVERTISED_LISTENERS: PLAINTEXT://kafka:29092,PLAINTEXT_HOST://localhost:9092
      KAFKA_LISTENER_SECURITY_PROTOCOL_MAP: PLAINTEXT:PLAINTEXT,PLAINTEXT_HOST:PLAINTEXT
      KAFKA_INTER_BROKER_LISTENER_NAME: PLAINTEXT
      KAFKA_OFFSETS_TOPIC_REPLICATION_FACTOR: 1

Führen Sie dies mit docker-compose up -d aus, und Sie haben einen Kafka-Cluster, der bereit ist, Zertifikate zu verarbeiten.

Schritt 2: Konfiguration von Trillian

Nun richten wir Trillian ein. Wir müssen es aus dem Quellcode kompilieren:


git clone https://github.com/google/trillian.git
cd trillian
go build ./cmd/trillian_log_server
go build ./cmd/trillian_log_signer

Erstellen Sie eine MySQL-Datenbank für Trillian:


CREATE DATABASE trillian;

Initialisieren Sie das Datenbankschema:


mysql -u root -p trillian < storage/mysql/schema/storage.sql

Starten Sie nun den Trillian-Log-Server und -Signer:


./trillian_log_server --logtostderr ...
./trillian_log_signer --logtostderr ...

Schritt 3: Implementierung des Zertifikatsübermittlers

Wir benötigen eine Komponente, um Zertifikate von unserer internen CA an Kafka zu übermitteln. Hier ist eine einfache Go-Implementierung:


package main

import (
	"context"
	"crypto/x509"
	"encoding/pem"
	"github.com/segmentio/kafka-go"
)

func submitCertificate(cert *x509.Certificate) error {
	w := kafka.NewWriter(kafka.WriterConfig{
		Brokers: []string{"localhost:9092"},
		Topic:   "ct-log-entries",
	})

	pemCert := pem.EncodeToMemory(&pem.Block{
		Type:  "CERTIFICATE",
		Bytes: cert.Raw,
	})

	return w.WriteMessages(context.Background(),
		kafka.Message{
			Key:   []byte(cert.SerialNumber.String()),
			Value: pemCert,
		},
	)
}

Schritt 4: Verarbeitung von Zertifikaten mit Trillian

Nun müssen wir Zertifikate von Kafka konsumieren und sie zu Trillian hinzufügen:


package main

import (
	"context"
	"github.com/google/trillian"
	"github.com/segmentio/kafka-go"
)

func processCertificates(logID int64) {
	r := kafka.NewReader(kafka.ReaderConfig{
		Brokers: []string{"localhost:9092"},
		Topic:   "ct-log-entries",
		GroupID: "trillian-processor",
	})

	client, err := trillian.NewTrillianLogClient(...)
	if err != nil {
		// Fehlerbehandlung
	}

	for {
		msg, err := r.ReadMessage(context.Background())
		if err != nil {
			// Fehlerbehandlung
			continue
		}

		leaf := &trillian.LogLeaf{
			LeafValue: msg.Value,
		}

		_, err = client.QueueLeaf(context.Background(), &trillian.QueueLeafRequest{
			LogId: logID,
			Leaf:  leaf,
		})
		if err != nil {
			// Fehlerbehandlung
		}
	}
}

Implementierung der konsistenzbasierten Überprüfung durch Gossip

Um die Konsistenz unseres CT-Logs über mehrere Instanzen hinweg sicherzustellen, implementieren wir ein Gossip-Protokoll. Dies ermöglicht es verschiedenen Log-Instanzen, ihre Ansichten des Logs zu vergleichen und Unstimmigkeiten zu erkennen.

Überblick über das Gossip-Protokoll

  1. Jede Log-Instanz sendet regelmäßig ihren neuesten Signierten Baumkopf (STH) an eine Reihe von Peers.
  2. Peers vergleichen den empfangenen STH mit ihrem eigenen.
  3. Wenn Unterschiede festgestellt werden, fordern Peers Konsistenznachweise an und überprüfen diese.
  4. Jede Unstimmigkeit löst Alarme zur weiteren Untersuchung aus.

Hier ist eine grundlegende Implementierung des Gossip-Protokolls:


package main

import (
	"context"
	"github.com/google/trillian"
	"github.com/google/trillian/client"
	"time"
)

type GossipParticipant struct {
	LogID     int64
	Client    trillian.TrillianLogClient
	Verifier  *client.LogVerifier
	Peers     []string
}

func (g *GossipParticipant) RunGossip() {
	ticker := time.NewTicker(5 * time.Minute)
	for range ticker.C {
		g.gossipRound()
	}
}

func (g *GossipParticipant) gossipRound() {
	ctx := context.Background()
	sth, err := g.Client.GetLatestSignedLogRoot(ctx, &trillian.GetLatestSignedLogRootRequest{LogId: g.LogID})
	if err != nil {
		// Fehlerbehandlung
		return
	}

	for _, peer := range g.Peers {
		peerSTH := getPeerSTH(peer) // Implementieren Sie diese Funktion, um STH von einem Peer zu erhalten
		if !g.Verifier.VerifyRoot(sth.SignedLogRoot, peerSTH.SignedLogRoot) {
			// STHs stimmen nicht überein, Konsistenznachweis anfordern
			proof, err := g.Client.GetConsistencyProof(ctx, &trillian.GetConsistencyProofRequest{
				LogId:          g.LogID,
				FirstTreeSize:  peerSTH.TreeSize,
				SecondTreeSize: sth.TreeSize,
			})
			if err != nil {
				// Fehlerbehandlung
				continue
			}

			// Überprüfen Sie den Konsistenznachweis
			if !g.Verifier.VerifyConsistencyProof(proof) {
				// Unstimmigkeit erkannt! Alarm auslösen
				raiseInconsistencyAlert(g.LogID, peer)
			}
		}
	}
}

func raiseInconsistencyAlert(logID int64, peer string) {
	// Implementieren Sie einen Alarmmechanismus (z.B. E-Mail senden, Vorfallreaktion auslösen)
}

Prüfung und Überwachung

Mit unserem CT-Log-System müssen wir Prüfungen und Überwachungen implementieren, um verdächtige Aktivitäten oder Unstimmigkeiten zu erkennen.

Implementierung eines Auditors

Die Aufgabe des Auditors besteht darin, das Log regelmäßig auf Zertifikate zu überprüfen, die gegen Richtlinien verstoßen oder verdächtig erscheinen. Hier ist eine grundlegende Implementierung:


package main

import (
	"context"
	"crypto/x509"
	"encoding/pem"
	"github.com/google/trillian"
	"time"
)

type Auditor struct {
	LogID  int64
	Client trillian.TrillianLogClient
}

func (a *Auditor) AuditLog() {
	ticker := time.NewTicker(1 * time Stunde)
	for range ticker.C {
		a.auditRound()
	}
}

func (a *Auditor) auditRound() {
	ctx := context.Background()
	leaves, err := a.Client.GetLeavesByRange(ctx, &trillian.GetLeavesByRangeRequest{
		LogId: a.LogID,
		StartIndex: 0,
		Count: 1000, // Anpassen nach Bedarf
	})
	if err != nil {
		// Fehlerbehandlung
		return
	}

	for _, leaf := range leaves.Leaves {
		block, _ := pem.Decode(leaf.LeafValue)
		if block == nil {
			// Fehlerbehandlung
			continue
		}

		cert, err := x509.ParseCertificate(block.Bytes)
		if err != nil {
			// Fehlerbehandlung
			continue
		}

		if isSuspiciousCertificate(cert) {
			raiseSuspiciousCertificateAlert(cert)
		}
	}
}

func isSuspiciousCertificate(cert *x509.Certificate) bool {
	// Implementieren Sie Prüfungen für verdächtige Zertifikate
	// Zum Beispiel:
	// - Unerwartete Aussteller
	// - Ungewöhnliche Gültigkeitszeiträume
	// - Verbotene Schlüsselverwendungen
	// - Unerwartete SANs
	return false
}

func raiseSuspiciousCertificateAlert(cert *x509.Certificate) {
	// Implementieren Sie einen Alarmmechanismus für verdächtige Zertifikate
}

Überwachung und Alarmierung

Um die Gesundheit und Leistung unseres CT-Log-Systems im Auge zu behalten, sollten wir eine umfassende Überwachung und Alarmierung implementieren. Hier sind einige wichtige Metriken, die verfolgt werden sollten:

  • Log-Größe und Wachstumsrate
  • Latenz bei der Zertifikatsübermittlung
  • Fehlerraten bei der Zertifikatsverarbeitung
  • Konsistenzprüfungen des Gossip-Protokolls
  • Ergebnisse und Alarme des Auditors

Sie können Tools wie Prometheus und Grafana verwenden, um diese Metriken zu sammeln und zu visualisieren. Hier ist ein Beispiel, wie man einige grundlegende Metriken mit der Prometheus-Client-Bibliothek für Go bereitstellt:


package main

import (
	"github.com/prometheus/client_golang/prometheus"
	"github.com/prometheus/client_golang/prometheus/promauto"
)

var (
	certificatesProcessed = promauto.NewCounter(prometheus.CounterOpts{
		Name: "ct_log_certificates_processed_total",
		Help: "Die Gesamtzahl der verarbeiteten Zertifikate",
	})

	processingLatency = promauto.NewHistogram(prometheus.HistogramOpts{
		Name: "ct_log_processing_latency_seconds",
		Help: "Die Latenz bei der Verarbeitung von Zertifikaten",
		Buckets: prometheus.DefBuckets,
	})

	gossipInconsistencies = promauto.NewCounter(prometheus.CounterOpts{
		Name: "ct_log_gossip_inconsistencies_total",
		Help: "Die Gesamtzahl der erkannten Gossip-Unstimmigkeiten",
	})
)

// Verwenden Sie diese Metriken in Ihrem Code:
// certificatesProcessed.Inc()
// processingLatency.Observe(duration.Seconds())
// gossipInconsistencies.Inc()

Fazit: Vertrauen, aber überprüfen (und protokollieren)

Die Implementierung eines Certificate Transparency Logs für Ihre interne PKI mag auf den ersten Blick übertrieben erscheinen. Aber in der Welt der Cybersicherheit, wo Vertrauen von größter Bedeutung ist und die Folgen eines Verstoßes katastrophal sein können, ist es ein kleiner Preis für Seelenfrieden.

Indem wir die Leistungsfähigkeit von Kafka für die hochdurchsatzstarke Nachrichtenverarbeitung und Trillian für kryptografische Integrität nutzen, haben wir ein robustes System geschaffen, das:

  • Unautorisierte oder falsch ausgestellte Zertifikate schnell erkennt
  • Einen unveränderlichen Prüfpfad aller Zertifikatsausstellungen bietet
  • Die Konsistenz über mehrere Log-Instanzen hinweg durch Gossip-Protokolle sicherstellt
  • Proaktive Überwachung und Alarmierung bei verdächtigen Aktivitäten ermöglicht

Denken Sie daran, im Bereich der PKI ist Vertrauen gut, aber Überprüfung ist besser. Durch die Implementierung dieses internen CT-Log-Systems verbessern Sie nicht nur Ihre Sicherheitslage; Sie bauen eine Grundlage des überprüfbaren Vertrauens auf, die der Prüfung von Audits und der Zeit standhalten kann.

"In God we trust. All others must bring data." - W. Edwards Deming

Nun gehen Sie voran und protokollieren Sie diese Zertifikate! Ihr zukünftiges Ich (und Ihre Auditoren) werden es Ihnen danken.

Weiterführende Literatur