Difference between revisions of "Gitea Setup on Rocky10 with SELinux"

From Bitbull Wiki
Jump to navigation Jump to search
(Created page with " =Setup Host= * OS: Rocky Linux 10 minimal * FQDN: gitea01.domain.tld <pre> HOST=$(hostname -f) genpasswd() { local l=$1 [ "$l" == "" ] && l=20 tr -dc A-Za-z...")
 
Line 1: Line 1:
 
 
=Setup Host=
 
=Setup Host=
 
* OS: Rocky Linux 10 minimal
 
* OS: Rocky Linux 10 minimal
Line 561: Line 560:
 
# Allow Gitea to read system network configuration
 
# Allow Gitea to read system network configuration
 
sysnet_read_config(gitea_t);
 
sysnet_read_config(gitea_t);
 
 
</pre>
 
</div>
 
</div>
 
 
<div class="toccolours mw-collapsible mw-collapsed" style="width:60%">
 
File: <b>gitea.fc</b>    Modified: <b>2025-07-12 12:41:42</b>
 
<div class="mw-collapsible-content">
 
<pre>
 
# Set the security context for the Gitea executable
 
/usr/local/bin/gitea -- gen_context(system_u:object_r:gitea_exec_t,s0)
 
# Set the security context for Gitea data directories
 
/var/lib/gitea(/.*)? gen_context(system_u:object_r:gitea_data_t,s0)
 
# Set the security context for Gitea configuration files
 
/etc/gitea(/.*)? gen_context(system_u:object_r:gitea_conf_t,s0)
 
 
</pre>
 
</pre>
 
</div>
 
</div>
Line 582: Line 565:
  
 
[[Category:Linux]]
 
[[Category:Linux]]
 +
[[Category:SELinux]]
 
[[Category:Security]]
 
[[Category:Security]]
[[Category:SELinux]]
 

Revision as of 11:05, 12 July 2025

Setup Host

  • OS: Rocky Linux 10 minimal
  • FQDN: gitea01.domain.tld

HOST=$(hostname -f)
 genpasswd() {
	local l=$1
       	[ "$l" == "" ] && l=20
      	tr -dc A-Za-z0-9_ < /dev/urandom | head -c ${l} | xargs
 }

# install reverse proxy and base software
dnf -y install openssl wget nginx git policycoreutils-python-utils

# for now, we set selinux to permissive, once all rules are set and we have no violations anymore, we set to enforce again
setenforce 0
sed -i 's/^SELINUX=.*/SELINUX=permissive/' /etc/selinux/config

semanage port -a -t ssh_port_t -p tcp 222
sed -i 's/^#Port 22/Port 222/' /etc/ssh/sshd_config
firewall-cmd --permanent --add-port=443/tcp
firewall-cmd --permanent --add-port=222/tcp
# firewall-cmd --permanent --remove-forward-port=port=22:proto=tcp:toport=2222:toaddr=127.0.0.1
firewall-cmd --permanent --add-forward-port=port=22:proto=tcp:toport=2222
systemctl restart sshd # test connection to port 222
firewall-cmd --reload

dnf install -y mariadb-server
systemctl enable --now mariadb
mysql_secure_installation

MARIADB_PW=$(genpasswd)
echo MARIADB_PW=$MARIADB_PW
mysql -u root -p <<EOF
CREATE DATABASE gitea CHARACTER SET 'utf8mb4' COLLATE 'utf8mb4_unicode_ci';
CREATE USER 'gitea'@'localhost' IDENTIFIED BY '$MARIADB_PW';
GRANT ALL PRIVILEGES ON gitea.* TO 'gitea'@'localhost';
FLUSH PRIVILEGES;
EOF

# create gitea user
useradd --system --shell /usr/bin/false --comment 'Git Version Control' --create-home --home-dir /var/lib/gitea git
mkdir -p /var/lib/gitea/data
mkdir -p /etc/gitea
chown -R git:git /var/lib/gitea
chown root:git /etc/gitea
chmod 770 /etc/gitea

GITEA_VERSION=1.23.8
wget -O /usr/local/bin/gitea https://dl.gitea.com/gitea/$GITEA_VERSION/gitea-$GITEA_VERSION-linux-amd64
chown root:git /usr/local/bin/gitea
chmod 750 /usr/local/bin/gitea

cat <<EOF >/etc/systemd/system/gitea.service
[Unit]
Description=Gitea (Git with a cup of tea)
After=syslog.target
After=network.target
Requires=mariadb.service

[Service]
RestartSec=2s
Type=simple
User=git
Group=git
WorkingDirectory=/var/lib/gitea/
ExecStart=/usr/local/bin/gitea web --config /etc/gitea/app.ini
Restart=always
Environment=USER=git HOME=/var/lib/gitea GITEA_WORK_DIR=/var/lib/gitea

[Install]
WantedBy=multi-user.target
EOF

cat <<EOF >/etc/gitea/app.ini
WORK_PATH = /var/lib/gitea/

[server]
APP_NAME = Gitea: Git with a cup of tea
RUN_USER = git
RUN_MODE = prod
HTTP_PORT = 3000
ROOT_URL = https://$HOST
SSH_DOMAIN = $HOST
START_SSH_SERVER = true
SSH_PORT         = 22
SSH_LISTEN_PORT  = 2222
OFFLINE_MODE = false

[database]
DB_TYPE = mysql
HOST = 127.0.0.1:3306
NAME = gitea
USER = gitea
PASSWD = $MARIADB_PW
SSL_MODE = disable

[security]
INSTALL_LOCK = true
SECRET_KEY = $(genpasswd 32)
INTERNAL_TOKEN = $(genpasswd 32)

[lfs]
PATH = /var/lib/gitea/data/lfs

[service]
DISABLE_REGISTRATION = true

[oauth2]
JWT_SECRET = $(genpasswd 32)


EOF

chown root:git /etc/gitea/app.ini
chmod 660 /etc/gitea/app.ini

systemctl daemon-reload
systemctl enable --now gitea

openssl req -x509 -newkey rsa:4096 -nodes \
  -keyout /etc/pki/tls/private/gitea.key \
  -out /etc/pki/tls/certs/gitea.crt \
  -days 3650 -subj "/CN=$HOST"

chown root:root /etc/pki/tls/private/gitea.key
chmod 600 /etc/pki/tls/private/gitea.key

openssl dhparam -out /etc/nginx/dhparam.pem 4096

cat <<EOF >/etc/nginx/conf.d/gitea.conf
server {
    listen 443 ssl;
    server_name $HOST;

    ssl_certificate /etc/pki/tls/certs/gitea.crt;
    ssl_certificate_key /etc/pki/tls/private/gitea.key;
    ssl_dhparam /etc/nginx/dhparam.pem;
    ssl_protocols TLSv1.2;
    add_header Strict-Transport-Security "max-age=31536000; 
    includeSubDomains; preload" always;
    ssl_stapling on;
    ssl_stapling_verify on;
    ssl_session_cache shared:SSL:10m;
    ssl_session_timeout 10m;
    ssl_ciphers 'ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES256-GCM-SHA384:ECDHE-RSA-AES256-GCM-SHA384:ECDHE-ECDSA-CHACHA20-POLY1305:ECDHE-RSA-CHACHA20-POLY1305:DHE-RSA-AES128-GCM-SHA256:DHE-RSA-AES256-GCM-SHA384';
    ssl_prefer_server_ciphers on;

    location / {
        proxy_pass http://127.0.0.1:3000;
        proxy_set_header Host \$host;
        proxy_set_header X-Real-IP \$remote_addr;
        proxy_set_header X-Forwarded-For \$proxy_add_x_forwarded_for;
        proxy_set_header X-Forwarded-Proto \$scheme;
    }
}
EOF

systemctl enable --now nginx

# change to git user, which has no sell as default
su -s /bin/bash git

genpasswd() {
  local l=$1
        [ "$l" == "" ] && l=20
        tr -dc A-Za-z0-9_ < /dev/urandom | head -c ${l} | xargs
 }

ADMIN_USER=$(genpasswd 8)
ADMIN_PW=$(genpasswd)

echo ADMIN_USER=$ADMIN_USER
echo ADMIN_PW=$ADMIN_PW
gitea admin user create --admin --username $ADMIN_USER --password "$ADMIN_PW" --email admin@domain.tld --config /etc/gitea/app.ini
exit

# install selinux tools as root
dnf install -y policycoreutils-devel checkpolicy setroubleshoot-server setools-console
> /var/log/audit/audit.log
reboot
ssh -lroot $HOST -p222



curl -k https://$(hostname -f) >/dev/null
sealert -a /var/log/audit/audit.log 

----------------------------------------------

mkdir -p /root/selinux/gitea
cd /root/selinux/gitea

for r in appstream baseos extras ; do dnf config-manager --set-disabled $r; done
sepolicy generate --init /usr/local/bin/gitea
for r in appstream baseos extras ; do dnf config-manager --set-enabled $r; done


# rename gitea_var_lib_t
grep gitea_var_lib_t gitea*
sed -i 's/gitea_var_lib_t/gitea_data_t/g' gitea*

# hide permissive setting, we want to use it in enforcing mode
sed -i 's/^permissive/#permissive/' gitea.te

# add file context rule
echo '/etc/gitea(/.*)?                gen_context(system_u:object_r:gitea_conf_t,s0)' >> gitea.fc

vim gitea.te
------
# add in declaration
type gitea_conf_t;
files_type(gitea_conf_t)

type gitea_port_t;
corenet_port(gitea_port_t)
------

# disable rpm building cmd
sed -i 's/^rpmbuild/#rpmbuild/' gitea.sh

bash gitea.sh

semanage port -a -t gitea_port_t -p tcp 2222
semanage port -a -t gitea_port_t -p tcp 3000

systemctl restart gitea

[root@gitea01]# ps -ef -Z | grep gitea
system_u:system_r:gitea_t:s0    git         1714       1 10 07:41 ?        00:00:01 /usr/local/bin/gitea web --config /etc/gitea/app.ini


[root@gitea01]# semanage port --list | grep gitea
gitea_port_t                   tcp      2222, 3000

[root@gitea01]# ls -lZ /etc/gitea/app.ini /var/lib/gitea/data/
-rw-rw----.  1 root git system_u:object_r:gitea_conf_t:s0  681 Jul 11 07:23 /etc/gitea/app.ini
/var/lib/gitea/data/:
total 0
drwxr-xr-x. 2 git git system_u:object_r:gitea_data_t:s0  6 Jul 11 07:23 actions_artifacts
[...]

> /var/log/audit/audit.log
systemctl restart gitea
curl -k https://$(hostname -f) >/dev/null
sealert -a /var/log/audit/audit.log 

[root@gitea01]# grep run: /var/log/messages | grep 3000 | tail -1
Jul 11 07:56:38 gitea01 setroubleshoot[2402]: SELinux is preventing /usr/sbin/nginx from name_connect access on the tcp_socket port 3000. For complete SELinux messages run: sealert -l c0b4821b-e5f0-41bb-95b6-e8eef3ecb36d


[root@gitea01]# ausearch -c 'nginx' --raw | audit2allow -R


# Lets see what domain_can_mmap_files contains
[root@gitea01]# getsebool -a | grep domain_can_mmap_files
domain_can_mmap_files --> off

[root@gitea01]# semanage boolean -l | grep domain_can_mmap_files
domain_can_mmap_files          (off  ,  off)  Allow any process to mmap any file on system with attribute file_type.

[root@gitea01]# sesearch -b domain_can_mmap_files -A
allow domain file_type:blk_file map; [ domain_can_mmap_files ]:True
allow domain file_type:chr_file map; [ domain_can_mmap_files ]:True
allow domain file_type:file map; [ domain_can_mmap_files ]:True
allow domain file_type:lnk_file map; [ domain_can_mmap_files ]:True

# Review, understand and then add this to gitea.te 
# Then rebuild policy with `bash gitea.sh`

> /var/log/audit/audit.log
systemctl restart gitea
curl -k https://$(hostname -f) >/dev/null
sealert -a /var/log/audit/audit.log 
grep 'run: sealert' /var/log/messages
ausearch  --raw | audit2allow
ausearch -c 'git' --raw | audit2allow -R


# Once you have no more errors, switch back to enforcing mode
[root@gitea01]# sealert -a /var/log/audit/audit.log
100% done
found 0 alerts in /var/log/audit/audit.log

okay, now lets test all the function we must have working
- log in as admin
- create org
- create repo
- modify repo
- delte repo
- create repo mirror
- administration
  - create user
  - run all  Maintenance Operations



# now we switch back to enforcing and test
# for now, we set selinux to permissive, once all rules are set and we have no violations anymore, we set to enforce again
setenforce 1
sed -i 's/^SELINUX=.*/SELINUX=enforcing/' /etc/selinux/config
grubby --update-kernel ALL --remove-args selinux
systemctl restart gitea
reboot

