[SOLVED] WebUI PAM Zugang Einschränken / WebUI restrict PAM (root) Login

NojuHD

Member
May 1, 2022
29
3
8
Hallo zusammen,

Ich möchte die WebUI über VPN für andere Erreichbar machen, damit diese Ihre VMs selbst verwalten können.

Nun hab ich mir die Frage gestellt, ob es denn möglich ist den Root Zugriff auf die WebUI nur in einem bestimmten Netzwerk zuzulassen?

Heimnetz: Root kann sich anmelden.
EXT Netz: Root kann sich nicht anmelden, sondern nur pve Accounts

Danke im Voraus.
 
Ich möchte die WebUI über VPN für andere Erreichbar machen, damit diese Ihre VMs selbst verwalten können.
Die API (welche ja die Web UI bedient) nur auf bestimmten Netzwerken verfügbar machen ist relativ einfach, siehe:
https://pve.proxmox.com/pve-docs/pve-admin-guide.html#_pvedaemon_proxmox_ve_api_daemon

Nun hab ich mir die Frage gestellt, ob es denn möglich ist den Root Zugriff auf die WebUI nur in einem bestimmten Netzwerk zuzulassen?
Nein, das ist nicht einfach möglich. Evtl. könnte man sich mit komplexeren fail2ban config o.ä. helfen, aber meiner Meinung nach ist es einfacher, und in der Praxis nicht wirklich weniger sicher, für den root@pam Account ein starkes, einzigartiges Password zu verwenden und Zweifaktor Authentifizierung (TFA) aufzusetzen.
 
Die API (welche ja die Web UI bedient) nur auf bestimmten Netzwerken verfügbar machen ist relativ einfach, siehe:
https://pve.proxmox.com/pve-docs/pve-admin-guide.html#_pvedaemon_proxmox_ve_api_daemon


Nein, das ist nicht einfach möglich. Evtl. könnte man sich mit komplexeren fail2ban config o.ä. helfen, aber meiner Meinung nach ist es einfacher, und in der Praxis nicht wirklich weniger sicher, für den root@pam Account ein starkes, einzigartiges Password zu verwenden und Zweifaktor Authentifizierung (TFA) aufzusetzen.

Hallo @t.lamprecht,

es ist jetzt etwas Zeit vergangen und ich wollte mich noch für die schnelle Hilfe bedanken.
Nun habe ich gestern in der Roadmap für PVE 8 gelesen, dass es nun möglich sein soll, den Zugang via pam_rhost einzuschränken. Wie setze ich dies am besten um?

Danke im Voraus.
 
Man kann dafür ein Script erstellen welches mit dem pam_exec plugin in ein Proxmox VE spezifischen PAM service config integriert wird.

Also, /usr/local/lib/pam/pve.sh mit dem folgenden Inhalt erstellen:

Bash:
#!/bin/bash

if [[ "$PAM_USER" != "root" ]]; then
    # only care about root user
    exit 0;
fi

logger "Testing PAM_RHOST ($PAM_RHOST) via $0"
case "$PAM_RHOST" in
    '127.0.0.1') exit 0 ;;
    '::ffff:127.0.0.1') exit 0 ;;
    # or whichever IPs you want to add
    '10.9.2.1') exit 0 ;;
    '::ffff:10.9.2.1') exit 0 ;;
    *)
        logger "Rejecting unknown PAM_RHOST ($PAM_RHOST) via $0"
        exit 1
        ;;
esac

Und mit chmod +x /usr/local/lib/pam/pve.sh ausführbar machen.

Dafür kann man natürlich auch perl/python/... verwenden, wäre sogar empfehlenswert, bash ist ja Teilweise etwas haarig.

Dann /etc/pam.d/proxmox-ve-auth mit dem Folgenden Inhalt erstellen:

Code:
auth [success=ok default=bad] pam_exec.so /usr/local/lib/pam/pve.sh

@include common-auth
account required pam_nologin.so
@include common-account

Damit wir zuerst das Script aufgerufen, wenn das mit OK (exit-code 0) endet, werden die restlichen PAM module verwendet um password etc. zu prüfen, wenn das Script sich aber mit exit-code 1 (nicht OK) beendet, bricht PAM an der stelle ab (wegen default=bad).

