Gitea

Qu’est-ce que gitea ?

Gitea est un outil de gestion de code côté serveur. Comparé à Github ou Gitlab, il a l’avantage d’être auto-hébergé mais surtout léger.

Installation

Pré-requis à l’installation de gitea

Par défaut, gitea demande uniquement une base de donnée. Toutefois, pour l’intégrer dans un environnement sécurisé et performant, on va rajouter un reverse-proxy. Nous aurons donc besoin de :

  • MariaDB >= 10.10.2

  • Nginx >= 1.18.0

  • De certificat pour la connexion HTTPS. Pour la sécurisation, on rajoutera :

  • Fail2Ban >= v0.11.2 Les installations et configurations sont traités dans d’autres documentations, je passe à la suite. N.B: Un rôle ansible existe et prends en charge l’ensemble de la configuration.

Préparation de la base de donnée

Je ne gère ici que MariaDB. Pour avoir la configuration avec PostgreSQL, cf la documentation officielle.

gitea_user="Gitea"
 gitea_password="YourPassword"
root_user="root"
database="GiteaDB"
localip=`ip a | egrep "^[ ]*inet " | cut -d "/" -f 1 | cut -d " " -f 6 | grep -v 127.0.0.1 || echo 127.0.0.1`
remoteip='YOUR.MYSQL.SERVER.ADDRESS' #Absent si sur le serveur local
remoteport='YOUR.MYSQL.SERVER.PORT'
if [ nc -z $remoteip $remoteport ]; then
cat > ./sql <<EOF
CREATE USER '${gitea_user}'@'${localip}' IDENTIFIED BY '${gitea_password}';
CREATE DATABASE ${database} CHARACTER SET 'utf8mb4' COLLATE 'utf8mb4_unicode_ci';
GRANT ALL PRIVILEGES ON ${database}.* TO '${gitea_user}'@'${localip}';
FLUSH PRIVILEGES;
EOF
mysql -h ${remoteip} -u ${root_user} -B -p  < ./sql
else
cat > ./sql <<EOF
CREATE USER '${gitea_user}'@'localhost' IDENTIFIED BY '${gitea_password}';
CREATE DATABASE ${database} CHARACTER SET 'utf8mb4' COLLATE 'utf8mb4_unicode_ci';
GRANT ALL PRIVILEGES ON ${database}.* TO '${gitea_user}'@'localhost';
FLUSH PRIVILEGES;
EOF
mysql -u ${root_user} -B -p $remote < ./sql
fi

rm ./sql

Avec ça, la database est initialisée et le compte Gitea peut s’y connecter avec le mot de passe associé.
Note relative à la sécurité : Alors oui, c’est pas bien de mettre le mot de passe en clair dans le fichier texte, c’est aussi pour ça qu’il est supprimé juste après et qu’il y a un espace devant l’ajout de la variable. A savoir que dans tous les cas, l’utilisateur git aura accès à ce mot de passe en clair dans la configuration de Gitea.

Préparation du reverse-proxy

Pour éviter d’exposer des ports supplémentaires, on va faire passer Gitea par un reverse-proxy. Pour cela, mon choix se porte sur Nginx. Pour les certificats, on pourra se tourner vers du Let'sEncrypt ou encore faire les notres.

cat >/etc/nginx/sites-available/gitea.nginx <<EOF
#gitea nginx conf
server {
  listen 80;
  server_name  gitea.luclis.fr srvprj02ovhluclis.fr;
  return 301 https://$host$request_uri;
}

server {
  listen 443 ssl http2;
  server_name  gitea.luclis.fr srvprj02ovhluclis.fr;
  ssl_certificate     /etc/ssl/public//gitea.luclis.fr_chain.pem;
  ssl_certificate_key /etc/ssl/private//gitea.luclis.fr.key;
  ssl_password_file   /etc/ssl/private//gitea.luclis.fr.pass;
  client_max_body_size 50m;

  #Fichier de logs
  access_log      /var/log/nginx/gitea_access.log;
  error_log       /var/log/nginx/gitea_error.log;

  location / {
    proxy_pass http://localhost:3000;
    proxy_set_header X-Real-IP $remote_addr;
    add_header Strict-Transport-Security "max-age=15552000; includeSubDomains; preload;";

  }
}
EOF
ln -fs /etc/nginx/sites-available/gitea.nginx /etc/nginx/sites-enabled/gitea.conf
systemctl restart nginx.service

Si tout va bien jusque là, vous devriez avoir une erreur 502en allant sur le site web : il faut encore que l’on install gitea.

Gitea en lui même

Avant d’installer gitea, il faut installer git. Ensuite on va lui créer un utilisateur disposant de droits restreints. Ensuite, on va créer les dossiers de gitea puis son personaliser son fichier de configuration.

sudo apt install git
gitea_user="Gitea"
 gitea_password="P@ssw0rd"
gitea_home="/home/gitea"
gitea_workdir="/var/lib/gitea"
database="GiteaDB"

