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

From Bitbull Wiki
Jump to navigation Jump to search
 
(3 intermediate revisions by the same user not shown)
Line 225: Line 225:
 
  dnf install -y policycoreutils-devel checkpolicy setroubleshoot-server setools-console
 
  dnf install -y policycoreutils-devel checkpolicy setroubleshoot-server setools-console
 
  > /var/log/audit/audit.log
 
  > /var/log/audit/audit.log
 +
touch /.autorelabel
 
  reboot
 
  reboot
 
  ssh -lroot $HOST -p222
 
  ssh -lroot $HOST -p222
Line 230: Line 231:
 
  mkdir -p /root/selinux/gitea
 
  mkdir -p /root/selinux/gitea
 
  cd /root/selinux/gitea
 
  cd /root/selinux/gitea
 +
 +
[[Category:Linux]]
 +
[[Category:SELinux]]
 +
[[Category:Security]]
  
 
==Generate policy default ruleset==
 
==Generate policy default ruleset==
Line 236: Line 241:
 
  for r in appstream baseos extras ; do dnf config-manager --set-enabled $r; done
 
  for r in appstream baseos extras ; do dnf config-manager --set-enabled $r; done
  
==Modify ruleset defaults
+
==Modify ruleset defaults==
 
Rename gitea_var_lib_t
 
Rename gitea_var_lib_t
 
  grep gitea_var_lib_t gitea*
 
  grep gitea_var_lib_t gitea*
Line 262: Line 267:
 
* build and load new rules
 
* build and load new rules
 
  bash gitea.sh
 
  bash gitea.sh
 +
 +
[[Category:Linux]]
 +
[[Category:SELinux]]
 +
[[Category:Security]]
  
 
==Apply new context lables==
 
==Apply new context lables==
Line 269: Line 278:
  
 
* Restart gitea  
 
* Restart gitea  
systemctl restart gitea
+
systemctl restart gitea
  
 
* Verify domain  
 
* Verify domain  
Line 292: Line 301:
 
   [...]
 
   [...]
 
</pre>
 
</pre>
 +
 +
[[Category:Linux]]
 +
[[Category:SELinux]]
 +
[[Category:Security]]
  
 
==Define additional SELinux rules==
 
==Define additional SELinux rules==
Line 322: Line 335:
 
  sed -i 's/^SELINUX=.*/SELINUX=enforcing/' /etc/selinux/config
 
  sed -i 's/^SELINUX=.*/SELINUX=enforcing/' /etc/selinux/config
 
  grubby --update-kernel ALL --remove-args selinux
 
  grubby --update-kernel ALL --remove-args selinux
 +
touch /.autorelabel
 
  reboot
 
  reboot
 
  sealert -a /var/log/audit/audit.log  
 
  sealert -a /var/log/audit/audit.log  
Line 351: Line 365:
 
ss -tan # port 2222 and 3000 are NOW listening!
 
ss -tan # port 2222 and 3000 are NOW listening!
 
</pre>
 
</pre>
 +
 +
[[Category:Linux]]
 +
[[Category:SELinux]]
 +
[[Category:Security]]
  
 
=Appendix=
 
=Appendix=

Latest revision as of 13:12, 12 July 2025

1 Setup

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

1.1 Disable SELinux

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

1.2 VARS and Functions

HOST=$(hostname -f)

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

1.3 Install software

install reverse proxy and base software

dnf -y install openssl wget nginx git policycoreutils-python-utils


1.4 Move system sshd port to 222

semanage port -a -t ssh_port_t -p tcp 222
sed -i 's/^#Port 22/Port 222/' /etc/ssh/sshd_config
systemctl restart sshd

1.5 Configure Firewall

  • open https
firewall-cmd --permanent --add-port=443/tcp
  • open new sshd port
firewall-cmd --permanent --add-port=222/tcp
  • forward port 22 to gitea
firewall-cmd --permanent --add-forward-port=port=22:proto=tcp:toport=2222
  • load new rules
firewall-cmd --reload

1.6 Install/Configure Mariadb

  • install and enable
dnf install -y mariadb-server
systemctl enable --now mariadb
  • secure mariadb
mysql_secure_installation
  • create gitea database user
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

1.7 Install Gitea

  • 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
  • Install 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
  • create systemd service
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
  • create gitea config
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


1.8 nginx configuration

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

1.9 create gitea application admin

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

2 SELinux configuration

2.1 Install selinux tools as root

dnf install -y policycoreutils-devel checkpolicy setroubleshoot-server setools-console
> /var/log/audit/audit.log
touch /.autorelabel
reboot
ssh -lroot $HOST -p222
mkdir -p /root/selinux/gitea
cd /root/selinux/gitea

2.2 Generate policy default ruleset

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

2.3 Modify ruleset defaults

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
  • build and load new rules
bash gitea.sh

2.4 Apply new context lables

  • Label ports
semanage port -a -t gitea_port_t -p tcp 2222
semanage port -a -t gitea_port_t -p tcp 3000
  • Restart gitea
systemctl restart gitea
  • Verify domain
 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
  • verify port lables
semanage port --list | grep gitea
   gitea_port_t                   tcp      2222, 3000
  • verify file lables
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/:
   drwxr-xr-x. 2 git git system_u:object_r:gitea_data_t:s0  6 Jul 11 07:23 actions_artifacts
   [...]

2.5 Define additional SELinux rules

  • Reset alerts and verify alerts
> /var/log/audit/audit.log
systemctl restart gitea
  • Now test the application with all its functions
  • verify new alerts
sealert -a /var/log/audit/audit.log 
grep 'run: sealert' /var/log/messages 
ausearch  --raw | audit2allow
  • Review, understand and then add this to gitea.te, gitea.fc, gitea.if
  • Then rebuild/install policy with `bash gitea.sh`
  • finally start over until you have no violations anymore

> /var/log/audit/audit.log reboot sealert -a /var/log/audit/audit.log grep 'run: sealert' /var/log/messages ausearch --raw | audit2allow ausearch -c 'git' --raw | audit2allow -R


3 ReEnable SELinux

Now we switch back to enforcing and test again

setenforce 1
sed -i 's/^SELINUX=.*/SELINUX=enforcing/' /etc/selinux/config
grubby --update-kernel ALL --remove-args selinux
touch /.autorelabel
reboot
sealert -a /var/log/audit/audit.log 

3.1 Test if rules are working 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!

4 Appendix

4.1 Final policy files

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);


4.2 Boolean Analysis: domain_can_mmap_files

  • Lets see what domain_can_mmap_files contains
getsebool -a | grep domain_can_mmap_files
  domain_can_mmap_files --> off


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.

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