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

From Bitbull Wiki
Jump to navigation Jump to search
 
(5 intermediate revisions by the same user not shown)
Line 1: Line 1:
=Setup Host=
+
=Setup=
 
* OS: Rocky Linux 10 minimal
 
* OS: Rocky Linux 10 minimal
 
* FQDN: gitea01.domain.tld
 
* FQDN: gitea01.domain.tld
 +
 +
==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
 
<pre>
 
<pre>
 +
setenforce 0
 +
sed -i 's/^SELINUX=.*/SELINUX=permissive/' /etc/selinux/config
 +
</pre>
  
 +
==VARS and Functions==
 +
<pre>
 
HOST=$(hostname -f)
 
HOST=$(hostname -f)
genpasswd() {
+
 
 +
genpasswd() {
 
local l=$1
 
local l=$1
 
       [ "$l" == "" ] && l=20
 
       [ "$l" == "" ] && l=20
 
       tr -dc A-Za-z0-9_ < /dev/urandom | head -c ${l} | xargs
 
       tr -dc A-Za-z0-9_ < /dev/urandom | head -c ${l} | xargs
  }
+
}
 +
</pre>
 +
 
 +
==Install software==
 +
install reverse proxy and base software
 +
dnf -y install openssl wget nginx git policycoreutils-python-utils
 +
 
 +
 
 +
==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
 +
 
 +
==Configure Firewall==
 +
 
 +
* open https
 +
firewall-cmd --permanent --add-port=443/tcp
 +
* open new sshd port
 +
firewall-cmd --permanent --add-port=222/tcp
  
# install reverse proxy and base software
+
* forward port 22 to gitea
dnf -y install openssl wget nginx git policycoreutils-python-utils
+
firewall-cmd --permanent --add-forward-port=port=22:proto=tcp:toport=2222
  
# for now, we set selinux to permissive, once all rules are set and we have no violations anymore, we set to enforce again
+
* load new rules
setenforce 0
+
firewall-cmd --reload
sed -i 's/^SELINUX=.*/SELINUX=permissive/' /etc/selinux/config
 
  
semanage port -a -t ssh_port_t -p tcp 222
+
==Install/Configure Mariadb==
sed -i 's/^#Port 22/Port 222/' /etc/ssh/sshd_config
+
* install and enable
firewall-cmd --permanent --add-port=443/tcp
+
dnf install -y mariadb-server
firewall-cmd --permanent --add-port=222/tcp
+
systemctl enable --now mariadb
# 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
+
* secure mariadb
systemctl enable --now mariadb
+
mysql_secure_installation
mysql_secure_installation
 
  
 +
* create gitea database user
 +
<pre>
 
MARIADB_PW=$(genpasswd)
 
MARIADB_PW=$(genpasswd)
 
echo MARIADB_PW=$MARIADB_PW
 
echo MARIADB_PW=$MARIADB_PW
Line 39: Line 62:
 
FLUSH PRIVILEGES;
 
FLUSH PRIVILEGES;
 
EOF
 
EOF
 +
</pre>
  
# create gitea user
+
==Install Gitea==
 +
* create gitea user
 +
<pre>
 
useradd --system --shell /usr/bin/false --comment 'Git Version Control' --create-home --home-dir /var/lib/gitea git
 
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 /var/lib/gitea/data
Line 47: Line 73:
 
chown root:git /etc/gitea
 
chown root:git /etc/gitea
 
chmod 770 /etc/gitea
 
chmod 770 /etc/gitea
 +
</pre>
  
 +
* Install gitea
 +
<pre>
 
GITEA_VERSION=1.23.8
 
GITEA_VERSION=1.23.8
 
wget -O /usr/local/bin/gitea https://dl.gitea.com/gitea/$GITEA_VERSION/gitea-$GITEA_VERSION-linux-amd64
 
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
 
chown root:git /usr/local/bin/gitea
 
chmod 750 /usr/local/bin/gitea
 
chmod 750 /usr/local/bin/gitea
 +
</pre>
  
 +
* create systemd service
 +
<pre>
 
cat <<EOF >/etc/systemd/system/gitea.service
 
cat <<EOF >/etc/systemd/system/gitea.service
 
[Unit]
 
[Unit]
Line 73: Line 105:
 
WantedBy=multi-user.target
 
WantedBy=multi-user.target
 
EOF
 
EOF
 +
</pre>
  
 +
* create gitea config
 +
<pre>
 
cat <<EOF >/etc/gitea/app.ini
 
cat <<EOF >/etc/gitea/app.ini
 
WORK_PATH = /var/lib/gitea/
 
WORK_PATH = /var/lib/gitea/
Line 110: Line 145:
 
[oauth2]
 
[oauth2]
 
JWT_SECRET = $(genpasswd 32)
 
JWT_SECRET = $(genpasswd 32)
 +
EOF
 +
</pre>
  
 +
chown root:git /etc/gitea/app.ini
 +
chmod 660 /etc/gitea/app.ini
  
EOF
+
systemctl daemon-reload
 +
systemctl enable --now gitea
  
chown root:git /etc/gitea/app.ini
 
