From e6baefdbd59b1454c65329c303d0db8a2336e6c1 Mon Sep 17 00:00:00 2001 From: Thomas von Dein Date: Mon, 16 Dec 2024 14:23:45 +0100 Subject: [PATCH] enhanced user management --- TODO.md | 13 ++ group_vars/all/all.yaml | 9 ++ roles/chat/templates/Bastillefile.j2 | 5 +- roles/pub/bin/group.sh | 57 +++++--- roles/pub/bin/user.sh | 200 +++++++++++++++------------ roles/pub/tasks/main.yaml | 4 +- 6 files changed, 172 insertions(+), 116 deletions(-) diff --git a/TODO.md b/TODO.md index fa912ae..bb8a71c 100644 --- a/TODO.md +++ b/TODO.md @@ -14,3 +14,16 @@ test the current setup: does it get configured and how does it limit users? also check if new users belong to login class "jail" and test their limits +## devzat file busy still failing + +https://github.com/BastilleBSD/bastille/issues/772 + +## ZFS quota + +zfs set groupquota@bsdnixer=10MB zhcloud/home + +zfs get groupquota@bsdnixer zhcloud/home + +zfs groupspace zhcloud/home +zfs userspace zhcloud/home + diff --git a/group_vars/all/all.yaml b/group_vars/all/all.yaml index e6c57b5..1612bf8 100644 --- a/group_vars/all/all.yaml +++ b/group_vars/all/all.yaml @@ -62,12 +62,21 @@ defaults: jailbase: /usr/local/bastille/jails jailgroups: + - name: first + state: present + id: 4000 - name: bsdnixer state: present jailusers: + - name: first + state: present + id: 4000 - name: scip state: present + - name: tuud + group: wheel + state: present - name: tom state: present diff --git a/roles/chat/templates/Bastillefile.j2 b/roles/chat/templates/Bastillefile.j2 index 748904b..c7a5091 100644 --- a/roles/chat/templates/Bastillefile.j2 +++ b/roles/chat/templates/Bastillefile.j2 @@ -1,17 +1,18 @@ SERVICE devzat stop -CP usr / - SYSRC sendmail_enable=NONE SYSRC tmpsize=500m SYSRC tmpmfs=AUTO SYSRC clear_tmp_enable=YES SYSRC devzat_enable=YES + CMD if test -L /home; then rm /home; fi CMD mkdir -p /home FSTAB /home home nullfs rw 0 0 CMD install -d -o nobody -m 700 /home/devzat +CP usr / + SERVICE devzat start diff --git a/roles/pub/bin/group.sh b/roles/pub/bin/group.sh index a88903d..5925f34 100755 --- a/roles/pub/bin/group.sh +++ b/roles/pub/bin/group.sh @@ -2,6 +2,7 @@ rootdir="" group="" +id="" action="" usage() { @@ -16,7 +17,7 @@ run() { } OPTIND=1 -while getopts d:g:a: opt ; do +while getopts d:g:a:i: opt ; do case $opt in d) rootdir="$OPTARG" @@ -24,6 +25,9 @@ while getopts d:g:a: opt ; do g) group="$OPTARG" ;; + i) + id="$OPTARG" + ;; a) action="$OPTARG" ;; @@ -39,28 +43,35 @@ if test -z "$group" -o -z "$action"; then usage fi -root="" +# we do it once for $rootdir and once on the host to have synchronous groups +for root in "$rootdir" ""; do + args="" -if test -n "$rootdir"; then - root="-R $rootdir" -fi + if test -n "$root"; then + root="-R $root" + fi -case "$action" in - present) - if pw $root group show "$group" > /dev/null 2>&1; then - if pw $root group show "$group" | grep -q LOCKED; then - echo "$group exists." + if test -n "$id"; then + args="-g $id" + fi + + case "$action" in + present) + if pw $root group show "$group" > /dev/null 2>&1; then + if pw $root group show "$group" | grep -q LOCKED; then + echo "$group exists." + fi + else + run pw $root group add "$group" $args fi - else - run pw $root group add "$group" - fi - ;; - absent) - if pw $root group show "$group" > /dev/null 2>&1; then - run pw $root group del "$group" - fi - ;; - *) - usage - ;; -esac + ;; + absent) + if pw $root group show "$group" > /dev/null 2>&1; then + run pw $root group del "$group" + fi + ;; + *) + usage + ;; + esac +done diff --git a/roles/pub/bin/user.sh b/roles/pub/bin/user.sh index 4c37f9c..45018c4 100755 --- a/roles/pub/bin/user.sh +++ b/roles/pub/bin/user.sh @@ -11,6 +11,7 @@ shell="/usr/local/bin/bash" comment="" loginclass="jail" action="" +id="" usage() { echo "Usage: $0 -u user [-h home] [-s shell] [-g groups] [-d rootdir] [-c comment] -a action" @@ -20,7 +21,7 @@ usage() { getuid() { # resolve jail uid - + root="$1" user="$2" pw $root show user "$user" -7 | cut -d: -f 3 @@ -28,14 +29,14 @@ getuid() { run() { # verbose exec - + echo "$@" "$@" } # parse commandline flags OPTIND=1 -while getopts d:u:h:g:s:c:a: opt ; do +while getopts d:u:h:g:s:c:a:i: opt ; do case $opt in d) rootdir="$OPTARG" @@ -43,6 +44,9 @@ while getopts d:u:h:g:s:c:a: opt ; do u) user="$OPTARG" ;; + i) + id="$OPTARG" + ;; h) home="$OPTARG" ;; @@ -70,99 +74,117 @@ if test -z "$user" -o -z "$action"; then usage fi -# setup pw flags -args="" -root="" +# we do it once for $rootdir and once on the host to have synchronous +# users, however, host users will be locked, unless they are in group +# wheel +for root in "$rootdir" ""; do + # setup pw flags + args="" + skel="" -if test -n "$rootdir"; then - root="-R $rootdir" -fi -if test -n "$groups"; then - args="-G $groups" -fi - -if test -n "$home"; then - args="$args -d $home -k /etc/skel -m -M 700" -else - args="$args -d /home/$user -k /etc/skel -m -M 700" -fi - -if test -n "$shell"; then - args="$args -s $shell" -else - args="$args -s /usr/local/bin/bash" -fi - -if test -n "$comment"; then - args="$args -c $comment" -fi - -if test -n "$loginclass"; then - args="$args -L $loginclass" -fi - -# the horse shall work -case "$action" in - present) - if pw $root user show "$user" > /dev/null 2>&1; then - if pw $root user show "$user" | grep -q LOCKED; then - # user is present but locked - run pw unlock "$user" - else - echo "$user exists." - fi - else - # create user - run pw $root user add "$user" $args + if test -n "$root"; then + root="-R $root" + if test -d "$root/etc/skel"; then + skel="-k /etc/skel" fi + fi - if test -e "/usr/local/bastille/keys/$user" -a ! -e "/home/$user/.ssh/authorized_keys"; then - # install ssh key - uid=$(getuid "$root" "$user") - run install -m 700 -o "$uid" -g "$uid" -d "/home/$user/.ssh" - run install -m 600 -o "$uid" -g "$uid" "/usr/local/bastille/keys/$user" "/home/$user/.ssh/authorized_keys" + if test -n "$groups"; then + args="-G $groups" + fi - # generate chat key, which is required so login to - # kobayashi, so that ssh-chat works even if the user does - # not have their own key yet. - run ssh-keygen -t ed25519 -f /home/$user/.ssh/id_chat_kobayashi -P "" + if test -n "$home"; then + args="$args -d $home $skel -m -M 700" + else + args="$args -d /home/$user $skel -m -M 700" + fi - ( - echo "The key id_chat_kobayashi exists so that you're able to reach" - echo "the kobayashi chat service. Once you have generated your own" - echo "key, you can just delete it." - ) > "/home/$user/.ssh/README" + if test -n "$shell"; then + args="$args -s $shell" + else + args="$args -s /usr/local/bin/bash" + fi + + if test -n "$comment"; then + args="$args -c $comment" + fi + + if test -n "$loginclass"; then + args="$args -L $loginclass" + fi + + if test -n "$id"; then + args="$args -u $id" + fi + + # the horse shall work + case "$action" in + present) + if pw $root user show "$user" > /dev/null 2>&1; then + if pw $root user show "$user" | grep -q LOCKED; then + # user is present but locked + run pw $root unlock "$user" + else + echo "$user exists." + fi + else + # create user + run pw $root user add "$user" $args + + # if we're running on host and the user is a regular jail user, lock them + if test -z "$root" -a "$groups" != "wheel"; then + run pw lock "$user" + fi + fi + + if test -e "/usr/local/bastille/keys/$user" -a ! -e "/home/$user/.ssh/authorized_keys"; then + # install ssh key + uid=$(getuid "$root" "$user") + run install -m 700 -o "$uid" -g "$uid" -d "/home/$user/.ssh" + run install -m 600 -o "$uid" -g "$uid" "/usr/local/bastille/keys/$user" "/home/$user/.ssh/authorized_keys" + + # generate chat key, which is required so login to + # kobayashi, so that ssh-chat works even if the user does + # not have their own key yet. + run ssh-keygen -t ed25519 -f /home/$user/.ssh/id_chat_kobayashi -P "" - if test ! -e "/home/$user/.ssh/config"; then ( - echo "Host kobayashi" - echo " Port 2222" - echo " IdentityFile ~/.ssh/id_chat_kobayashi" - echo " StrictHostKeyChecking no" - ) > "/home/$user/.ssh/config" + echo "The key id_chat_kobayashi exists so that you're able to reach" + echo "the kobayashi chat service. Once you have generated your own" + echo "key, you can just delete it." + ) > "/home/$user/.ssh/README" + + if test ! -e "/home/$user/.ssh/config"; then + ( + echo "Host kobayashi" + echo " Port 2222" + echo " IdentityFile ~/.ssh/id_chat_kobayashi" + echo " StrictHostKeyChecking no" + ) > "/home/$user/.ssh/config" + fi + + run chown "$uid:$uid" /home/$user/.ssh/* fi - - run chown "$uid:$uid" /home/$user/.ssh/* - fi - ;; - absent) - if pw $root user show "$user" > /dev/null 2>&1; then - # get rid - run pw $root user del "$user" - fi - ;; - locked) - if pw $root user show "$user" > /dev/null 2>&1; then - if pw $root user show "$user" | grep -q LOCKED; then - echo "$user is already locked." - else - # lock'em out - run pw lock "$user" + ;; + absent) + if pw $root user show "$user" > /dev/null 2>&1; then + # get rid + run pw $root user del "$user" fi - fi - ;; - *) - usage - ;; -esac + ;; + locked) + if pw $root user show "$user" > /dev/null 2>&1; then + if pw $root user show "$user" | grep -q LOCKED; then + echo "$user is already locked." + else + # lock'em out + run pw $root lock "$user" + fi + fi + ;; + *) + usage + ;; + esac +done diff --git a/roles/pub/tasks/main.yaml b/roles/pub/tasks/main.yaml index 8b8c6b8..dd65090 100644 --- a/roles/pub/tasks/main.yaml +++ b/roles/pub/tasks/main.yaml @@ -97,7 +97,7 @@ # create our own group[s] - name: Manage groups loop: "{{ jailgroups }}" - ansible.builtin.script: "bin/group.sh -g {{ item.name }} -a {{ item.state }} -d /usr/local/bastille/jails/{{ role_name }}/root" + ansible.builtin.script: "bin/group.sh -g {{ item.name }} -a {{ item.state }} -i '{{ item.id | default(None) }}' -d /usr/local/bastille/jails/{{ role_name }}/root" # The normal ansible user module can't be used here, because we're # talking about jail users here. I tried to patch the module to @@ -109,7 +109,7 @@ # well. - name: Manage users loop: "{{ jailusers }}" - ansible.builtin.script: "bin/user.sh -u {{ item.name }} -g '{{ item.groups | default(defaults.group) }}' -c {{ role_name }}-user -a {{ item.state }} -d {{ defaults.jailbase }}/{{ role_name }}/root" + ansible.builtin.script: "bin/user.sh -u {{ item.name }} -g '{{ item.groups | default(defaults.group) }}' -c {{ role_name }}-user -a {{ item.state }} -i '{{ item.id | default(None) }}' -d {{ defaults.jailbase }}/{{ role_name }}/root" - name: add dns entry for jail host community.dns.hetzner_dns_record: