Configuring SSL for SonarQube

I’m working in the DevOps team of KoçSistem. The company has many products and projects of its own. And as the DevOps team, we are designing the DevOps cycle for all our projects and products.

We are using Azure DevOps for our pipelines. And we decided to use SonarQube to measure the code quality for all our projects. We have been using both for about three years now. Our SonarQube setup is an on-premise setup running with docker-compose and it’s been running smoothly.

Recently, we wanted to enable SSL on our SonarQube for security measures. I checked the official documents to determine the way to do it. It looked pretty straightforward:

  • Add a reverse proxy (nginx) to your docker-compose.yml
  • Configure your proxy to use SSL with your certificates and prepare redirection for http -> https
  • Store the configuration file of reverse proxy and certificate files in a volume.

So, this was the compose file we had:

version: "3.3"services:
sonarqube:
container_name: sonarqube_71
image: sonarqube:7.1-alpine
restart: always
ports:
- "80:9000" # web-ui (http)
- "443:9000" # web-ui (https)
networks:
- sonarnet
environment:
- SONARQUBE_JDBC_URL=jdbc:postgresql://db:5432/sonar
volumes:
- /data/docker-volumes/sonarqube/conf:/opt/sonarqube/conf
- /data/docker-volumes/sonarqube/data:/opt/sonarqube/data
- /data/docker-volumes/sonarqube/extensions:/opt/sonarqube/extensions
- /data/docker-volumes/sonarqube/bundled-plugins:/opt/sonarqube/lib/bundle d-plugins
db:
image: postgres
restart: always
ports:
- 5432:5432
networks:
- sonarnet
environment:
- POSTGRES_USER=sonar
- POSTGRES_PASSWORD=sonar
volumes:
- /data/docker-volumes/postgresql:/var/lib/postgresql
- /data/docker-volumes/postgresql/data:/var/lib/postgresql/data
networks:
sonarnet:
driver: bridge

And I modified it to have a reverse proxy and new volumes. I also changed the port of SonarQube container since we didn’t need it to be accessed directly from outside anymore. This is the new version:

version: "3.3"services:
sonarqube:
container_name: sonarqube_71
image: sonarqube:7.1-alpine
restart: always
ports:
- "9000" # web-ui (http)
# - "443:9000" # web-ui (https)
networks:
- sonarnet
environment:
- SONARQUBE_JDBC_URL=jdbc:postgresql://db:5432/sonar
volumes:
- /data/docker-volumes/sonarqube/conf:/opt/sonarqube/conf
- /data/docker-volumes/sonarqube/data:/opt/sonarqube/data
- /data/docker-volumes/sonarqube/extensions:/opt/sonarqube/extensions
- /data/docker-volumes/sonarqube/bundled-plugins:/opt/sonarqube/lib/bundle d-plugins
db:
image: postgres
restart: always
ports:
- 5432:5432
networks:
- sonarnet
environment:
- POSTGRES_USER=sonar
- POSTGRES_PASSWORD=sonar
volumes:
- /data/docker-volumes/postgresql:/var/lib/postgresql
- /data/docker-volumes/postgresql/data:/var/lib/postgresql/data
reverse_proxy:
container_name: reverse_proxy
depends_on:
- sonarqube
image: nginx
networks:
- sonarnet
ports:
- 80:80
- 443:443
restart: always
volumes:
- /data/docker-volumes/nginx/default.conf:/etc/nginx/conf.d/default.conf
- /data/docker-volumes/nginx/sonarqube.crt:/etc/ssl/certs/sonarqube .crt
- /data/docker-volumes/nginx/sonarqube.key:/etc/ssl/private/sonarqube.key
networks:
sonarnet:
driver: bridge

Then I configured my nginx config file as below:

server {
listen 80;
listen [::]:80;
server_name sonarqube.kocsistem.com.tr; return 301 https://$server_name$request_uri;
}
server {
listen 443 ssl;
listen [::]:443 ssl;
client_max_body_size 100M;
server_name sonarqube.kocsistem.com.tr; ssl_certificate /etc/ssl/certs/sonarqube.crt;
ssl_certificate_key /etc/ssl/private/sonarqube.key;
access_log /var/log/nginx/sonarqube.access.log; location / {
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-SSL on;
proxy_set_header X-Forwarded-Host $host;
proxy_pass http://sonarqube:9000;
proxy_redirect off;
}
}

I had a .pfx file for our wildcard certificate. So I used OpenSSL to convert it to a .crt and a .key file with the following commands:

#First create the .key file
openssl pkcs12 -in [yourfile.pfx] -nocerts -out [keyfile-encrypted.key]
#Then decrypt the .key
openssl rsa -in [keyfile-encrypted.key] -out [keyfile-decrypted.key]
#Finally, create your .crt file:
openssl pkcs12 -in [yourfile.pfx] -clcerts -nokeys -out [certificate.crt]

Then I killed my old containers and created the new ones. I checked from my browser and YES! Everything seemed to be working fine. I tried to reach via http protocol and got redirected to https with my valid certificate.

Since my redirection worked, I thought that my Azure DevOps — SonarQube certification would also work with no problems. But when I ran one of the pipelines, I faced the error:

UNABLE_TO_VERIFY_LEAF_SIGNATURE

Then I looked it up online to see if anyone had the same problem with SonarQube <-> Azure DevOps integration. I saw many questions but I couldn’t find the answer. Finally, I figured out that Azure DevOps agents were running on NodeJs and NodeJs did not trust the server if the server only has client certificate.

So I went back to my .pfx file. This time I ran the same OpenSSL script without the -clcerts flag:

openssl pkcs12 -in [yourfile.pfx] -nokeys -out [certificate.crt]

This time I got the bundle certificate (Root & Intermediate & Client). When I copied this certificate file to my volume folder, my Azure DevOps agent verified the signature and the integration worked as intended.

Note: SonarQube requires new tokens for the service connections after this change. So I updated my connections with a new token by using Azure DevOps APIs.

Get the Medium app

A button that says 'Download on the App Store', and if clicked it will lead you to the iOS App store
A button that says 'Get it on, Google Play', and if clicked it will lead you to the Google Play store