chmod 660 /etc/gitea/app.ini
 
 
systemctl daemon-reload
 
systemctl enable --now gitea
 
  
 +
==nginx configuration==
 +
<pre>
 
openssl req -x509 -newkey rsa:4096 -nodes \
 
openssl req -x509 -newkey rsa:4096 -nodes \
 
   -keyout /etc/pki/tls/private/gitea.key \
 
   -keyout /etc/pki/tls/private/gitea.key \
 
   -out /etc/pki/tls/certs/gitea.crt \
 
   -out /etc/pki/tls/certs/gitea.crt \
 
   -days 3650 -subj "/CN=$HOST"
 
   -days 3650 -subj "/CN=$HOST"
 +
</pre>
  
chown root:root /etc/pki/tls/private/gitea.key
+
chown root:root /etc/pki/tls/private/gitea.key
chmod 600 /etc/pki/tls/private/gitea.key
+
chmod 600 /etc/pki/tls/private/gitea.key
  
openssl dhparam -out /etc/nginx/dhparam.pem 4096
+
openssl dhparam -out /etc/nginx/dhparam.pem 4096
  
 +
<pre>
 
cat <<EOF >/etc/nginx/conf.d/gitea.conf
 
cat <<EOF >/etc/nginx/conf.d/gitea.conf
 
server {
 
server {
Line 157: Line 196:
 
}
 
}
 
EOF
 
EOF
 +
</pre>
  
systemctl enable --now nginx
+
systemctl enable --now nginx
  
# change to git user, which has no sell as default
+
==create gitea application admin==
su -s /bin/bash git
+
Change to git user, which has no sell as default
 +
su -s /bin/bash git
  
 +
<pre>
 