Das kann man auch so für PMG (proxmox-mailgateway-auth) und PBS (proxmox-backup-auth) konfigurieren, man muss nur den PAM Config Filename anpassen.
 
Last edited:
  • Like
Reactions: NojuHD and fluxX04
Hallo @t.lamprecht,

nochmals danke für die schnelle Hilfe, es hat wie beschrieben funktioniert, nach beheben von 2 kleinen Fehlern im Bash Skript ;)

Ich habe nun ein Python Skript erstellt, welches die Funktion des Bash Skripts etwas erweitert. (Ich bin nicht wirklich erfahren was Programmierung an geht)

unter /etc/proxmox-ve-auth.conf kann man eine Datei mit den beschränkten Benutzern und den erlaubten IPs ablegen, die Datei kann wie folgt aussehen:

Code:
root 127.0.0.1,192.168.0.0/24
user 127.0.0.1

/etc/pam.d/proxmox-ve-auth sieht wie folgt aus:

Code:
auth [success=ok default=bad] pam_exec.so /bin/python3 /usr/local/lib/pam/pve.py

@include common-auth
account required pam_nologin.so
@include common-account

Das Python Skript sieht wie folgt aus:


Python:
import sys
import os
import ipaddress

config_path = '/etc/proxmox-ve-auth.conf'

def ipisinlist(host, ip):
    if '/' in ip:
        if host in ipaddress.ip_network(ip, strict=False):
            return True
        else:
            return False
    else:
        if host == ipaddress.ip_address(ip):
            return True
        else:
            return False

acl = {}
with open(config_path, 'r') as config_file:
    for line in config_file:
        parts = line.strip().split()
        if len(parts) >= 2:
            username = parts[0]
            ip_list = parts[1].split(',')
            acl[username] = ip_list

PAM_USER = os.environ.get('PAM_USER')
PAM_RHOST = os.environ.get('PAM_RHOST')

# Check if PAM_USER is Restricted
if PAM_USER in acl:
    for ip in acl[PAM_USER]:
        try:
            PAM_RHOST = ipaddress.ip_address(PAM_RHOST)
            if PAM_RHOST.version == 6 and PAM_RHOST.ipv4_mapped:
                if ipisinlist(PAM_RHOST.ipv4_mapped, ip):
                    sys.exit(0)
            else:
                if ipisinlist(PAM_RHOST, ip):
                    sys.exit(0)
        except ValueError:
            logger_message = f"Invalid RAM_RHOST address: ({PAM_RHOST}) via {sys.argv[0]})"
    logger_message = f"Rejecting unknown PAM_RHOST ({PAM_RHOST}) via {sys.argv[0]})"
else:
    sys.exit(0)
sys.exit(1)

FYI:
Das Skript übersetzt in PAM_RHOST enthaltene IPv4-mapped Adressen in normale IPv4 Adressen. Z.B.: ::ffff:192.168.0.1 -> 192.168.0.1 damit bekommt der Host auch Zugriff wenn nur der IPv4 Adressbereich in /etc/proxmox-ve-auth.conf freigegeben ist.
 
Last edited:
nach beheben von 2 kleinen Fehlern im Bash Skript
Hab nur einen gefunden (} statt fi in der if-Bedingung, blödes "muscle memory" ;) ) und auch editiert, was war der Zweite?

Ich habe nun ein Python Skript erstellt, welches die Funktion des Bash Skripts etwas erweitert. (Ich bin nicht wirklich erfahren was Programmierung an geht)
Nice, und danke fürs Teilen!

Was mir auffällt, dein logging scheint verkehrt herum zu sein, bei exit 0 wird ja akzeptiert, nicht "rejected".
Kein verhaltens bug, aber kann wohl verwirrend sein. IPv4-inIPv6 handlet deine regex wohl halbwegs richtig, aber geht sicher auch bissl schöner, sonst sehe ich nur paar stilistische Sachen, aber da ist vieles auch einfach Persönliche Geschmackssache.

Hab dann auch noch was in Perl geschrieben, das behandelt auch IPv4-mapped-in-IPv6 Addressen, ist etwa für den Proxmox Backup Server relevant, aber für neuere Proxmox VE und Proxmox Mail Gateway haben wir die LISTEN_IP auch auf "any" umgestellt, und da kann man dann hier auch IPv4 als IPv6 erhalten. Sowas würde bei deinem Script die Regex wohl auch unnötig machen.