[root@gitea01]# sealert -a /var/log/audit/audit.log 
100% done

###### TEST IF SELINUX WORKS AS EXPECTED ####################################################################
chcon -t home_root_t /etc/gitea/app.ini
> /var/log/audit/audit.log
reboot
sealert -a /var/log/audit/audit.log
restorecon -FRv /etc/gitea/
> /var/log/audit/audit.log
reboot
sealert -a /var/log/audit/audit.log


semanage port -a -t ssh_port_t -p tcp 2222
semanage port -a -t ssh_port_t -p tcp 3000
> /var/log/audit/audit.log                
reboot                                    
sealert -a /var/log/audit/audit.log 
ss -tan # port 2222 and 3000 are not listening!
semanage port -a -t gitea_port_t -p tcp 2222
semanage port -a -t gitea_port_t -p tcp 3000
semanage port -l | grep gitea_
    gitea_port_t                   tcp      2222, 3000
> /var/log/audit/audit.log
reboot
sealert -a /var/log/audit/audit.log
ss -tan # port 2222 and 3000 are NOW listening!

#############################################################################################################

File: gitea.fc Modified: 2025-07-12 12:41:42

# Set the security context for the Gitea executable
/usr/local/bin/gitea		--	gen_context(system_u:object_r:gitea_exec_t,s0)
# Set the security context for Gitea data directories
/var/lib/gitea(/.*)?		gen_context(system_u:object_r:gitea_data_t,s0)
# Set the security context for Gitea configuration files
/etc/gitea(/.*)?		gen_context(system_u:object_r:gitea_conf_t,s0)

File: gitea.if Modified: 2025-07-12 12:43:07