sudo useradd ${gitea_user} -r -s /usr/sbin/nologin -md ${gitea_home}
sudo mkdir -p ${gitea_workdir}/{data,custom,log} /etc/gitea
sudo chown ${gitea_user}:${gitea_user} ${gitea_workdir} -R
sudo chmod 750 ${gitea_workdir} -R

sudo cat >/etc/gitea/app.ini<<EOF
APP_NAME = Gitea
RUN_USER = ${gitea_user}
RUN_MODE = PROD

[repository]
ROOT                    = ${gitea_home}/gitea-repositories
FORCE_PRIVATE           = true
MAX_CREATION_LIMIT      = 0
DISABLE_HTTP_GIT        = true
DEFAULT_BRANCH          = master
DEFAULT_PRIVATE         = last
ENABLE_PUSH_CREATE_USER = true
ENABLE_PUSH_CREATE_ORG  = true
[repository.upload]
TEMP_PATH           = ${gitea_workdir}/data/tmp/uploads

[ui]
SHOW_USER_EMAIL = true
DEFAULT_THEME   = arc-green

[server]
PROTOCOL              = http
DOMAIN                = luclis.fr
ROOT_URL              = https://gitea.luclis.fr/
HTTP_ADDR             = 127.0.0.1
HTTP_PORT             = 3000
START_SSH_SERVER      = false
SSH_DOMAIN            = luclis.fr
OFFLINE_MODE          = false
APP_DATA_PATH         = ${gitea_workdir}/data
LFS_START_SERVER      = true
LFS_JWT_SECRET        =

[lfs]
PATH      = ${gitea_workdir}/data/lfg

[database]
DB_TYPE  = mysql
HOST     = 127.0.0.1:3306
NAME     = ${database}
USER     = ${gitea_user}
PASSWD   = ${gitea_password}
SSL_MODE = false
LOG_SQL  = false

[security]
INSTALL_LOCK        = true
SECRET_KEY          =
INTERNAL_TOKEN      =
DISABLE_GIT_HOOKS   = true
PASSWORD_CHECK_PWN  = false

[service]
DISABLE_REGISTRATION              = false
REGISTER_EMAIL_CONFIRM            = false
REQUIRE_SIGNIN_VIEW               = true
DEFAULT_KEEP_EMAIL_PRIVATE        = false
ENABLE_CAPTCHA                    = true
SHOW_REGISTRATION_BUTTON          = true
ALLOW_ONLY_EXTERNAL_REGISTRATION  = false
ENABLE_NOTIFY_MAIL                = false

[mailer]
ENABLED            = false
FROM               = ${gitea_user}@luclis.fr
MAILER_TYPE        = sendmail
SENDER_PATH        = /usr/sbin/sendmail
SENDER_ARGS        = "--"

[session]
PROVIDER          = memory
COOKIE_SECURE     = true
COOKIE_NAME       = I_like_gitea
SESSION_LIFE_TIME = 36000
SAME_SITE         = strict

[attachment]
ENABLED = true
PATH    = ${gitea_workdir}/data/attachments

[log]
MODE       = console
LEVEL      = Info
EOF
sudo chmod 740 /etc/gitea/
sudo chmod 640 /etc/gitea/app.ini
sudo chown ${gitea_user}:${gitea_user} /etc/gitea -R

Maintenant que tout cela est opérationel, on peut télécharger gitea et préparer son service. Lors du téléchargement, on vérifiera également le hash du fichier. Bien que celui-ci soit colocalisé avec le binaire, c’est une petite protection en plus qui ne coute pas grand chose.

gitea_user="Gitea"
 gitea_password="P@ssw0rd"
gitea_home="/home/gitea"
gitea_workdir="/var/lib/gitea"
database="GiteaDB"
sudo -u ${gitea_user} wget -O ${gitea_home}/gitea-1.18.1-linux-amd64 https://dl.gitea.io/gitea/1.18.1/gitea-1.18.1-linux-amd64
sudo -u ${gitea_user} wget -O ${gitea_home}/gitea-1.18.1-linux-amd64.sha256 https://dl.gitea.io/gitea/1.18.1/gitea-1.18.1-linux-amd64.sha256
sudo -u ${gitea_user} sha256sum -c ${gitea_home}/gitea-1.18.1-linux-amd64.sha256

if [ $? -eq 0 ] ; then
  sudo mv ${gitea_home}/gitea-1.18.1-linux-amd64 /usr/local/bin/gitea
  sudo chmod 500 /usr/local/bin/gitea
  sudo chown ${gitea_user}:${gitea_user} /usr/local/bin/gitea
  sudo rm ${gitea_home}/gitea-1.18.1-linux-amd64.sha256
fi

sudo cat >/etc/systemd/system/gitea.service<<EOF

[Unit]
Description=Gitea (Git with a cup of tea)
After=syslog.target
After=network.target
After=mariadb.service