Das Perl script, mit statischer Config nur für root (erweitern auf per-user config, und/oder auslesen aus File wie du's hast wäre nicht eine allzu große Änderung):
Perl:
#!/usr/bin/perl

use strict;
use warnings;

use Net::IP qw($IP_B_IN_A_OVERLAP $IP_IDENTICAL);

# Define the list of allowed CIDRs
my @allowed_cidrs = (
    '127.0.0.0/8',        # IPv4 loopback
    '::1/128',            # IPv6 loopback
    'fe80::/10',          # IPv6 link-local addresses
    '10.0.0.0/8',         # LAN
    '172.16.0.0/12',      # LAN
    '192.168.0.0/16',     # LAN
    # ...
);

my $user = $ENV{'PAM_USER'} or die "PAM_USER not defined\n";
my $rhost = $ENV{'PAM_RHOST'} or die "PAM_RHOST not defined\n";

# only check the all-powerfull user, ignore all others
exit(0) if $user ne 'root';

if (my $embedded_ipv4 = Net::IP::ip_get_embedded_ipv4($rhost)) {
    $rhost = $embedded_ipv4; # normalize IPv4-mapped-in-IPv6 first
}

my $request_ip = Net::IP->new($rhost) or die "invalid IP address '$rhost' in PAM_RHOST\n";

for my $ip_range (map { Net::IP->new($_) } @allowed_cidrs) {
    my $overlap = $ip_range->overlaps($request_ip);
    next if !defined($overlap);

    if ($overlap == $IP_B_IN_A_OVERLAP || $overlap == $IP_IDENTICAL) {
        `logger "allowing login request for user '$user' from '$rhost' to proceed"`; # uncomment for debugging
        exit(0); # OK
    }
}

`logger "rejecting login for user '$user' from '$rhost' early"`;
exit(1); # no configured CIDR matched the IP, exit with failure

An jeden der sowas ausrollt: Es empfiehlt sich das nicht über die Shell im PVE/PBS/PMG web-interface zu konfigurieren, sondern lieber über SSH o.ä., und dann auch testen, sonst kann man sich auch mal leicht selbst aussperren.
 
  • Like
Reactions: NojuHD
Hab nur einen gefunden (} statt fi in der if-Bedingung, blödes "muscle memory" ;) ) und auch editiert, was war der Zweite?

Entschuldige es war natürlich nur der eine Fehler.

Rest war ein Layer 8 Problemchen :)
Ich hab das Skript beim manuellen Ausführen per sh und nicht per bash aufgerufen und der mag die double Brackets nicht.

Was mir auffällt, dein logging scheint verkehrt herum zu sein, bei exit 0 wird ja akzeptiert, nicht "rejected".
Kein verhaltens bug, aber kann wohl verwirrend sein. IPv4-inIPv6 handlet deine regex wohl halbwegs richtig, aber geht sicher auch bissl schöner, sonst sehe ich nur paar stilistische Sachen, aber da ist vieles auch einfach Persönliche Geschmackssache.

Das logging werde ich natürlich gleich anpassen, da war ich wohl zu müde um mein eigenes Skript noch zu verstehen :)

Was den Stil angeht bin ich mir sicher, dass es in jedem Fall besser geht.
Ist nur mein erstes Skript in Python, zudem wollte ich erst noch in die Programmierung einsteigen, daher habe ich quasi noch NULL Erfahrung.

Also fühlt euch frei das Skript von neu auf umzugestalten geschweige den neu zu erstellen, wenn es nicht sogar einfacher ist das Perl Skript zu verwenden :D
 
Last edited:

About

The Proxmox community has been around for many years and offers help and support for Proxmox VE, Proxmox Backup Server, and Proxmox Mail Gateway.
We think our community is one of the best thanks to people like you!

Get your subscription!

The Proxmox team works very hard to make sure you are running the best software and getting stable updates and security enhancements, as well as quick enterprise support. Tens of thousands of happy customers have a Proxmox subscription. Get yours easily in our online shop.

Buy now!