# Interface to allow domain transition to gitea_t when executing gitea_exec_t
interface(`gitea_domtrans',`
	gen_require(`
		type gitea_t, gitea_exec_t;
	')

	corecmd_search_bin($1)
	domtrans_pattern($1, gitea_exec_t, gitea_t)
')

# Interface to allow execution of gitea_exec_t in the caller's domain
interface(`gitea_exec',`
	gen_require(`
		type gitea_exec_t;
	')

	corecmd_search_bin($1)
	can_exec($1, gitea_exec_t)
')

# Interface to allow searching of Gitea library directories
interface(`gitea_search_lib',`
	gen_require(`
		type gitea_data_t;
	')

	allow $1 gitea_data_t:dir search_dir_perms;
	files_search_var_lib($1)
')

# Interface to allow reading of Gitea library files
interface(`gitea_read_lib_files',`
	gen_require(`
		type gitea_data_t;
	')

	files_search_var_lib($1)
	read_files_pattern($1, gitea_data_t, gitea_data_t)
')

# Interface to allow management of Gitea library files
interface(`gitea_manage_lib_files',`
	gen_require(`
		type gitea_data_t;
	')

	files_search_var_lib($1)
	manage_files_pattern($1, gitea_data_t, gitea_data_t)
')

# Interface to allow management of Gitea library directories
interface(`gitea_manage_lib_dirs',`
	gen_require(`
		type gitea_data_t;
	')

	files_search_var_lib($1)
	manage_dirs_pattern($1, gitea_data_t, gitea_data_t)
')


# Interface to allow administration of a Gitea environment
interface(`gitea_admin',`
	gen_require(`
		type gitea_t;
		type gitea_data_t;
	')

	allow $1 gitea_t:process { signal_perms };
	ps_process_pattern($1, gitea_t)

    tunable_policy(`deny_ptrace',`',`
        allow $1 gitea_t:process ptrace;
    ')

	files_search_var_lib($1)
	admin_pattern($1, gitea_data_t)
	optional_policy(`
		systemd_passwd_agent_exec($1)
		systemd_read_fifo_file_passwd_run($1)
	')
')

File: gitea.te Modified: 2025-07-12 12:44:36

# Define the Gitea SELinux policy module version
policy_module(gitea, 1.0.0)

########################################
# Required types and classes for Gitea SELinux policy
require {
  type gitea_t;
  type gitea_data_t;
  type gitea_port_t;                      
  type gitea_conf_t;                               
  class dir search;
  class process setpgid;
  class file { getattr map open read execute execute_no_trans};
  class tcp_socket { accept bind listen name_bind name_connect connect create getattr getopt setopt read write};
  class udp_socket { connect create getattr setopt };
  type tmp_t;
  type httpd_t;
} 

type gitea_t;
type gitea_exec_t;
# Initialize the Gitea daemon domain
init_daemon_domain(gitea_t, gitea_exec_t)

# permissive gitea_t;

type gitea_data_t;
files_type(gitea_data_t)

type gitea_conf_t;
files_type(gitea_conf_t)

type gitea_port_t;
corenet_port(gitea_port_t)

########################################
# gitea policy definitions #############
# Allow Gitea to read and write to its own FIFO files
allow gitea_t self:fifo_file rw_fifo_file_perms;
# Allow Gitea to create and use Unix stream sockets
allow gitea_t self:unix_stream_socket create_stream_socket_perms;

# Allow Gitea to search its configuration directory
allow gitea_t gitea_conf_t:dir search;             
# Allow Gitea to get attributes, open, and read its configuration files
allow gitea_t gitea_conf_t:file { getattr open read };

# Allow HTTPD to connect to Gitea's TCP socket
allow httpd_t gitea_port_t:tcp_socket name_connect;

# Allow Gitea to manage its data directories
manage_dirs_pattern(gitea_t, gitea_data_t, gitea_data_t)
# Allow Gitea to manage its data files
manage_files_pattern(gitea_t, gitea_data_t, gitea_data_t)
# Allow Gitea to manage its symbolic link files
manage_lnk_files_pattern(gitea_t, gitea_data_t, gitea_data_t)
# Allow file transitions for Gitea in /var/lib
files_var_lib_filetrans(gitea_t, gitea_data_t, { dir file lnk_file })

# Allow Gitea to use interactive file descriptors
domain_use_interactive_fds(gitea_t)

# Allow Gitea to read files in /etc
files_read_etc_files(gitea_t)

# Allow Gitea to read localization files
miscfiles_read_localization(gitea_t)

# Define file transition patterns for Gitea
filetrans_pattern(gitea_t, gitea_data_t, gitea_data_t, file);
filetrans_pattern(gitea_t, gitea_data_t, gitea_data_t, dir);
filetrans_pattern(gitea_t, tmp_t, gitea_data_t, { file dir });

# Allow Gitea to map its data files
allow gitea_t gitea_data_t:file map;
# Allow Gitea to bind to its TCP socket
allow gitea_t gitea_port_t:tcp_socket name_bind;
# Allow Gitea to set process group ID
allow gitea_t self:process setpgid;
# Allow Gitea to perform operations on its TCP socket
allow gitea_t self:tcp_socket { accept bind listen read write};
# Allow Gitea to read the password file
auth_read_passwd_file(gitea_t)
# Allow Gitea to execute shell commands
corecmd_check_exec_shell(gitea_t)
# Allow Gitea to execute binaries
corecmd_exec_bin(gitea_t)
# Allow Gitea to bind to generic TCP nodes
corenet_tcp_bind_generic_node(gitea_t)
# Allow Gitea to read from sysfs
dev_read_sysfs(gitea_t)
# Allow Gitea to read network sysctl settings
kernel_read_net_sysctls(gitea_t)
# Allow Gitea to search network sysctl settings
kernel_search_network_sysctl(gitea_t)

# Allow Gitea to execute its own executable without transition
allow gitea_t gitea_exec_t:file execute_no_trans;
# Allow Gitea to execute its data files
allow gitea_t gitea_data_t:file execute;
# Allow Gitea to execute its data files without transition
allow gitea_t gitea_data_t:file execute_no_trans;
# Allow Gitea to connect to its TCP socket
allow gitea_t gitea_port_t:tcp_socket name_connect;  
# Allow Gitea to perform various operations on its TCP socket
allow gitea_t self:tcp_socket { connect create getattr getopt setopt };
# Allow Gitea to perform various operations on its UDP socket
allow gitea_t self:udp_socket { connect create getattr setopt };
# Allow Gitea to connect to HTTP ports
corenet_tcp_connect_http_port(gitea_t);
# Allow Gitea to connect to MySQL ports
corenet_tcp_connect_mysqld_port(gitea_t)
# Allow Gitea to read generic certificates
miscfiles_read_generic_certs(gitea_t);
# Allow Gitea to read system network configuration
sysnet_read_config(gitea_t);