# Moves the admin user off uid/gid 1000, which many container images use # (OpenSearch among them). Sharing it would let the admin user read, change # or delete the SIEM's data, and signal its processes, without sudo. # # Run it once, after the first Ansible run and BEFORE Kubernetes: usermod refuses # while any process runs as the uid, and container processes count. The playbook # never kills anything but the admin's own login sessions; if something else runs # as the uid, it stops and lists it. # # ansible-playbook move-admin-uid.yml -K --limit k8s-worker1 # one board first # ansible-playbook move-admin-uid.yml -K --limit k8s # then the rest # # usermod refuses to change a user that is logged in, and Ansible logs in as # that user. So a temporary user does the move, and is removed at the end. # sshd allows extra AllowUsers lines to add up, so a drop-in lets it in for the move. - name: 1. A temporary admin, with the same SSH key hosts: all become: true vars: admin_user: "{{ lookup('config', 'DEFAULT_REMOTE_USER') }}" tasks: - name: Temporary user ansible.builtin.user: name: uidmove shell: /bin/bash - name: Its .ssh folder ansible.builtin.file: path: /home/uidmove/.ssh state: directory owner: uidmove group: uidmove mode: "0700" - name: Its SSH key is the admin's ansible.builtin.copy: src: "/home/{{ admin_user }}/.ssh/authorized_keys" dest: /home/uidmove/.ssh/authorized_keys remote_src: true owner: uidmove group: uidmove mode: "0600" - name: Sudo without a password, for this user only, for the next few minutes ansible.builtin.copy: dest: /etc/sudoers.d/uidmove content: "uidmove ALL=(ALL) NOPASSWD: ALL\n" mode: "0440" validate: visudo -cf %s - name: Let it log in over SSH (the base role allows only the admin) ansible.builtin.copy: dest: /etc/ssh/sshd_config.d/05-uidmove.conf content: "AllowUsers uidmove\n" mode: "0644" - name: Check and reload sshd (open sessions stay up) ansible.builtin.shell: sshd -t && systemctl reload ssh changed_when: true - name: Close Ansible's kept-open connection as the admin ansible.builtin.meta: reset_connection - name: 2. Move the admin user, logged in as the temporary one hosts: all become: true remote_user: uidmove vars: admin_user: "{{ lookup('config', 'DEFAULT_REMOTE_USER') }}" new_id: 2000 tasks: - name: End the admin's login sessions (nothing else is killed) ansible.builtin.command: loginctl terminate-user {{ admin_user }} register: term changed_when: term.rc == 0 failed_when: false - name: Wait until no process runs as the admin ansible.builtin.command: pgrep -u {{ admin_user }} register: left until: left.rc == 1 retries: 15 delay: 2 changed_when: false failed_when: false - name: Stop if something other than a login still runs as the admin's uid ansible.builtin.shell: ps -o pid,user,args -u {{ admin_user }} register: who changed_when: false failed_when: true when: left.rc != 1 - name: New gid ansible.builtin.group: name: "{{ admin_user }}" gid: "{{ new_id }}" - name: New uid (usermod re-owns the home folder) ansible.builtin.user: name: "{{ admin_user }}" uid: "{{ new_id }}" group: "{{ admin_user }}" - name: Files in the home folder still in the old group ansible.builtin.command: find /home/{{ admin_user }} -xdev -gid 1000 -exec chgrp -h {{ admin_user }} {} + changed_when: false - name: Close Ansible's kept-open connection as the temporary user ansible.builtin.meta: reset_connection - name: 3. Back as the admin, remove the temporary user hosts: all become: true tasks: - name: No more passwordless sudo, and no SSH for the temporary user ansible.builtin.file: path: "{{ item }}" state: absent loop: - /etc/sudoers.d/uidmove - /etc/ssh/sshd_config.d/05-uidmove.conf - name: Check and reload sshd ansible.builtin.shell: sshd -t && systemctl reload ssh changed_when: true - name: Wait until no process runs as the temporary user ansible.builtin.command: pgrep -u uidmove register: left until: left.rc == 1 retries: 15 delay: 2 changed_when: false failed_when: left.rc != 1 - name: Remove the temporary user and its home ansible.builtin.user: name: uidmove state: absent remove: true - name: Show the result ansible.builtin.command: id become: false register: who changed_when: false - ansible.builtin.debug: msg: "{{ who.stdout }}"