Can't add cert to latest Scanner CLI Docker image

There is another impact following the switch to scanner-cli (an unprivileged user). It is no longuer possible to add a custom certificate in cacert using keytool.

This case happen when using a custom certificate authority which can be common in a context of a company/enterprise.

1 Like

Hi @xavier

Are you following the documented way using -v ${YOUR_CERTS_DIR}/cacerts:/tmp/cacerts ?

Then you have to be sure the scanner-cli user (1000) has read permission on the cacerts file.

We were able to reproduce. Ticket created, thanks for the feedback.

Good morning,

We are trying this out with version 10.0 which should have the fix mentioned, however keytool is only running under the root user.
We are therefore not able to run the docker image with a dedicated user and we need to run it with the root user.
Is it possible to fix it in the future?

Hey @Paulien_van_Alst

Can you give it a try with 11.0? An entirely new base image is being used in the latest verison.

I am fine with testing it but what is then the way to go with custom certificates?
In version 11 the logic for importing the certificates into the keystore has been removed from the entry point script

Check the docs here, specifically the section If running the scanner with Docker

This does not work, the scanner is not able to use the certificates…
The certificates seem not to be loaded in the Java keystore.
The certificates are placed in /tmp/cacerts/ as indicated in the docs but nothing is done with them

Hey again @Paulien_van_Alst .

As mentioned in the docs, you must build a new Docker image if you want to use your own cacerts trust store.

If running the scanner with Docker

If you need to configure a self-signed certificate for the scanner to communicate with your SonarQube instance, you can use a volume under /tmp/cacerts to add it to the containers java trust store:

docker run \
    --rm \
    -v ${YOUR_CERTS_DIR}/cacerts:/tmp/cacerts \
    -v ${YOUR_CACHE_DIR}:/opt/sonar-scanner/.sonar/cache \
    -v ${YOUR_REPO}:/usr/src \
    -e SONAR_HOST_URL="http://${SONARQUBE_URL}" \
    sonarsource/sonar-scanner-cli`

Then, assuming both the cacerts and Dockerfile are in the current directory, create the new image with a command such as:

docker build --tag our-custom/sonar-scanner-cli

My colleagues (@Joe and @wayne.khan) has shown me a simple example, with a custom Dockerfile based on the sonar-scanner-cli DockerHub page (or its GitHub source):

ARG TAG=11.0.1.1589_6.1.0  # Specify a different tag if needed
FROM sonarsource/sonar-scanner-cli:${TAG}

# Copy a local, known good truststore
COPY cacerts /opt/sonar-scanner/jre/lib/security/cacerts`

Then build the custom sonar-scanner-cli image:

[azureuser@InterviewFirstStage java]$ sudo docker build --tag our-custom/sonar-scanner-cli .
[+] Building 0.7s (7/7) FINISHED                                                                                                                                                                               docker:default
 => [internal] load build definition from Dockerfile                                                                                                                                                                     0.0s
 => => transferring dockerfile: 294B                                                                                                                                                                                     0.0s
 => [internal] load metadata for docker.io/sonarsource/sonar-scanner-cli:11.0.1.1589_6.1.0                                                                                                                               0.0s
 => [internal] load .dockerignore                                                                                                                                                                                        0.1s
 => => transferring context: 2B                                                                                                                                                                                          0.0s
 => [internal] load build context                                                                                                                                                                                        0.1s
 => => transferring context: 161.93kB                                                                                                                                                                                    0.0s
 => [1/2] FROM docker.io/sonarsource/sonar-scanner-cli:11.0.1.1589_6.1.0                                                                                                                                                 0.2s
 => [2/2] COPY cacerts /opt/sonar-scanner/jre/lib/security/cacerts                                                                                                                                                       0.1s
 => exporting to image                                                                                                                                                                                                   0.1s
 => => exporting layers                                                                                                                                                                                                  0.1s
 => => writing image sha256:92b1338867237e1331bf5719d666b8aef4ab554b25c2760af420f028a3cd4c37                                                                                                                             0.0s
 => => naming to docker.io/our-custom/sonar-scanner-cli   `

Then check the contents:

[azureuser@InterviewFirstStage java]$ sudo docker container ls
CONTAINER ID   IMAGE                          COMMAND                  CREATED         STATUS         PORTS     NAMES
87387d5e448d   our-custom/sonar-scanner-cli   "/usr/bin/entrypoint…"   5 seconds ago   Up 4 seconds             great_mayer
[azureuser@InterviewFirstStage java]$ sudo docker exec -ti 87387d5e448d sh
sh-5.2$ cd /opt/sonar-scanner/jre/lib/security
sh-5.2$ ls -la
total 400
dr-xr-xr-x. 1 scanner-cli scanner-cli     21 Sep  2 06:08 .
dr-xr-xr-x. 1 scanner-cli scanner-cli     22 Jun 26 15:33 ..
-r-xr-xr-x. 1 scanner-cli scanner-cli   2488 Apr 17 06:07 blocked.certs
-r--r--r--. 1 root        root        161817 May  1 14:31 cacerts
-r-xr-xr-x. 1 scanner-cli scanner-cli  10129 Apr 17 06:07 default.policy
-r-xr-xr-x. 1 scanner-cli scanner-cli 228598 Apr 17 06:07 public_suffix_list.dat

Note the file size of 161817, which is the size of my own local cacerts. If you don’t modify the container’s cacerts with your own truststore, then the size is different, which indicates that the cacerts was not replaced:

sudo docker run \
    --rm \
    -v /home/azureuser/Projects/jojo-simple:/usr/src \
    -e SONAR_HOST_URL="https://your-own-SQ-URL" \
    sonarsource/sonar-scanner-cli:11.0.1.1589_6.1.0 sleep infinity

In another window

[azureuser@InterviewFirstStage jojo-simple]$ sudo docker exec -ti 0689d90a44b3 sh
sh-5.2$  ls -la /opt/sonar-scanner/jre/lib/security/cacerts 
-r-xr-xr-x. 1 scanner-cli scanner-cli 171578 Apr 17 06:07 /opt/sonar-scanner/jre/lib/security/cacerts`

I hope this helps.

Colin

2 Likes

Hi Colin,

that is a very unfortunate change and the solution is still unsatisfactory. Maintaining our own image is not too much of an issue, but this used to be so simple…

I’ve tried the following as part of a GitLab CI pipeline and this still failed:

keytool -noprompt -importcert -alias testfabrik -keystore $JAVA_HOME/lib/security/cacerts -storepass changeit -file /etc/ssl/certs/tf/tf.crt
cp $JAVA_HOME/lib/security/cacerts /tmp/cacerts

Also trying what you suggested (with the custom image): there is no folder /opt/sonar-scanner/jre/ in docker.io/sonarsource/sonar-scanner-cli:11.1.0.1640_6.2.0

Hey @bo0ts

Thanks for the feedback. As I understand it, we are going to try and make it easier for users again.

Hi @bo0ts

I am not very familiar with GitLab, but from what I have seen, the previous recommended way was to use our Scanner Docker CLI image, but without the default entrypoint being used (seems to be a documented approach in GitLab). Something like:

sonarqube-check:
  image:
    name: sonarsource/sonar-scanner-cli:latest
    entry point: [""]
  variables:
    SONAR_USER_HOME: "${CI_PROJECT_DIR}/.sonar"  # Defines the location of the analysis task cache
  script:
    - sonar-scanner -Dsonar.qualitygate.wait=true

so to import your self-signed certificate, you were basically on your own, because our “logic” is in our entrypoint.sh.

Your previous logic was probably to import the certificate in the JVM cacerts since the image was run with a root user. But with 10+ versions of the image, we are now running with a non-root user. We also changed the OS from Alpine to AmazonLinux, so the JVM cacerts location has changed.

Anyway, we are trying to move away from any Java-specific configuration, so going forward, the preferred way to configure SSL is to rely on the SonarScanner-specific truststore location.

Try something like:

sonarqube-check:
  image:
    name: sonarsource/sonar-scanner-cli:11
    entrypoint: [""]
  variables:
    SONAR_USER_HOME: "${CI_PROJECT_DIR}/.sonar"  # Defines the location of the analysis task cache
    SONAR_SCANNER_OPTS: "-Djavax.net.ssl.trustStore=${SONAR_USER_HOME}/ssl/truststore.p12 -Djavax.net.ssl.trustStorePassword=changeit"  # only needed for SQ versions < 10.6
  script:
    - keytool -noprompt -importcert -storetype PKCS12  -alias testfabrik -keystore $SONAR_USER_HOME/ssl/truststore.p12 -storepass changeit -file /etc/ssl/certs/tf/tf.crt
    - sonar-scanner -Dsonar.qualitygate.wait=true -Dsonar.scanner.truststorePassword=changeit

Let me know how it goes, I am curious to see if this is working fine for you. If not, please share your previous way to configure SSL, and your SonarQube version, this would be helpful for me to better understand the GitLab use cases.

Would it be possible to simply include sudo permissions in the image? I’m in the same boat: prior versions ran as root, and the JDK’s cacerts file was under the root:root ownership. We are using GitLab CI/CD, and my first approach was to simply update my Sonar job in the pipeline to sudo to root and run the keytool import of my CA.

Unfortunately sudo is not available and I, too, do not want to maintain a custom image.

Hi @keithwegner

We changed from root to a regular user to decrease the attack surface. I don’t know if allowing sudo would not defeat this purpose, but I will ask my colleagues

In the meantime, would you mind trying the latest image + my suggesting to put the certificate in a pkcs12 truststore in ${SONAR_USER_HOME}/ssl/truststore.p12
This should not be much more effort than the previous way, and much more future proof.

With the latest release of the Scanner Docker image, it should be possible to simplify even more the SSL config, because SONAR_SCANNER_OPTS is not needed anymore:

sonarqube-check:
  image:
    name: sonarsource/sonar-scanner-cli:11
    entrypoint: [""]
  variables:
    SONAR_USER_HOME: "${CI_PROJECT_DIR}/.sonar"  # Defines the location of the analysis task cache
  script:
    - keytool -noprompt -importcert -storetype PKCS12  -alias sonarqube -keystore $SONAR_USER_HOME/ssl/truststore.p12 -storepass changeit -file /where/is/server.crt_or_pem
    - sonar-scanner -Dsonar.qualitygate.wait=true -Dsonar.scanner.truststorePassword=changeit

Hi, has the solution to this evolved?

using the code above I get the error:

The certificate was added to keystore
keytool error: java.io.FileNotFoundException: /builds/myuser/projectfolder/.sonar/ssl/truststore.p12 (No such file or directory)

Sorry, maybe you need to create the directory first:

sonarqube-check:
  image:
    name: sonarsource/sonar-scanner-cli:11
    entrypoint: [""]
  variables:
    SONAR_USER_HOME: "${CI_PROJECT_DIR}/.sonar"  # Defines the location of the analysis task cache
  script:
    - mkdir -p $SONAR_USER_HOME/ssl
    - keytool -noprompt -importcert -storetype PKCS12  -alias sonarqube -keystore $SONAR_USER_HOME/ssl/truststore.p12 -storepass changeit -file /where/is/server.crt_or_pem
    - sonar-scanner -Dsonar.qualitygate.wait=true -Dsonar.scanner.truststorePassword=changeit

hi @Julien_HENRY ,

i’ve encountered this thread after struggling with the same issue myself.
we are working in an air-gapped environment, and have our own private certificates.
we were able to add the certificate manually to the sonarsource/sonar-scanner-cli:10.0.3.1430_5.0.1 docker image, we are failing to do so using the following image: sonarsource/sonar-scanner-cli:11.1.1.1661_6.2.1.

as mentioned before, we are also strongly against creating our own manipulated image based on your image.

is there any other suggestion you can offer us?
we are using jenkins as ci system.

i am able to provide any other needed information, if it will help.

thanks.

Hi @amidar

Have you tried the last mentioned option? All recent scanners should pick-up certificates stored in a pkcs12 truststore, that you should save in the $SONAR_USER_HOME/ssl/truststore.p12 location.