genpasswd() {
 
genpasswd() {
 
   local l=$1
 
   local l=$1
Line 176: Line 218:
 
gitea admin user create --admin --username $ADMIN_USER --password "$ADMIN_PW" --email admin@domain.tld --config /etc/gitea/app.ini
 
gitea admin user create --admin --username $ADMIN_USER --password "$ADMIN_PW" --email admin@domain.tld --config /etc/gitea/app.ini
 
exit
 
exit
 +
</pre>
  
# install selinux tools as root
+
=SELinux configuration=
dnf install -y policycoreutils-devel checkpolicy setroubleshoot-server setools-console
+
==Install selinux tools as root==
> /var/log/audit/audit.log
 
reboot
 
ssh -lroot $HOST -p222
 
  
 +
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
  
curl -k https://$(hostname -f) >/dev/null
+
[[Category:Linux]]
sealert -a /var/log/audit/audit.log
+
[[Category:SELinux]]
 +
[[Category:Security]]
  
----------------------------------------------
+
==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
  
mkdir -p /root/selinux/gitea
+
==Modify ruleset defaults==
cd /root/selinux/gitea
+
Rename gitea_var_lib_t
 +
grep gitea_var_lib_t gitea*
 +
sed -i 's/gitea_var_lib_t/gitea_data_t/g' gitea*
  
for r in appstream baseos extras ; do dnf config-manager --set-disabled $r; done
+
* Hide permissive setting, we want to use it in enforcing mode
sepolicy generate --init /usr/local/bin/gitea
+
sed -i 's/^permissive/#permissive/' gitea.te
for r in appstream baseos extras ; do dnf config-manager --set-enabled $r; done
 
  
 +
* Add file context rule
 +
echo '/etc/gitea(/.*)?                gen_context(system_u:object_r:gitea_conf_t,s0)' >> gitea.fc
  
# rename gitea_var_lib_t
+
* <tt>vim gitea.te</tt>
grep gitea_var_lib_t gitea*
+
<pre>
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
 
# add in declaration
 
type gitea_conf_t;
 
type gitea_conf_t;
Line 216: Line 260:
 
type gitea_port_t;
 
type gitea_port_t;
 
corenet_port(gitea_port_t)
 
corenet_port(gitea_port_t)
------
+
</pre>
  
# disable rpm building cmd
+
* disable rpm building cmd
sed -i 's/^rpmbuild/#rpmbuild/' gitea.sh
+
sed -i 's/^rpmbuild/#rpmbuild/' gitea.sh
  
bash gitea.sh
+
* build and load new rules
 +
bash gitea.sh
  
semanage port -a -t gitea_port_t -p tcp 2222
+
[[Category:Linux]]
semanage port -a -t gitea_port_t -p tcp 3000
+
[[Category:SELinux]]
 +
[[Category:Security]]
  
systemctl restart gitea
+
==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
  
[root@gitea01]# ps -ef -Z | grep gitea
+
* Restart 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
+
systemctl restart gitea
  
 +
* Verify domain
 +
<pre>
 +
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
 +
</pre>
  
[root@gitea01]# semanage port --list | grep gitea
+
* verify port lables
gitea_port_t                  tcp      2222, 3000
+
<pre>
 +
semanage port --list | grep gitea
 +
  gitea_port_t                  tcp      2222, 3000
 +
</pre>
  
[root@gitea01]# ls -lZ /etc/gitea/app.ini /var/lib/gitea/data/
+
* verify file lables
-rw-rw----.  1 root git system_u:object_r:gitea_conf_t:s0  681 Jul 11 07:23 /etc/gitea/app.ini
+
<pre>
/var/lib/gitea/data/:
+
ls -lZ /etc/gitea/app.ini /var/lib/gitea/data/
total 0
+
  -rw-rw----.  1 root git system_u:object_r:gitea_conf_t:s0  681 Jul 11 07:23 /etc/gitea/app.ini
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
+
  /var/lib/gitea/data/:
systemctl restart gitea
+
  drwxr-xr-x. 2 git git system_u:object_r:gitea_data_t:s0  6 Jul 11 07:23 actions_artifacts
curl -k https://$(hostname -f) >/dev/null
+
  [...]
sealert -a /var/log/audit/audit.log
+
</pre>
 
 
[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
 
  
 +
[[Category:Linux]]
 +
[[Category:SELinux]]
 +
[[Category:Security]]
  
# Lets see what domain_can_mmap_files contains
+
==Define additional SELinux rules==
[root@gitea01]# getsebool -a | grep domain_can_mmap_files
+
* Reset alerts and verify alerts
domain_can_mmap_files --> off
+
> /var/log/audit/audit.log
 +
systemctl restart gitea
  
[root@gitea01]# semanage boolean -l | grep domain_can_mmap_files
+
* Now test the application with all its functions
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
+
* verify new alerts
allow domain file_type:blk_file map; [ domain_can_mmap_files ]:True
+
sealert -a /var/log/audit/audit.log
allow domain file_type:chr_file map; [ domain_can_mmap_files ]:True
+
grep 'run: sealert' /var/log/messages
allow domain file_type:file map; [ domain_can_mmap_files ]:True
+
ausearch  --raw | audit2allow
allow domain file_type:lnk_file map; [ domain_can_mmap_files ]:True
 
  
# Review, understand and then add this to gitea.te  
+
* Review, understand and then add this to gitea.te, gitea.fc, gitea.if
# Then rebuild policy with `bash gitea.sh`
+
* Then rebuild/install policy with `bash gitea.sh`
  
 +
* finally start over until you have no violations anymore
 
> /var/log/audit/audit.log
 
> /var/log/audit/audit.log
systemctl restart gitea
+
reboot
curl -k https://$(hostname -f) >/dev/null
 
 
sealert -a /var/log/audit/audit.log  
 
sealert -a /var/log/audit/audit.log  
 
grep 'run: sealert' /var/log/messages
 
grep 'run: sealert' /var/log/messages
Line 279: Line 330:
  
  
# Once you have no more errors, switch back to enforcing mode
+
=ReEnable SELinux=
[root@gitea01]# sealert -a /var/log/audit/audit.log
+
Now we switch back to enforcing and test again
100% done
+
setenforce 1
found 0 alerts in /var/log/audit/audit.log
+
sed -i 's/^SELINUX=.*/SELINUX=enforcing/' /etc/selinux/config
 
+
grubby --update-kernel ALL --remove-args selinux
okay, now lets test all the function we must have working
+
touch /.autorelabel
- log in as admin
+
reboot
- create org
+
sealert -a /var/log/audit/audit.log  
- 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
 
  
 +
==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
  
 +
<pre>
 
semanage port -a -t ssh_port_t -p tcp 2222
 
semanage port -a -t ssh_port_t -p tcp 2222
 
semanage port -a -t ssh_port_t -p tcp 3000
 
semanage port -a -t ssh_port_t -p tcp 3000
Line 328: Line 359:
 
semanage port -a -t gitea_port_t -p tcp 3000
 
semanage port -a -t gitea_port_t -p tcp 3000
 
semanage port -l | grep gitea_
 
semanage port -l | grep gitea_
    gitea_port_t                  tcp      2222, 3000
+
  gitea_port_t                  tcp      2222, 3000
 
> /var/log/audit/audit.log
 
> /var/log/audit/audit.log
 
reboot
 
reboot
 
sealert -a /var/log/audit/audit.log
 
sealert -a /var/log/audit/audit.log
 
ss -tan # port 2222 and 3000 are NOW listening!
 
ss -tan # port 2222 and 3000 are NOW listening!
 +
</pre>
  
#############################################################################################################
+
[[Category:Linux]]
 +
[[Category:SELinux]]
 +
[[Category:Security]]
 +
 
 +
=Appendix=
 +
==Final policy files==
 
</pre>
 
</pre>
 
<div class="toccolours mw-collapsible mw-collapsed" style="width:60%">
 
<div class="toccolours mw-collapsible mw-collapsed" style="width:60%">
Line 563: Line 600:
 
</div>
 
</div>
 
</div>
 
</div>
 +
 +
 +
==Boolean Analysis: domain_can_mmap_files==
 +
* Lets see what domain_can_mmap_files contains
 +
<pre>
 +
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
 +
</pre>
  
 
[[Category:Linux]]
 
[[Category:Linux]]
 
[[Category:SELinux]]
 
[[Category:SELinux]]
 
[[Category:Security]]
 
[[Category:Security]]

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