Introducción
SonarQube es un software de código abierto desarrollado por una sociedad anónima fundada en 2008 cuya sede está en Suiza y que permite evaluar la calidad del código que se desarrolla y permite que los equipos de desarrollo crezcan elaborando software de calidad. Actualmente lo estoy descubriendo y me gustaría compartir un poco la instalación que hice en un CentOS 8. Actualmente hay una versión comunitaria y otras versiones que contienen más características pero que son de pago, nosotros nos vamos a centrar en la comunitaria.
Requisitos recomendados
Los requisitos mínimos para poder funcionar son los siguientes:
Mínimo 3 GB de RAM, 2GB que utilizará SonarQube y 1 GB que utilizará y debe quedar libre para el sistema. Aunque yo lo he podido hacer funcionar en un SO con 2GB de RAM.
Tener instalado un sistema gestor de base de datos como:
- PostgreSQL, será con el que trabajaremos.
- Microsoft SQL Server
- Oracle
Tenemos que tener almacenamiento bastante rápido para las operaciones de I/O que realiza Elastic Search, sin embargo, si lo quieres para tu uso personal, no hace falta a menos que vayas a calcular la materia oscura del universo.
Recomendaciones: Si estamos trabajando con máquinas virtuales, es indispensable hacer snapshot antes de empezar, o crear una máquina plantilla, anotar los cambios y luego hacerlos en nuestra futura máquina que irá a producción.
Tareas y pasos previos
Instalar el servicio solucionador de problemas de SELinux
Recordemos que CentOS hace uso de unas políticas de seguridad que trabajan junto con el kernel de Linux llamadas SELinux, y que permiten que no se ejecuten exploits 0 day entre otras cosas. Por eso es importante lidiar con las políticas y NO desactivarlas bajo ningún concepto.
Verificar que tenemos SELinux activo:
$ sestatus
Devolverá una salida como esta:
SELinux status: enabled
SELinuxfs mount: /sys/fs/selinux
SELinux root directory: /etc/selinux
Loaded policy name: targeted
Current mode: enforcing
Mode from config file: enforcing
Policy MLS status: enabled
Policy deny_unknown status: allowed
Memory protection checking: actual (secure)
Max kernel policy version: 31
Si el valor SELinux status: enabled
y Current mode
es enforcing
, está bien, si no tendremos que:
- Revisar si tenemos el paquete
selinux-policy-targeted
yselinux-policy
instalados. - Si tenemos desactivado SELinux, hacer un snapshot, y activarlo, editamos
/etc/selinux/config
SELINUX=enforcing
- Activarlo ahora
# setenforce 1
Por otro lado, si tenemos las políticas instaladas y activadas instalamos el servidor que nos ayudará a solucionar los problemas con las políticas.
# dnf install setroubleshoot-server
Revisar si tenemos algún ejecutable que se ha intentado saltarse las políticas:
# sealert -a /var/log/audit.log
El archivo de configuración de este servidor está: /etc/setroubleshoot/setroubleshoot.conf
Crear usuario/grupo y home
Para crearlo:
# useradd sonarqube -m -d /opt/sonarqube
# passwd sonarqube
Este creará el usuario con un home específico en /opt/sonarqube
y le asignaremos una contraseña.
Asignar los valores requeridos
Tenemos que tener en cuenta estos valores:
vm.max_map_count
tiene que ser >= 262144fs.file-max
es >= 65536- El usuario que ejecute SonarQube podrá abrir hasta un total de 65536 descriptores de archivos y también abrir al menos un total de 4096 hilos.
Podemos revisar estos valores:
$ sysctl vm.max_map_count
$ sysctl fs.file-max
$ ulimit -n
$ ulimit -u
Asignamos los valores si son inferiores:
# sysctl -w vm.max_map_count=262144
# sysctl -w fs.file-max=65536
# ulimit -n 65536
# ulimit -u 4096
Para que se conserven estos valores al arranque, creamos el siguiente archivo: /etc/sysctl.d/99-sonarcube.conf
vm.max_map_count=262144
fs.file-max=65536
Y creamos otro archivo: /etc/security/limits.d/99-sonarqube.conf
sonarqube - nofile 65536
sonarqube - nproc 4096
Recomiendan verificar si tenemos SECCOMP habilitado en el kernel de Linux, lo he comprobado y efectivamente está habilitado en el kernel oficial de CentOS 8. Sin embargo, conviene siempre hacerlo, en caso de que no lo tengans, tendrás que especificar la siguiente línea en su archivo de configuración o recompilar el kernel con estas opciones (algo no recomendado).
$ grep SECCOMP /boot/config-$(uname -r)
Si te devuelve esta salida, no hace falta que añadas nada.
CONFIG_HAVE_ARCH_SECCOMP_FILTER=y
CONFIG_SECCOMP_FILTER=y
CONFIG_SECCOMP=y
Si te devuelve lo contrario “y” por un “n”, o no salen las líneas, tendrías que añadir esta línea al archivo en la $HOME
de SonarQube: $HOME/conf/sonar.properties
más adelante.
sonar.search.javaAdditionalOpts=-Dbootstrap.system_call_filter=false
Instalando OpenJDK 11
Es necesario tenerlo instalado para poder continuar:
# dnf install java-11-openjdk-headless.x86_64
Instalando y configurando PostgreSQL
Por defecto, tenemos la versión 10.6 disponible en los repositorios AppStream.
NOTA: Aconsejo trabajar con tmux cuando estamos en el servidor para poder tener multisesión en la terminal virtual (tty).
Segundo, instalar PostgreSQL:
# dnf install postgresql-server
NOTA: Que sepamos que se ha creado un usuario y grupo postgres
y que tiene por defecto el UID y GID 26 cuyo home es /var/lib/pgsql
. Si vamos a utilizar alguna aplicación que precise de alguna configuración y necesite tener variables de entorno configuradas, tendremos que editar el archivo /var/lib/pgsql/.bash_profile
Inicializamos la base de datos:
# postgresql-setup --initdb
Si tenemos la siguiente salida es que ha ido todo bien:
* Initializing database in '/var/lib/pgsql/data'
* Initialized, logs are in /var/lib/pgsql/initdb_postgresql.log
Arrancando el servidor
# systemctl start postgresql.service
Si vemos la salida del netstat -ptna
veremos que hay un servicio escuchando por el puerto 5432.
tcp 0 0 127.0.0.1:5432 0.0.0.0:* LISTEN 21159/postmaster
tcp6 0 0 ::1:5432 :::* LISTEN 21159/postmaster
No vamos a configurar el acceso de manera remota porque es darle los caramelos a los niños directamente.
Cambiando la contraseña del usuario postgres
$ psql
postgres=# ALTER USER postgres WITH PASSWORD 'cambiaLaContrasenaAqui';
ALTER ROLE
Crear los objetos en la BD
Los usuarios/grupos existen en PostgreSQL como ROLE, comento este paso para que no nos liemos administrando la base de datos en un futuro.
$ createuser -U postgres -W -D -l -P -R -S sonarqube
Opciones:
-U postgres
: Utilizamos el superusuarios de PostgreSQL-D
evita que el ROLE nuevo cree bases de datos-l
permite hacer login-P
Nos pregunta la contraseña sin emitir caracteres como en el comandopasswd
o el login en una terminal virtualtty
.-R
el usuario no creará otros ROLE-S
evita tener superprivilegios en todo el sistema
Revisamos que se creó el usuario correctamente, escalamos privilegios en el sistema y hacemos sesión como usuario postgres
:
$ su -
# su - postgres
$ psql -U postgres
postgres=# \du
List of roles
Role name | Attributes | Member of
-----------+------------------------------------------------------------+-----------
postgres | Superuser, Create role, Create DB, Replication, Bypass RLS | {}
sonarqube | | {}
Salimos de la sesión en PostgreSQL utilizando \l
y creamos la base de datos con el comando createdb
:
$ createdb -U postgres -E UTF-8 -l en_US.UTF-8 -O sonarqube sonarqube
Opciones:
-U postgres
: Utilizamos el superusuarios de PostgreSQL-E UTF-8
: Estamos diciendo que la base de datos debe tener UTF-8 como codificación por defecto.-l en_US.UTF-8
: Le decimos que el idioma y codificación serán inglés americano y UTF-8-O sonarqube
: Es el propietario de la DBsonarqube
: Usuario que hemos creado
Revisamos que se ha creado la base de datos correctamente:
$ psql -U postgres
postgres=# \l
List of databases
Name | Owner | Encoding | Collate | Ctype | Access privileges
-----------+-----------+----------+-------------+-------------+-----------------------
postgres | postgres | UTF8 | en_US.UTF-8 | en_US.UTF-8 |
sonarqube | sonarqube | UTF8 | en_US.UTF-8 | en_US.UTF-8 |
Damos privilegios al usuario sonarqube:
postgres=# GRANT ALL PRIVILEGES ON DATABASE sonarqube TO sonarqube;
Y revisamos que ya los tiene:
postgres-# \l
List of databases
Name | Owner | Encoding | Collate | Ctype | Access privileges
-----------+-----------+----------+-------------+-------------+-------------------------
postgres | postgres | UTF8 | en_US.UTF-8 | en_US.UTF-8 |
sonarqube | sonarqube | UTF8 | en_US.UTF-8 | en_US.UTF-8 | =Tc/sonarqube +
| | | | | sonarqube=CTc/sonarqube
Hacemos copia de seguridad del archivo /var/lib/pgsql/data/pg_hba.conf
# cp -av /var/lib/pgsql/data/pg_hba.conf /var/lib/pgsql/data/pg_hba.conf.bck.$(date +%d-%m-%y-%H:%M)
Editamos el archivo con nuestro editor favorito y comentamos las siguientes líneas:
#host all all 127.0.0.1/32 ident
#host all all ::1/128 ident
#local replication all peer
#host replication all 127.0.0.1/32 ident
#host replication all ::1/128 ident
Y añadimos las siguientes:
host sonarqube sonarqube 127.0.0.1/32 md5
host sonarqube sonarqube ::1/128 md5
NOTA: Si no tenemos IPv6 habilitado, evitamos copiar las líneas ::1/128
.
NOTA: Por otro lado, con este cambio, evitamos la conexión indiscriminada, y hacemos una política de denegamos todo y vamos permitiendo de forma controlada.
Reiniciamos el servicio:
# systemctl restart postgresql.service
Probamos a loguearnos:
$ psql -U sonarqube -W -h localhost -d sonarqube
Obtendremos el prompt:
psql (10.6)
Type "help" for help.
sonarqube=>
Habilitamos el servicio en el arranque:
# systemctl enable postgresql.service
¿Qué pasa si nos hemos equivocado?
Pues podemos deshacer nuestros pasos de la siguiente forma:
NOTA: Es importante eliminar primero la base de datos que está asociada al role sonarqube porque PostgreSQL no permite eliminar el usuario si hay permisos asociados al role.
Eliminar la base de datos:
$ dropdb --if-exists sonarqube
Eliminar el usuario:
$ dropuser --if-exists sonarqube
Instalando SonarQube
Accedemos al sistema como usuario sonarqube
y descargamos el archivo de su sitio oficial.
Recordemos que el usuario sonarqube
tiene su $HOME
en /opt/sonarqube
.
$ unzip sonarqube*.zip
$ mv sonarqube*/* .
$ rm -rf sonarqube-*
Retiquetamos las etiquetas para SELinux, si te interesa guardar en un archivo el resultado puedes ejecutarlo con una redireccionando la salida a un archivo:
# restorecon -vR /opt/sonarqube/
No te asustes si aparecen muchas líneas como estas:
Relabeled /opt/sonarqube/lib/common/netty-buffer-4.1.32.Final.jar from unconfined_u:object_r:usr_t:s0 to unconfined_u:object_r:lib_t:s0
Relabeled /opt/sonarqube/lib/common/commons-io-2.6.jar from unconfined_u:object_r:usr_t:s0 to unconfined_u:object_r:lib_t:s0
Relabeled /opt/sonarqube/lib/jsw from unconfined_u:object_r:usr_t:s0 to unconfined_u:object_r:lib_t:s0
Relabeled /opt/sonarqube/lib/jsw/wrapper-3.2.3.jar from unconfined_u:object_r:usr_t:s0 to unconfined_u:object_r:lib_t:s0
Forman parte del proceso y al estar en modo verbose, se muestran.
Creamos un directorio para el almacenamiento de datos por parte de ElasticSearch
# mkdir -p /var/sonarqube/{data,temp}
# chown sonarqube:sonarqube /var/sonarqube/{data,temp}
Hacemos una copia de seguridad de este archivo: /opt/sonarqube/conf/sonar.properties
$ cp -av $HOME/conf/sonar.properties $HOME/conf/sonar.properties.bck.$(date +%d-%m-%Y-%H:%M)
Editamos el archivo opt/sonarqube/conf/sonar.properties
añadiendo las siguientes líneas al final del archivo:
sonar.jdbc.username=sonarqube
sonar.jdbc.password=example@
sonar.jdbc.url=jdbc:postgresql://localhost/sonarqube
sonar.path.data=/var/sonarqube/data
sonar.path.temp=/var/sonarqube/temp
sonar.web.host=IP_DE_TU_HOST
sonar.web.port=9000
sonar.web.context=/sonarqube
NOTA: Si tratas de configurar el puerto por defacto del 1024, no podrás hacerlo si no eres root
. Para ello tendrás que mirar alternativas con setcap
o explorar otras vías, por lo que perderás más tiempo haciéndolo que creando una redirección en el cortafuegos.
Guardamos e iniciamos el proceso:
$ cd /opt/sonarqube/bin/linux-x86-64
$ ./sonar.sh start
Veremos una salida como esta:
Starting SonarQube...
Started SonarQube.
Habilitando el acceso al puerto desde firewalld
:
# firewall-cmd --add-port 9000/tcp --permanent
# firewall-cmd --reload
¡Voilá! tendremos SonarQube arrancado y funcionando, puedes revisarlo en http://IP_SERVIDOR:9000/sonarqube
Si de lo contrario, has recibido un mensaje como este:
Starting SonarQube...
Stopped SonarQube.
Hay algo que no está funcionando. ¿Cómo revisarlo?
- Revisar los logs de:
/opt/sonarqube/logs
- Revisar que no hayan problemas en SELinux con
# sealert -a /var/log/audit/audit.log
- Comprobar que estamos ejecutándolo con el usuario y grupo
sonarqube
- Comprobar que los permisos de los directorios y ejecutables son del usuario que tocan:
# find /opt/sonarqube/ ! -user sonarqube
# find /opt/sonarqube/ ! -group sonarqube
# find /var/sonarqube/ ! -user sonarqube
# find /var/sonarqube/ ! -group sonarqube
Si devuelven salidas quiere decir que esos archivos/directorios no tienen los permisos correspondientes.
- Comprobar que tenemos OpenJDK correctamente instalado:
$ whereis java
java: /usr/bin/java /usr/lib/java /etc/java /usr/share/java /usr/share/man/man1/java.1.gz
- Verificar que el servicio de PostgreSQL está corriendo:
$ systemctl status postgresql.service
- Verificar que podemos acceder mediante usuario
sonarqube
a la base de datos desonarqube
:
$ psql -U sonarqube -W -h localhost -d sonarqube
- Revisar que la configuración de base de datos, servidor web… corresponde con la realidad.
/opt/sonarqube/conf/sonar.properties
- Mirar si los archivos tienen los valores que tocan en
/etc/sysctl.d/99-sonarqube.conf
y/etc/security/limits.d/99-sonarqube.conf
Creando un servicio
¡Ahora que ya funciona! Es hora de crear un servicio para que arranque con la máquina.
Creamos en el directorio /etc/systemd/system/multi-user.target.wants/sonarqube.service
Y añadimos las siguientes líneas:
[Unit]
Description=Servicio que gestiona SonarQube
After=postgresql.service
[Service]
Type=forking
User=sonarqube
Group=sonarqube
ExecStart=/opt/sonarqube/bin/linux-x86-64/sonar.sh start
ExecStop=/opt/sonarqube/bin/linux-x86-64/sonar.sh stop
PIDFile=/opt/sonarqube/bin/linux-x86-64/SonarQube.pid
LimitNOFILE=65536
LimitNPROC=4096
Restart=always
[Install]
WantedBy=multi-user.target
Recargamos la nueva configuración del servicio:
# systemctl daemon-reload
Iniciamos el servicio
# systemctl start sonarcube.service
Habilitamos el servicio al arranque:
systemctl enable sonarcube.service
Para confirmar que todo va a funcionar si hay un apagón o un reinicio programado, hay que hacer un reinicio del servidor y comprobarlo, no basta con ya lo haré, cuando se pueda, hay que hacerlo.
# systemctl reboot
Y con esto, habremos instalado SonarQube en CentOS 8 y con SELinux habilitado (por favor seguir las buenas prácticas). Más adelante, según vaya viendo más sobre SonarQube iré publicando más tutoriales.