[Service]
Type=simple
User=${gitea_user}
Group=${gitea_user}
WorkingDirectory=${gitea_workdir}
ExecStart=/usr/local/bin/gitea web --config /etc/gitea/app.ini
Restart=always
PrivateTmp=yes
Environment=USER=${gitea_user} HOME=${gitea_home} GITEA_WORK_DIR=${gitea_workdir}

[Install]
WantedBy=multi-user.target
EOF

sudo systemctl enable gitea
sudo systemctl start gitea

Voilà, votre gitea est fonctionnel.

Configuration

Jonction à un domain LDAP

Renouvellement des mots de passes

Après avoir appliqué la PSO, j’ai du changer les mots de passes. Voici la procédure pour pas en oublier un. N.B : Bien penser a mettre un premier espace devant la commande afin qu’elle ne soit pas enregistrée dans l’historique de la personne qui l’a tapé !

samba-tool user setpassword svc_git
 sudo -u git gitea -c /etc/gitea/app.ini admin auth update-ldap --id 3 --bind-password XXXX

Création d’utilisateurs locaux

Dans certains cas (ex : Jenkins), il nous faudra un utilisateur local. Si ces derniers sont des comptes de services ou assimilable, il est recommandé de doper leur mot de passe et d’utiliser une clé d’accès (token). Pour cela, se connecter sur Gitea avec un compte administrateur

Administration du site
Comptes utilisateurs
Créer un compte
Source d'authentification : Locales
Visibilité de l'utilisatuer : Privée
Nom de l'utilisatuer : Jenkins
Adresse e-mail : no-reply@luclis.fr
Mot de passe <YOUR-PASSWORD>
Demander à l'utilisateur de changer son mot de passe (recommandé) : non
Envoyer une notification d'inscription : non

On modifiera ensuite ce compte pour le durcir un peu : Le compte ne doit pas pouvoir créer de dépôts ni d’organismes et doit être restreint. On va ensuite pouvoir créer un token avec d’abord. Pour cela, se connecter en tant que le compte créé, puis cliquer sur configuration

Application
Nom du jeton : Interconnexion Jenkins
Générer le jeton

A ce moment, Gitea a du créer un jeton de connexion pour le compte Jenkins et l’afficher à l’écran. Pensez à stocker ce mot de passe dans un endroit sécurisé, au hasard, un keepass ou équivalent. C’est tout, votre utilisateur est créer, peut se connecter, et fonctionne.

Sécurisation

Lecture des paramètres déjà mis

J’ai déjà paramétré certaines options de sécurités et réduction de la surface d’attaque :

  • Les cookies :

    • Ces derniers expirent au bout de 10h (soit une grosse journée de travail) ;

    • Ils sont limités à la même origine.

  • La vérification des mots de passe via IHaveBeenPwned

    • Ça peut sembler être une bonne idée, mais c’est un peu dommage d’envoyer nos credentials vers un serveur externe.

    • Je verrai pour faire un serveur similaire de mon côté.

Réduction des droits sur le dossier /etc/gitea

Une fois les clés générées automatiquement, gitea n’a plus besoin d’avoir accès en écriture à son fichier de configuration. On peut donc le donner à root :

sudo chown root:git /etc/gitea -R

Changer le mot de passe ldap

Dans le cas d’un compte de service, avec un mot de passe qui expire tous les ans, il faut penser à le changer. Pour cela, le réinitialiser dans l’AD puis le changer sur le fichier de configuration :

kinit svc_gitea
# si nécessaire, reset de force : 
samba-tool user setpassword svc_gitea
# Il doit y avoir une option avec samba-tool user password, mais je n´ai pas réussis à la faire marcher.
 aze='yourpassword' #Penser à l'espace pour ne pas vous retrouver avec le mot de passe dans l'historique bash.
sudo -u git gitea -c /etc/gitea/app.ini admin auth update-ldap --id 3 --bind-password ${aze}
# gitea admin auth list pour trouver l'ID de la configuration.

Fail2Ban

Utilisation

Rajouter occ en tant qu’alias

Pour me simplifier la vie, je me suis rajouté occ directement en tant qu’alias dans mon shell. J’ai préféré utiliser le bash de root, mais avec une bonne configuration sudo, celle la peut se mettre pour tout utilisateur privilégié.

echo "alias gitea='sudo -u git gitea -c /etc/gitea/app.ini'" >> /root/.bashrc

Ca serait mieux de réussir à le placer juste après les autres alias, mais je ne sais pas le faire en oneliner.

TroubleShooting

SSH port already in use

Si jamais vous changez le paramètre START_SSH_SERVER a TRUE, alors Gitea va chercher à lancer … un serveur ssh ! Si jamais vous avez déjà votre propre serveur ssh qui tourne, dans ce cas le service va planter en boucle.

Push en http interdit

Comme pour les cookie, j’ai interdit le push en HTTP. Il faudrait vérifier que cela ne s’applique pas à l’HTTPS.

Notes

Voir ce que ça vaut si je passe le protocol en fcgi. Peut-$etre plus rapide ?