Zum Inhalt

Produktivbetrieb

Umstellen von cc-backend auf Produktivbetrieb

Verwendung von nginx

Anpassungen in der config.json: * "addr" wird auf einen Port > 1024 gesetzt, z.B. 8443. * Einträge für "https-cert-file" und "https-key-file" werden entfernt * "redirect-http-to" wir entfernt

nginx-config anlegen (z.B. /etc/nginx/sites-available/clustercockpit):

nginx-config anzeigen
server {
    listen 443 ssl;
    listen [::]:443 ssl;

    server_name __FQDN__;

    location = /robots.txt {
        default_type text/plain;
        return 200 "User-agent: *\nDisallow: /\n";
    }

    server_tokens off;
    autoindex off;

    ssl_certificate     /etc/ssl/__PEM_FILE__;
    ssl_certificate_key /etc/ssl/__KEY_FILE__;

    ssl_protocols       TLSv1.2 TLSv1.3;
    ssl_ciphers         HIGH:!aNULL:!MD5;

    add_header Strict-Transport-Security "max-age=31536000" always;
    add_header X-Content-Type-Options "nosniff" always;
    add_header Referrer-Policy "strict-origin-when-cross-origin" always;
    add_header X-Frame-Options "DENY" always;

    location / {
        limit_except GET POST HEAD {
            deny all;
        }

        proxy_pass         http://127.0.0.1:8443;
        proxy_set_header   Host $host;
        proxy_set_header   X-Real-IP $remote_addr;
        proxy_set_header   X-Forwarded-For $proxy_add_x_forwarded_for;
        proxy_set_header   X-Forwarded-Proto $scheme;
        proxy_read_timeout 90;
    }
}

server {
    listen 80;
    listen [::]:80;
    server_name __FQDN__;
    return 301 https://$host$request_uri;
}

Noch die Platzhalter für den FQDN und die SSL-Zertifikatsdateien ersetzen und aktivieren: ln -s /etc/nginx/sites-available/clustercockpit /etc/nginx/sites-enabled/. Mit dieser Konfig wird der Traffic von Port 80 auf Port 443 weitergeleitet und generell alle Anfragen an 8443 weitergereicht, sowohl für IPv4 als auch IPv6. Der systemd-Service sollte noch angepasst werden, damit die Weboberfläche erst gestartet wird, wenn nginx bereits gestartet ist: Requires=nginx.service

LDAP-Anbindung

Die Anbindung an LDAP ermöglicht es den Usern ihre eigenen Jobs zu sehen und sich mit ihren gewohnten Logindaten anzumelden. In der Regel wird dazu ein bind-user der IDM Abteilung benötigt. In der config.json von cc-backend sehen die Einträge dann z.B. so aus:

  "ldap": {
    "url": "ldaps://hpcldap.rrze.uni-erlangen.de",
    "user_base": "ou=people,ou=hpc,dc=rrze,dc=uni-erlangen,dc=de",
    "search_dn": "cn=hpcmonitoring,ou=roadm,ou=profile,ou=hpc,dc=rrze,dc=uni-erlangen,dc=de",
    "user_bind": "uid={username},ou=people,ou=hpc,dc=rrze,dc=uni-erlangen,dc=de",
    "user_filter": "(&(objectclass=posixAccount))",
    "sync_interval": "24h"
  },

In diesem Beispiel werden alle Einträge aus dem LDAP Verzeichnis alle 24 Stunden synchronisiert. Je nach Größe der Institution oder den Vorgaben des IDM (Rate-Limting) ist es sinnvoll eine LDAP-Gruppe nur mit den HPC-Usern anzulegen und nur diese Gruppe zu synchronisieren:

    "user_filter": "(&(objectclass=posixAccount)(memberOf=cn=hpc,ou=groups,dc=uni-erlangen,dc=de))",
    "syncUserOnLogin": true

"syncUserOnLogin" fügt User beim ersten Login zur lokalen Datenbank hinzu. Es wird dann kein "sync_interval" mehr benötigt.

Checkmk

Um die Ablaufzeit des jwt-Token mit Hilfe von checkmk überprüfen zu lassen, kann man ein python-Skript in /usr/lib/check_mk_agent/local/ hinterlegen (muss ausführbar sein):

#!/usr/bin/python3

import jwt
import time
import sys
import os

JWT_FILE = "/opt/monitoring/cc-backend/admin.jwt"

def critical(msg):
    print(f"3 jwt_token - {msg}")
    sys.exit(3)

try:
    if not os.path.exists(JWT_FILE):
        critical("JWT file not found")

    with open(JWT_FILE, 'r') as f:
        token = f.read().strip()

    try:
        payload = jwt.decode(token, options={"verify_signature": False})
    except jwt.DecodeError:
        critical("JWT decode error")
    except Exception as e:
        critical(f"JWT decoding failed: {type(e).__name__}")

    exp = payload.get("exp")
    if not exp:
        critical("exp field missing in JWT")

    now = int(time.time())
    seconds_left = exp - now
    days_left = seconds_left // 86400

    if seconds_left <= 0:
        print(f"2 jwt_token - JWT Token expired!")
        sys.exit(2)
    elif days_left < 30:
        print(f"1 jwt_token - JWT Token expires in {days_left} days")
        sys.exit(1)
    else:
        print(f"0 jwt_token - JWT Token is valid ({days_left} days left)")
        sys.exit(0)

except Exception as e:
    critical(f"Unexpected error: {type(e).__name__}")