diff --git a/dev/host_vars/vps.yml b/dev/host_vars/vps.yml new file mode 100644 index 0000000..8deb737 --- /dev/null +++ b/dev/host_vars/vps.yml @@ -0,0 +1,68 @@ +############## +#### base #### +############## +base_allow_reboot: true +base_manage_network: false + +selinux: + state: enforcing + permissive_domains: + # logind drops its D-Bus connection under enforcing on trixie and never + # reconnects; pidfs/refpolicy gap. https://trello.com/c/x49s4EdL + - systemd_logind_t + +users: + git: + uid: 1001 + gid: 1001 + home: true + system: true + +root_gpgkeys: + - name: kris@lamoureux.io + id: 42A3A92C5DA0F3E5F71A3710105B748C1362EB96 + +############### +#### proxy #### +############### +base_domain: local.krislamo.org + +proxy: + servers: + - domain: "git.{{ base_domain }}" + proxy_pass: "http://127.0.0.1:3000" + +################ +#### podman #### +################ +podman_compose: + git: + root: /opt/oci + trusted_keys: + - id: 42A3A92C5DA0F3E5F71A3710105B748C1362EB96 + compose: + - name: gitea + url: https://github.com/krislamo/gitea + version: 84e5880484e803fdcf53c7f70b699988d28021d0 + enabled: true + env: + DATA: "{{ gitea_data }}" + SSH_DIR: "{{ gitea_data }}/git/.ssh" + USER_UID: "{{ gitea_uid }}" + USER_GID: "{{ gitea_uid }}" + SE_LEVEL: "{{ gitea_se_level }}" + DOMAIN: "git.{{ base_domain }}" + PROXY_TRUSTED_PROXIES: "{{ gitea_trusted_proxies }}" + DB_HOST: "{{ gitea.DB_HOST }}" + DB_NAME: "{{ gitea.DB_NAME }}" + DB_USER: "{{ gitea.DB_USER }}" + DB_PASSWD: "{{ gitea.DB_PASSWD }}" + +############### +#### gitea #### +############### +gitea: + DB_HOST: host.containers.internal + DB_NAME: gitea + DB_USER: gitea + DB_PASSWD: password diff --git a/dev/vps.yml b/dev/vps.yml new file mode 100644 index 0000000..47fce69 --- /dev/null +++ b/dev/vps.yml @@ -0,0 +1,11 @@ +- name: Install VPS Server + hosts: all + become: true + vars_files: + - host_vars/vps.yml + roles: + - base + - proxy + - mariadb + - podman + - gitea diff --git a/roles/base/tasks/firewall.yml b/roles/base/tasks/firewall.yml index 5d86b22..f299daf 100644 --- a/roles/base/tasks/firewall.yml +++ b/roles/base/tasks/firewall.yml @@ -8,6 +8,17 @@ name: fail2ban state: present +- name: Ensure Fail2ban's log file is correctly labelled + ansible.builtin.file: + path: /var/log/fail2ban.log + state: touch + mode: "0640" + access_time: preserve + modification_time: preserve + setype: fail2ban_log_t + when: selinux is defined and selinux is not false + notify: restart_fail2ban + - name: Deny incoming traffic by default community.general.ufw: default: deny diff --git a/roles/base/tasks/system.yml b/roles/base/tasks/system.yml index cbc4afe..28b219b 100644 --- a/roles/base/tasks/system.yml +++ b/roles/base/tasks/system.yml @@ -16,6 +16,13 @@ policy: "{{ selinux.policy | default('default') }}" when: selinux is defined and selinux is not false +- name: Set SELinux permissive domains + community.general.selinux_permissive: + domain: "{{ item }}" + permissive: true + loop: "{{ selinux.permissive_domains | default([]) }}" + when: selinux is defined and selinux is not false + - name: Check for GRUB ansible.builtin.stat: path: /etc/default/grub @@ -100,7 +107,7 @@ community.crypto.openssh_keypair: path: "{{ base_scripts }}/.keys/id_ed25519" type: ed25519 - comment: "{{ ansible_hostname }}-deploy-key" + comment: "{{ ansible_facts['hostname'] }}-deploy-key" mode: "400" state: present when: scripts is defined diff --git a/roles/base/templates/smb.conf.j2 b/roles/base/templates/smb.conf.j2 index a38cbb3..947f053 100644 --- a/roles/base/templates/smb.conf.j2 +++ b/roles/base/templates/smb.conf.j2 @@ -1,7 +1,7 @@ [global] workgroup = WORKGROUP server string = Samba Server %v - netbios name = {{ ansible_hostname }} + netbios name = {{ ansible_facts['hostname'] }} security = user map to guest = bad user dns proxy = no diff --git a/roles/base/templates/wireguard.j2 b/roles/base/templates/wireguard.j2 index 7a7b861..5453c47 100644 --- a/roles/base/templates/wireguard.j2 +++ b/roles/base/templates/wireguard.j2 @@ -1,6 +1,6 @@ # {{ ansible_managed }} -[Interface] # {{ ansible_hostname }} +[Interface] # {{ ansible_facts['hostname'] }} PrivateKey = {{ wgkey['content'] | b64decode | trim }} Address = {{ wireguard.address }} {% if wireguard.listenport is defined %} diff --git a/roles/docker/tasks/main.yml b/roles/docker/tasks/main.yml index 8f6e85d..132bdf4 100644 --- a/roles/docker/tasks/main.yml +++ b/roles/docker/tasks/main.yml @@ -77,7 +77,7 @@ community.crypto.openssh_keypair: path: "{{ docker_repos_keys }}/id_{{ docker_repos_keytype }}" type: "{{ docker_repos_keytype }}" - comment: "{{ ansible_hostname }}-deploy-key" + comment: "{{ ansible_facts['hostname'] }}-deploy-key" mode: "400" state: present when: docker_compose_deploy is defined diff --git a/roles/gitea/defaults/main.yml b/roles/gitea/defaults/main.yml index c797d5e..cad90a8 100644 --- a/roles/gitea/defaults/main.yml +++ b/roles/gitea/defaults/main.yml @@ -1,6 +1,6 @@ # container settings gitea_name: gitea -gitea_sshport: "222" +gitea_sshport: "2222" gitea_webport: "3000" gitea_ssh: "127.0.0.1:{{ gitea_sshport }}" gitea_web: "127.0.0.1:{{ gitea_webport }}" @@ -16,7 +16,12 @@ gitea_dbuser: "{{ gitea_name }}" # proxy settings gitea_proxy_limit: "1" -gitea_trusted_proxies: "172.16.0.0/12" +gitea_trusted_proxies: "10.89.0.0/16" # host -gitea_root: "{{ docker_compose_root }}/{{ gitea_name }}" +gitea_root: "{{ podman_compose.git.root }}/{{ gitea_name }}" +gitea_logs: "{{ podman_log_root }}/{{ gitea_name }}" +gitea_data: /srv/gitea +gitea_se_level: "s0:c22,c222" +gitea_uid: 1000 +gitea_oci_uid: "{{ podman_subuid_base['git'] | int + gitea_uid | int - 1 }}" diff --git a/roles/gitea/files/gitea_ssh.te b/roles/gitea/files/gitea_ssh.te new file mode 100644 index 0000000..4ceb755 --- /dev/null +++ b/roles/gitea/files/gitea_ssh.te @@ -0,0 +1,9 @@ +module gitea_ssh 1.0; + +require { + type sshd_t; + type ssh_exec_t; + class file { getattr read open map execute execute_no_trans }; +} + +allow sshd_t ssh_exec_t:file { getattr read open map execute execute_no_trans }; diff --git a/roles/gitea/handlers/main.yml b/roles/gitea/handlers/main.yml index f36f530..e7dd291 100644 --- a/roles/gitea/handlers/main.yml +++ b/roles/gitea/handlers/main.yml @@ -1,5 +1,5 @@ -- name: Restart Gitea - ansible.builtin.service: - name: "{{ docker_compose_service }}@{{ gitea_name }}" - state: restarted - listen: restart_gitea +- name: Reload ssh + ansible.builtin.systemd_service: + name: ssh + state: reloaded + listen: restart_ssh diff --git a/roles/gitea/tasks/main.yml b/roles/gitea/tasks/main.yml index 8d2db15..9e09240 100644 --- a/roles/gitea/tasks/main.yml +++ b/roles/gitea/tasks/main.yml @@ -13,7 +13,7 @@ community.mysql.mysql_user: name: "{{ gitea.DB_USER }}" password: "{{ gitea.DB_PASSWD }}" - host: '%' + host: "%" state: present priv: "{{ gitea.DB_NAME }}.*:ALL" login_unix_socket: /var/run/mysqld/mysqld.sock @@ -21,35 +21,36 @@ - name: Create git's .ssh directory ansible.builtin.file: path: /home/git/.ssh + owner: git + group: git mode: "700" state: directory + setype: >- + {{ (selinux is defined and selinux is not false) + | ternary('ssh_home_t', omit) }} - name: Generate git's SSH keys community.crypto.openssh_keypair: path: /home/git/.ssh/id_rsa + owner: git + group: git + mode: "600" + register: gitea_keypair + +- name: Label git's SSH keys for sshd access + ansible.builtin.file: + path: "/home/git/.ssh/{{ item }}" + setype: >- + {{ (selinux is defined and selinux is not false) + | ternary('ssh_home_t', omit) }} + loop: + - id_rsa + - id_rsa.pub - name: Find git's public SSH key ansible.builtin.slurp: src: /home/git/.ssh/id_rsa.pub - register: git_rsapub - -- name: Get stats on git's authorized_keys file - ansible.builtin.stat: - path: /home/git/.ssh/authorized_keys - register: git_authkeys - -- name: Create git's authorized_keys file - ansible.builtin.file: - path: /home/git/.ssh/authorized_keys - mode: "600" - state: touch - when: not git_authkeys.stat.exists - -- name: Add git's public SSH key to authorized_keys - ansible.builtin.lineinfile: - path: /home/git/.ssh/authorized_keys - regex: "^ssh-rsa" - line: "{{ git_rsapub['content'] | b64decode }}" + register: gitea_rsapub - name: Create Gitea host script for SSH ansible.builtin.template: @@ -57,11 +58,147 @@ dest: /usr/local/bin/gitea mode: "755" +- name: Install Gitea SSH SELinux policy source + ansible.builtin.copy: + src: gitea_ssh.te + dest: "{{ podman_selinux_dir }}/gitea_ssh.te" + owner: root + group: root + mode: "0644" + register: gitea_selinux_src + when: selinux is defined and selinux is not false + +- name: Clear stale Gitea SSH SELinux artifacts + ansible.builtin.file: + path: "{{ podman_selinux_dir }}/gitea_ssh.{{ item }}" + state: absent + loop: [mod, pp] + when: + - selinux is defined and selinux is not false + - gitea_selinux_src is changed + +- name: Compile Gitea SSH SELinux policy module + ansible.builtin.command: + cmd: >- + checkmodule -M -m -o {{ podman_selinux_dir }}/gitea_ssh.mod + {{ podman_selinux_dir }}/gitea_ssh.te + creates: "{{ podman_selinux_dir }}/gitea_ssh.mod" + when: selinux is defined and selinux is not false + +- name: Package Gitea SSH SELinux policy module + ansible.builtin.command: + cmd: >- + semodule_package -o {{ podman_selinux_dir }}/gitea_ssh.pp + -m {{ podman_selinux_dir }}/gitea_ssh.mod + creates: "{{ podman_selinux_dir }}/gitea_ssh.pp" + when: selinux is defined and selinux is not false + +- name: List loaded SELinux policy modules for Gitea + ansible.builtin.command: + cmd: semodule -l + register: gitea_semodule_list + changed_when: false + when: selinux is defined and selinux is not false + +- name: Load Gitea SSH SELinux policy module + ansible.builtin.command: + cmd: semodule -i {{ podman_selinux_dir }}/gitea_ssh.pp + register: gitea_semodule + changed_when: gitea_semodule.rc == 0 + when: + - selinux is defined and selinux is not false + - gitea_selinux_src is changed or "gitea_ssh" not in gitea_semodule_list.stdout_lines + +- name: Configure sshd for Gitea AuthorizedKeysCommand + ansible.builtin.template: + src: gitea_sshd.conf.j2 + dest: /etc/ssh/sshd_config.d/gitea.conf + owner: root + group: root + mode: "0644" + validate: /usr/sbin/sshd -t -f %s + notify: restart_ssh + +- name: Set SELinux context on Gitea's data directory + community.general.sefcontext: + target: "{{ gitea_data }}(/.*)?" + setype: container_file_t + selevel: "{{ gitea_se_level }}" + state: present + when: selinux is defined and selinux is not false + +- name: Create Gitea's data directory + ansible.builtin.file: + path: "{{ gitea_data }}" + state: directory + owner: "{{ gitea_oci_uid }}" + group: "{{ gitea_oci_uid }}" + mode: "0750" + setype: >- + {{ (selinux is defined and selinux is not false) + | ternary('container_file_t', omit) }} + selevel: "{{ gitea_se_level }}" + +- name: Create Gitea's container-side SSH directories + ansible.builtin.file: + path: "{{ item.path }}" + state: directory + owner: "{{ gitea_oci_uid }}" + group: "{{ gitea_oci_uid }}" + mode: "{{ item.mode }}" + setype: >- + {{ (selinux is defined and selinux is not false) + | ternary('container_file_t', omit) }} + selevel: "{{ gitea_se_level }}" + loop: + - { path: "{{ gitea_data }}/git", mode: "0755" } + - { path: "{{ gitea_data }}/git/.ssh", mode: "0700" } + +- name: Authorise git's public SSH key inside the container + ansible.builtin.copy: + content: "{{ gitea_rsapub['content'] | b64decode }}" + dest: "{{ gitea_data }}/git/.ssh/authorized_keys" + owner: "{{ gitea_oci_uid }}" + group: "{{ gitea_oci_uid }}" + mode: "0600" + setype: >- + {{ (selinux is defined and selinux is not false) + | ternary('container_file_t', omit) }} + selevel: "{{ gitea_se_level }}" + +- name: Set SELinux context on Gitea's logging directory + community.general.sefcontext: + target: "{{ gitea_logs }}(/.*)?" + setype: oci_log_t + selevel: "{{ gitea_se_level }}" + state: present + when: selinux is defined and selinux is not false + - name: Create Gitea's logging directory ansible.builtin.file: - name: /var/log/gitea + name: "{{ gitea_logs }}" state: directory - mode: "755" + owner: "{{ gitea_oci_uid }}" + group: "{{ gitea_oci_uid }}" + mode: "0755" + setype: >- + {{ (selinux is defined and selinux is not false) + | ternary('oci_log_t', omit) }} + selevel: "{{ gitea_se_level }}" + +- name: Create Gitea's log file for Fail2ban + ansible.builtin.file: + path: /var/log/oci/gitea/gitea.log + state: touch + owner: "{{ gitea_oci_uid }}" + group: "{{ gitea_oci_uid }}" + mode: "0640" + modification_time: preserve + access_time: preserve + setype: >- + {{ (selinux is defined and selinux is not false) + | ternary('oci_log_t', omit) }} + selevel: "{{ gitea_se_level }}" - name: Install Gitea's Fail2ban filter ansible.builtin.template: diff --git a/roles/gitea/templates/compose-env.j2 b/roles/gitea/templates/compose-env.j2 deleted file mode 100644 index e540e17..0000000 --- a/roles/gitea/templates/compose-env.j2 +++ /dev/null @@ -1,19 +0,0 @@ -# {{ ansible_managed }} -gitea_version={{ gitea_version }} -gitea_name={{ gitea_name }} -gitea_domain={{ gitea_domain }} -gitea_rooturl={{ gitea_rooturl }} -gitea_web={{ gitea_web }} -gitea_ssh={{ gitea_ssh }} -gitea_dbtype={{ gitea_dbtype }} -gitea_dbhost={{ gitea_dbhost }} -gitea_dbname={{ gitea_dbname }} -gitea_dbuser={{ gitea_dbuser }} -gitea_dbpass={{ gitea_dbpass }} -gitea_proxy_limit={{ gitea_proxy_limit }} -gitea_trusted_proxies={{ gitea_trusted_proxies }} -{% if not gitea_signup %} -gitea_disable_registration=true -{% else %} -gitea_disable_registration=false -{% endif %} diff --git a/roles/gitea/templates/docker-compose.yml.j2 b/roles/gitea/templates/docker-compose.yml.j2 deleted file mode 100644 index 44b27b9..0000000 --- a/roles/gitea/templates/docker-compose.yml.j2 +++ /dev/null @@ -1,36 +0,0 @@ -version: '3.7' - -services: - gitea: - image: "gitea/gitea:${gitea_version}" - container_name: "${gitea_name}" - ports: - - "${gitea_ssh}:22" - - "${gitea_web}:3000" - extra_hosts: - - "host.docker.internal:host-gateway" - environment: - - USER_UID={{ getent_passwd.git[1] }} - - USER_GID={{ getent_group.git[1] }} - - GITEA__log__MODE=file - - GITEA__server__ROOT_URL=${gitea_rooturl} - - GITEA__server__DOMAIN=${gitea_domain} - - GITEA__server__SSH_DOMAIN=${gitea_domain} - - GITEA__database__DB_TYPE=${gitea_dbtype} - - GITEA__database__HOST=${gitea_dbhost} - - GITEA__database__NAME=${gitea_dbname} - - GITEA__database__USER=${gitea_dbuser} - - GITEA__database__PASSWD=${gitea_dbpass} - - GITEA__security__INSTALL_LOCK=true - - GITEA__security__REVERSE_PROXY_LIMIT=${gitea_proxy_limit} - - GITEA__security__REVERSE_PROXY_TRUSTED_PROXIES=${gitea_trusted_proxies} - - GITEA__service__DISABLE_REGISTRATION=${gitea_disable_registration} - volumes: - - {{ gitea_volume }}:/data - - /home/git/.ssh:/data/git/.ssh - - /var/log/gitea:/data/gitea/log - - /etc/timezone:/etc/timezone:ro - - /etc/localtime:/etc/localtime:ro - -volumes: - {{ gitea_volume }}: diff --git a/roles/gitea/templates/fail2ban-jail.conf.j2 b/roles/gitea/templates/fail2ban-jail.conf.j2 index 749e732..9d1f9bf 100644 --- a/roles/gitea/templates/fail2ban-jail.conf.j2 +++ b/roles/gitea/templates/fail2ban-jail.conf.j2 @@ -2,17 +2,8 @@ [gitea] enabled = true filter = gitea -logpath = /var/log/gitea/gitea.log +logpath = {{ gitea_logs }}/gitea.log maxretry = 10 findtime = 3600 bantime = 900 action = iptables-allports - -[gitea-docker] -enabled = true -filter = gitea -logpath = /var/log/gitea/gitea.log -maxretry = 10 -findtime = 3600 -bantime = 900 -action = iptables-allports[chain="FORWARD"] diff --git a/roles/gitea/templates/gitea_sshd.conf.j2 b/roles/gitea/templates/gitea_sshd.conf.j2 new file mode 100644 index 0000000..0975bac --- /dev/null +++ b/roles/gitea/templates/gitea_sshd.conf.j2 @@ -0,0 +1,3 @@ +# {{ ansible_managed }} +AuthorizedKeysCommand /usr/local/bin/gitea keys -e git -u %u -t %t -k %k +AuthorizedKeysCommandUser git diff --git a/roles/mariadb/tasks/main.yml b/roles/mariadb/tasks/main.yml index f6d3692..a36b640 100644 --- a/roles/mariadb/tasks/main.yml +++ b/roles/mariadb/tasks/main.yml @@ -16,12 +16,22 @@ regex: "^bind-address" line: "bind-address = {{ ansible_facts.docker0.ipv4.address }}" notify: restart_mariadb - when: ansible_facts.docker0 is defined + when: ansible_facts['docker0'] is defined + +- name: Change the bind-address for rootless containers + ansible.builtin.lineinfile: + path: /etc/mysql/mariadb.conf.d/50-server.cnf + regexp: "^bind-address" + line: "bind-address = 0.0.0.0" + notify: restart_mariadb + when: + - ansible_facts['docker0'] is not defined + - podman_compose is defined - name: Flush handlers to ensure MariaDB restarts immediately ansible.builtin.meta: flush_handlers tags: restart_mariadb - when: ansible_facts.docker0 is defined + when: ansible_facts['docker0'] is defined or podman_compose is defined - name: Allow database connections from Docker community.general.ufw: @@ -29,4 +39,4 @@ port: "3306" proto: tcp src: "{{ item }}" - loop: "{{ mariadb_trust | default(['172.16.0.0/12']) }}" + loop: "{{ mariadb_trust | default(['169.254.0.0/16']) }}" diff --git a/roles/podman/defaults/main.yml b/roles/podman/defaults/main.yml index 8639764..8496664 100644 --- a/roles/podman/defaults/main.yml +++ b/roles/podman/defaults/main.yml @@ -1,4 +1,6 @@ # Default configuration for podman role -podman_repos_keytype: ed25519 -podman_ssh_key_path: "{{ ansible_user_dir }}/.ssh" +podman_log_root: /var/log/oci podman_nodocker: false +podman_repos_keytype: ed25519 +podman_selinux_dir: /usr/share/selinux +podman_ssh_key_path: "{{ ansible_user_dir }}/.ssh" diff --git a/roles/podman/files/oci_log.te b/roles/podman/files/oci_log.te new file mode 100644 index 0000000..b654c8b --- /dev/null +++ b/roles/podman/files/oci_log.te @@ -0,0 +1,19 @@ +module oci_log 1.0; + +require { + type container_t; + type fail2ban_t; + attribute logfile; + attribute file_type; + attribute non_security_file_type; + class dir { add_name search watch write }; + class file { append create getattr open watch }; +} + +type oci_log_t; +typeattribute oci_log_t file_type, non_security_file_type, logfile; + +allow container_t oci_log_t:dir { add_name search write }; +allow container_t oci_log_t:file { append create getattr open }; +allow fail2ban_t oci_log_t:dir watch; +allow fail2ban_t oci_log_t:file watch; diff --git a/roles/podman/tasks/deploy.yml b/roles/podman/tasks/deploy.yml index 03f28ba..dd9335e 100644 --- a/roles/podman/tasks/deploy.yml +++ b/roles/podman/tasks/deploy.yml @@ -71,7 +71,7 @@ community.crypto.openssh_keypair: path: "{{ podman_homedir }}/.ssh/podman-id_{{ podman_repos_keytype }}" type: "{{ podman_repos_keytype }}" - comment: "{{ ansible_hostname }}-{{ podman_user }}-deploy-key" + comment: "{{ ansible_facts['hostname'] }}-{{ podman_user }}-deploy-key" owner: "{{ podman_user }}" group: "{{ podman_user }}" mode: "0600" diff --git a/roles/podman/tasks/main.yml b/roles/podman/tasks/main.yml index 1094b46..a0ccd94 100644 --- a/roles/podman/tasks/main.yml +++ b/roles/podman/tasks/main.yml @@ -3,6 +3,91 @@ name: ["podman", "docker-cli", "docker-compose"] state: present +- name: Allow rootless containers to use capabilities in their user namespace + ansible.posix.seboolean: + name: container_use_userns_all_caps + state: true + persistent: true + when: selinux is defined and selinux is not false + +- name: Create SELinux policy build directory + ansible.builtin.file: + path: "{{ podman_selinux_dir }}" + state: directory + owner: root + group: root + mode: "0755" + when: selinux is defined and selinux is not false + +- name: Install container log SELinux policy source + ansible.builtin.copy: + src: oci_log.te + dest: "{{ podman_selinux_dir }}/oci_log.te" + owner: root + group: root + mode: "0644" + register: podman_selinux_src + when: selinux is defined and selinux is not false + +- name: Clear stale container log SELinux artifacts + ansible.builtin.file: + path: "{{ podman_selinux_dir }}/oci_log.{{ item }}" + state: absent + loop: [mod, pp] + when: + - selinux is defined and selinux is not false + - podman_selinux_src is changed + +- name: Compile container log SELinux policy module + ansible.builtin.command: + cmd: >- + checkmodule -M -m -o {{ podman_selinux_dir }}/oci_log.mod + {{ podman_selinux_dir }}/oci_log.te + creates: "{{ podman_selinux_dir }}/oci_log.mod" + when: selinux is defined and selinux is not false + +- name: Package container log SELinux policy module + ansible.builtin.command: + cmd: >- + semodule_package -o {{ podman_selinux_dir }}/oci_log.pp + -m {{ podman_selinux_dir }}/oci_log.mod + creates: "{{ podman_selinux_dir }}/oci_log.pp" + when: selinux is defined and selinux is not false + +- name: List loaded SELinux policy modules + ansible.builtin.command: + cmd: semodule -l + register: podman_semodule_list + changed_when: false + when: selinux is defined and selinux is not false + +- name: Load container log SELinux policy module + ansible.builtin.command: + cmd: semodule -i {{ podman_selinux_dir }}/oci_log.pp + register: podman_semodule + changed_when: podman_semodule.rc == 0 + when: + - selinux is defined and selinux is not false + - podman_selinux_src is changed or "oci_log" not in podman_semodule_list.stdout_lines + +- name: Set SELinux context on container log directory + community.general.sefcontext: + target: "{{ podman_log_root }}(/.*)?" + setype: oci_log_t + state: present + when: selinux is defined and selinux is not false + +- name: Create container log directory + ansible.builtin.file: + path: "{{ podman_log_root }}" + state: directory + owner: root + group: root + mode: "0755" + setype: >- + {{ (selinux is defined and selinux is not false) + | ternary('oci_log_t', omit) }} + - name: Install GnuPG tools and trusted CA bundle ansible.builtin.apt: name: ["gnupg", "ca-certificates"] @@ -19,13 +104,19 @@ label: "{{ item }}" when: podman_compose is defined +- name: Set subuid base facts for podman users + ansible.builtin.set_fact: + podman_subuid_base: "{{ podman_subuid_base | default({}) | combine({ + item.item: 100000 + ((item.ansible_facts.getent_passwd[item.item][1] + | int - 1000) * 65536) }) }}" + loop: "{{ user_info.results }}" + loop_control: + label: "{{ item.item }}" + - name: Configure /etc/subuid for rootless users ansible.builtin.lineinfile: path: "/etc/subuid" - line: - "{{ item.item }}:{{ 100000 + - ((item.ansible_facts.getent_passwd[item.item][1] | int - 1000) * 65536) - }}:65536" + line: "{{ item.item }}:{{ podman_subuid_base[item.item] }}:65536" regexp: "^{{ item.item }}:" create: true backup: true @@ -37,10 +128,7 @@ - name: Configure /etc/subgid for rootless users ansible.builtin.lineinfile: path: "/etc/subgid" - line: - "{{ item.item }}:{{ 100000 + - ((item.ansible_facts.getent_passwd[item.item][1] | int - 1000) * 65536) - }}:65536" + line: "{{ item.item }}:{{ podman_subuid_base[item.item] }}:65536" regexp: "^{{ item.item }}:" create: true backup: true @@ -49,10 +137,39 @@ loop_control: label: "{{ item.item }}" -- name: Enable lingering for podman compose user - ansible.builtin.command: - cmd: "loginctl enable-linger {{ item.item }}" - changed_when: false +- name: Ensure systemd linger directory exists + ansible.builtin.file: + path: /var/lib/systemd/linger + state: directory + owner: root + group: root + mode: "0755" + +- name: Enable lingering for podman compose users + ansible.builtin.file: + path: "/var/lib/systemd/linger/{{ item.item }}" + state: touch + owner: root + group: root + mode: "0644" + access_time: preserve + modification_time: preserve + loop: "{{ user_info.results }}" + loop_control: + label: "{{ item.item }}" + +- name: Start user manager for podman compose users + ansible.builtin.systemd_service: + name: "user@{{ item.ansible_facts.getent_passwd[item.item][1] }}.service" + state: started + loop: "{{ user_info.results }}" + loop_control: + label: "{{ item.item }}" + +- name: Wait for user runtime directory + ansible.builtin.wait_for: + path: "/run/user/{{ item.ansible_facts.getent_passwd[item.item][1] }}/bus" + timeout: 30 loop: "{{ user_info.results }}" loop_control: label: "{{ item.item }}" @@ -97,7 +214,7 @@ dest: /etc/profile.d/docker-host.sh owner: root group: root - mode: '0755' + mode: "0755" - name: Install git for repository cloning ansible.builtin.apt: diff --git a/roles/proxy/handlers/main.yml b/roles/proxy/handlers/main.yml index 5e59514..4bfa1bb 100644 --- a/roles/proxy/handlers/main.yml +++ b/roles/proxy/handlers/main.yml @@ -1,13 +1,3 @@ -- name: Enable nginx sites configuration - ansible.builtin.file: - src: "/etc/nginx/sites-available/{{ item.item.domain }}.conf" - dest: "/etc/nginx/sites-enabled/{{ item.item.domain }}.conf" - state: link - mode: "400" - loop: "{{ nginx_sites.results }}" - when: item.changed - listen: reload_nginx - - name: Reload nginx ansible.builtin.service: name: nginx diff --git a/roles/proxy/tasks/main.yml b/roles/proxy/tasks/main.yml index 299f8cb..a1683e9 100644 --- a/roles/proxy/tasks/main.yml +++ b/roles/proxy/tasks/main.yml @@ -43,7 +43,16 @@ loop_control: label: "{{ item.domain }}" notify: reload_nginx - register: nginx_sites + +- name: Enable nginx sites configuration + ansible.builtin.file: + src: "/etc/nginx/sites-available/{{ item.domain }}.conf" + dest: "/etc/nginx/sites-enabled/{{ item.domain }}.conf" + state: "{{ item.enabled | default(true) | ternary('link', 'absent') }}" + loop: "{{ proxy.servers }}" + loop_control: + label: "{{ item.domain }}" + notify: reload_nginx - name: Generate self-signed certificate ansible.builtin.command: