Migrate Gitea to rootless Podman / SELinux
- Front git-over-SSH with host sshd and live key lookup - Build and load custom SELinux policies oci_log and gitea_ssh
This commit is contained in:
@@ -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 }}"
|
||||
|
||||
@@ -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 };
|
||||
@@ -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
|
||||
|
||||
+159
-22
@@ -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:
|
||||
|
||||
@@ -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 %}
|
||||
@@ -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 }}:
|
||||
@@ -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"]
|
||||
|
||||
@@ -0,0 +1,3 @@
|
||||
# {{ ansible_managed }}
|
||||
AuthorizedKeysCommand /usr/local/bin/gitea keys -e git -u %u -t %t -k %k
|
||||
AuthorizedKeysCommandUser git
|
||||
Reference in New Issue
Block a user