Projektarbeit-MYP/backend/generate_ssl_cert.py

261 lines
9.9 KiB
Python

#!/usr/bin/env python
# -*- coding: utf-8 -*-
import os
import datetime
from cryptography import x509
from cryptography.x509.oid import NameOID
from cryptography.hazmat.primitives import hashes
from cryptography.hazmat.primitives.asymmetric import rsa
from cryptography.hazmat.primitives.serialization import Encoding, PrivateFormat, NoEncryption
import ipaddress
import argparse
def generate_ssl_certificate():
"""
Generiert ein verbessertes SSL-Zertifikat für die MYP-Anwendung
mit korrekten Metadaten und alternativen Namen.
"""
print("Generiere verbessertes SSL-Zertifikat für die MYP-Anwendung...")
# Verzeichnispfade definieren
ssl_dir = "app/instance/ssl"
ssl_cert_path = os.path.join(ssl_dir, "myp.crt")
ssl_key_path = os.path.join(ssl_dir, "myp.key")
# Verzeichnis erstellen, falls es nicht existiert
os.makedirs(ssl_dir, exist_ok=True)
try:
# Privaten Schlüssel mit 4096 Bit generieren (sicherer)
private_key = rsa.generate_private_key(
public_exponent=65537,
key_size=4096,
)
# Aktuelles Datum und Ablaufdatum (1 Jahr gültig)
now = datetime.datetime.now()
valid_until = now + datetime.timedelta(days=365)
# Liste aller möglichen Hostnamen/IPs
hostnames = [
"localhost",
"raspberrypi",
"m040tbaraspi001",
"m040tbaraspi001.de040.corpintra.net"
]
# IP-Adressen (als String, werden später konvertiert)
ip_addresses = [
"127.0.0.1",
"192.168.0.105"
]
# Erweiterte Zertifikatsattribute
subject = issuer = x509.Name([
x509.NameAttribute(NameOID.COMMON_NAME, "raspberrypi"),
x509.NameAttribute(NameOID.ORGANIZATION_NAME, "Mercedes-Benz AG"),
x509.NameAttribute(NameOID.ORGANIZATIONAL_UNIT_NAME, "Werk 040 Berlin"),
x509.NameAttribute(NameOID.COUNTRY_NAME, "DE"),
x509.NameAttribute(NameOID.STATE_OR_PROVINCE_NAME, "Berlin"),
x509.NameAttribute(NameOID.LOCALITY_NAME, "Berlin")
])
# Subject Alternative Names (SAN) erstellen
san_list = []
for hostname in hostnames:
san_list.append(x509.DNSName(hostname))
# IP-Adressen hinzufügen
for ip in ip_addresses:
san_list.append(x509.IPAddress(ipaddress.IPv4Address(ip)))
# Zertifikat erstellen
cert = x509.CertificateBuilder().subject_name(
subject
).issuer_name(
issuer
).public_key(
private_key.public_key()
).serial_number(
x509.random_serial_number()
).not_valid_before(
now
).not_valid_after(
valid_until
).add_extension(
x509.SubjectAlternativeName(san_list),
critical=False,
).add_extension(
x509.BasicConstraints(ca=True, path_length=None), critical=True
).add_extension(
x509.KeyUsage(
digital_signature=True,
content_commitment=False,
key_encipherment=True,
data_encipherment=False,
key_agreement=False,
key_cert_sign=True,
crl_sign=True,
encipher_only=False,
decipher_only=False
), critical=True
).add_extension(
x509.ExtendedKeyUsage([
x509.oid.ExtendedKeyUsageOID.SERVER_AUTH,
x509.oid.ExtendedKeyUsageOID.CLIENT_AUTH
]), critical=False
).sign(private_key, hashes.SHA256())
# Zertifikat und Schlüssel speichern
with open(ssl_key_path, "wb") as f:
f.write(private_key.private_bytes(
encoding=Encoding.PEM,
format=PrivateFormat.TraditionalOpenSSL,
encryption_algorithm=NoEncryption()
))
with open(ssl_cert_path, "wb") as f:
f.write(cert.public_bytes(Encoding.PEM))
# Kopieren des Zertifikats in das Frontend-Verzeichnis
frontend_ssl_dir = "../frontend/ssl"
os.makedirs(frontend_ssl_dir, exist_ok=True)
import shutil
shutil.copy2(ssl_cert_path, os.path.join(frontend_ssl_dir, "myp.crt"))
shutil.copy2(ssl_key_path, os.path.join(frontend_ssl_dir, "myp.key"))
print(f"SSL-Zertifikat wurde erstellt:")
print(f"- Zertifikat: {ssl_cert_path}")
print(f"- Schlüssel: {ssl_key_path}")
print(f"- Kopiert nach: {frontend_ssl_dir}")
print(f"- Gültig bis: {valid_until.strftime('%d.%m.%Y')}")
print(f"- Hostnamen: {', '.join(hostnames)}")
print(f"- IP-Adressen: {', '.join(ip_addresses)}")
return True
except Exception as e:
print(f"Fehler beim Erstellen des SSL-Zertifikats: {e}")
return False
def install_certificate_system():
"""
Installiert das Zertifikat im System-Zertifikatsspeicher (Windows).
Nur für Windows-Systeme.
"""
import platform
if platform.system() != "Windows":
print("Diese Funktion ist nur unter Windows verfügbar.")
return False
try:
import subprocess
import os
ssl_cert_path = os.path.abspath(os.path.join("app", "instance", "ssl", "myp.crt"))
# Prüfen, ob Datei existiert
if not os.path.exists(ssl_cert_path):
print(f"Zertifikat nicht gefunden unter: {ssl_cert_path}")
# Alternativen Pfad versuchen
alt_path = os.path.abspath(os.path.join("backend", "app", "instance", "ssl", "myp.crt"))
if os.path.exists(alt_path):
ssl_cert_path = alt_path
print(f"Verwende alternativen Pfad: {ssl_cert_path}")
else:
print("Zertifikat konnte nicht gefunden werden.")
return False
# Befehle zum Installieren des Zertifikats im Windows-Zertifikatsspeicher
commands = [
["certutil", "-addstore", "-f", "ROOT", ssl_cert_path],
["certutil", "-addstore", "-f", "CA", ssl_cert_path],
["certutil", "-addstore", "-f", "MY", ssl_cert_path]
]
for cmd in commands:
subprocess.run(cmd, check=True, capture_output=True)
print("Zertifikat wurde erfolgreich im System-Zertifikatsspeicher installiert.")
return True
except Exception as e:
print(f"Fehler bei der Installation des Zertifikats im System: {e}")
return False
def copy_to_raspberry():
"""
Kopiert das Zertifikat auf den Raspberry Pi.
Erfordert SSH-Zugriff auf den Raspberry Pi.
"""
try:
import subprocess
ssl_cert_path = os.path.abspath("app/instance/ssl/myp.crt")
ssl_key_path = os.path.abspath("app/instance/ssl/myp.key")
# Raspberry Pi-Zugangsdaten
raspberry_host = "raspberrypi"
raspberry_user = "pi"
raspberry_dest = "/home/pi/myp/ssl"
# Befehle zum Kopieren der Dateien auf den Raspberry Pi
scp_commands = [
["scp", ssl_cert_path, f"{raspberry_user}@{raspberry_host}:{raspberry_dest}/myp.crt"],
["scp", ssl_key_path, f"{raspberry_user}@{raspberry_host}:{raspberry_dest}/myp.key"]
]
# SSH-Befehl zum Erstellen des Verzeichnisses auf dem Raspberry Pi
ssh_command = ["ssh", f"{raspberry_user}@{raspberry_host}", f"mkdir -p {raspberry_dest}"]
# Verzeichnis auf dem Raspberry Pi erstellen
print(f"Erstelle Verzeichnis auf dem Raspberry Pi: {raspberry_dest}")
subprocess.run(ssh_command, check=True)
# Dateien kopieren
for cmd in scp_commands:
print(f"Kopiere {cmd[1]} nach {cmd[2]}")
subprocess.run(cmd, check=True)
print(f"Zertifikate wurden erfolgreich auf den Raspberry Pi kopiert nach {raspberry_dest}")
# Berechtigungen setzen
chmod_command = ["ssh", f"{raspberry_user}@{raspberry_host}", f"chmod 600 {raspberry_dest}/myp.key"]
subprocess.run(chmod_command, check=True)
# Zertifikat im System-Zertifikatsspeicher installieren
install_command = ["ssh", f"{raspberry_user}@{raspberry_host}", f"sudo cp {raspberry_dest}/myp.crt /usr/local/share/ca-certificates/ && sudo update-ca-certificates"]
subprocess.run(install_command, check=True)
print("Zertifikat wurde erfolgreich auf dem Raspberry Pi installiert und registriert.")
return True
except Exception as e:
print(f"Fehler beim Kopieren des Zertifikats auf den Raspberry Pi: {e}")
return False
if __name__ == "__main__":
print("=== MYP SSL-Zertifikatsgenerator ===")
# Kommandozeilenargumente parsen
parser = argparse.ArgumentParser(description='MYP SSL-Zertifikatsgenerator')
parser.add_argument('--no-install', action='store_true', help='Zertifikat nicht im System installieren')
parser.add_argument('--no-raspberry', action='store_true', help='Zertifikat nicht auf den Raspberry Pi kopieren')
parser.add_argument('--quiet', action='store_true', help='Keine Benutzerinteraktion')
args = parser.parse_args()
# Zertifikat generieren
cert_generated = generate_ssl_certificate()
if not cert_generated:
print("Generierung des Zertifikats fehlgeschlagen.")
exit(1)
# System-Installation des Zertifikats
if not args.no_install:
if args.quiet or input("Möchten Sie das Zertifikat im System-Zertifikatsspeicher installieren? (j/n): ").lower() == 'j':
install_certificate_system()
# Kopieren auf Raspberry Pi
if not args.no_raspberry:
if args.quiet or input("Möchten Sie das Zertifikat auf den Raspberry Pi kopieren? (j/n): ").lower() == 'j':
copy_to_raspberry()
print("Vorgang abgeschlossen.")