CI for the cheapskates – part 2 – Security

In the previous post, we’ve described the way to set up CI pipeline with Maven repository with minimal cost. Now we continue down this road to improve security and reliability of this setup.

So far, our Maven repository is available through HTTP, but the problem is that anyone can access it. We want to restrict access to this repository to authorized users only. To support this, we will set up password-based authentication for users, and use SSL to secure connection and credentials transport.

Setting up SSL

First order of business is to set up SSL, so our repository can only be access through HTTPS. There are two parts of this setup: creating SSL certificate and configuring Nginx to use it for HTTPS connections.

Creating SSL certificate

Before setting up HTTPS, we need to obtain SSL certificate. Since we are cheapskates (see post title), we will create self-signed certificate for this. Another option is to get valid SSL certificate from Certificate Authority, but self-signed will have to do for now. Before this step, make sure you have OpenSSL installed in your system. Create the certificate using the following commands:

First, we create a directory which will hold SSL certificates. The next command will create the certificate for repository. The options we supply are the following:

  • req  – specifies that we want to use X.509 Certificate Signing Request (CSR)
  • -x509  – specifies that we want to create self-signed certificate instead of generating CSR
  • -nodes  – skip securing certificate with passphrase
  • -days  – number of days this certificate will be valid
  • -newkey rsa:2048  – specifies that we want to generate new certificate and new key at the same time
  • -keyout  – location where to place the generated key
  • -out  – location where to place generated certificate

When you enter this command, you will be prompted to answer some questions, and then new certificate will be generated.

Configuring Nginx to use certificate

In the previous post, we configured Nginx to serve our repository through plain HTTP. Now, we will modify it to force HTTPS connection.  Modify the file to look like this:

There are few lines we added here. In line 2, we tell the server to listen for SSL requests on port 443 (default HTTPS port). In lines 6-7, we specify SSL certificate to use for SSL connections. Note that these paths refer to files we generated in previous step.

In lines 10-12, we add a rule which will redirect all HTTP traffic to HTTPS. This will cause all requests to http://mysite , to be redirected to https://mysite , forcing the use of HTTPS protocol.

You can now try accessing your repository artifacts from the browser. If you enter HTTP URL,  it should redirect you to HTTPS. Note that, since we are using self-signed certificate, your browser will show a warning that certificate is not trusted. You should add exception for this case.

Accessing repository from Maven over HTTPS

If everything went OK, you should have  your repository running correctly over HTTPS. But, if you try to run Maven build, it will probably fail, complaining about not being able to find valid certification path. This is because we used self-signed certificate, and JVM does not have it in it’s trusted keystore. There are 2 ways we can resolve this:

  • add certificate to keystore on development machine
  • tell Maven to allow untrusted certificates

Here, we will use option 2. We will invoke Maven with the following configuration properties:

To avoid typing these parameters every time, we can create .mavenrc file in home directory, and add the following in it:

Restrict access to unauthorized users

The final step in securing our repository is to allow only authorized users to access. Right now, we have SSL, but anybody can get our  repository artifacts. We will enable password authentication for accessing repository.

First, we need to create a password file which will hold usernames and their respective passwords. We will create hidden file /etc/nginx/.mvnrepo_pswd . Then, we will use OpenSSL tools to add users and encrypted passwords to this file. In this example, we will add user mvnuser :

The first command will add a user, and next one will add encrypted password for that user. It will prompt you for the password. After that, we need to change Nginx configuration to enable authentication. Change you Nginx config file to look like this:

As you can see, the only difference compared to previous version is that we added two lines which define authentication realm (first line) and passwords file (second line). If you now try to download an artifact from repository using your browser, you should get a login dialog prompting you for username and password.

Add login info to Maven

If you now try to build your Maven project, you will get an error saying that access is unauthorized. We need to specify username and password which Maven will use when accessing the repository. This information should be added to settings.xml  file in your local Maven repository. Add the following to the <servers>  section:

Here, element <id>  must match the ID under which repository is declared in your POM file. Now, you should be able to build your project and download all dependencies.

Bonus points – purge snapshots

As you work on your projects, you will inevitably be deploying many SNAPSHOT versions to repository. Over time, this will incur big storage costs. Since SNAPSHOT versions are usually short lived, you can safely remove old versions to save space. We can create simple shell script to purge old SNAPSHOTS.

Create a file called /usr/bin/repo-purge  with the following content (this is inspired by this Github gist):

This script will find all files in REPO  directory older then AGE  days, which contain SNAPSHOT in name. It will delete these files and then remove empty directories. In order to automate things, add this script to Cron job table, so it executes periodically. Don’t forget to set executable flags for the script.

 

References

 

Leave a Reply

Your email address will not be published. Required fields are marked *