This is the 2nd part of the Jenkins-as-Code series. In this part we will focus on configuring Jenkins through code. The goal is to avoid manual configuration in the UI and instead leverage configuration scripts in a central Github repository which are executed by a Jenkins pipeline.

In the previous part of this series we created a Jenkins docker image with a baked in pipeline for executing configuration scripts and seeding. We now focus on those configuration scripts.

Directory Layout

Lets quickly remind ourselves about the layout of our shared library repository.

shared-library
├── resources
│   ├── config
│   │   ├── auth.groovy
│   │   ├── credentials.groovy
│   │   ├── slack.groovy
│   │   ├── theme.groovy
│   │   ├── sshd.groovy
│   │   ├── github.groovy
│   │   ├── timezone.groovy
│   │   ├── baseURL.groovy
│   │   ├── globalEnvVars.groovy
│   │   ├── globalSharedLibrary.groovy
│   │   └── slaves.groovy
│   ├── init
│   │   └── ConfigurationAndSeedingPipeline.groovy
│   └── jobDSL
└── vars

The configuration scripts reside in resources/config.

Secrets - Setting Credentials in Jenkins

In most cases Jenkins needs credentials such as ssh keys (e.g., deploy keys) or secret IDs (e.g., ClientID and ClientSecret from OAuth Apps). We can mount the credentials as files into our docker container, but we still need to read them into the internal Jenkins credential store.

credentials.groovy:

The above script adds Slack, Github CI User and HashiCorp Vault tokens from local files into Jenkins. Further, it adds user/password credentials for the dockerhub and Github CI user from local files into Jenkins. Last but not least, it adds SSH private keys for a service repository and slave nodes from local files into Jenkins.

Authentication - Configuring Access to Jenkins

Jenkins is a powerful part of our infrastructure. We build and deploy services with it, so we want to limit access. As we host our shared libray on Github we could use Github OAuth to easily authenticate users. In order for that to work we first need to setup an OAuth Application for our Github organization at https://github.com/organizations/<my-org>/settings/applications. This will give us a client_id and a client_secret, which we have to pass to Jenkins in order to connect with Github to verify the user’s identity.

githubOAuth.groovy:

The above script configures the Github OAuth Plugin and gives admin permissions to user fishi0x01 and the members of the Github team my_team_name.

Configuring the Global Shared Library

A global shared library is usable by every job by adding a simple @Pipeline('<lib-name>') annotation (to the Jenkinsfile).

globalSharedLibrary.groovy:

The above script configures git@github.com:<my-org>/<my-shared-library>.git as a global shared library which can be used by every job.

Some General Settings

Lets continue with the configuration of some convenient plugins.

Theme

Lets spice up our Jenkins with a custom UI. We can use the Simple Theme Plugin for that. Further, we can use Afonso F’s theme generator to create a valid Jenkins .css file for this plugin. We should place the generated .css file in the userContent directory of Jenkins in order to be publicly available.

theme.groovy

The above script configures the simple theme plugin to use our generated .css file.

Slack

It is nice to get deploy or build messages send directly to slack.

slack.groovy:

The above script configures the slack plugin. This enables us to use slackSend calls in our pipelines.

Base URL

The base URL setting is very important as it is used to generate the URLs within Jenkins.

baseURL.groovy:

The above script configures the base URL to our domain.

Timezone

Obviously a proper timezone setting is nice in order to not be confused by the build times.

timezone.groovy:

User Public Keys

We can add public keys for users.

user-public-keys.groovy:

Adding a public key to a user is useful if you must interact with jenkins via jenkins-cli. In my experience Jenkins CLI works best when used with the -ssh option.

GitHub

MultiBranch Pipelines are a nice way to build projects. However, they do not work with classic deploy keys. If you host your projects on Github, then an easy way to get your multibranch pipelines running is by using the Github Plugin.

github.groovy:

The above script configures the Github Plugin to connect to Github with a CI user’s token. Of course you have to create that CI user first and give it access to your Github organization.

SSHD

The SSHD setting might become important for you if you try to trigger jobs from the command line on the jenkins master. We will need it in a later part of this series when we try to create a pipeline to bootstrap slaves in different cloud providers.

sshd.groovy:

The above script configures the SSHD port of the Jenkins master.

Global Environment Variables

Global environment variables are visible to every build. That way some general settings can be made visible to all pipelines.

globalEnvVars.groovy:

The above script configures global environment variables.

The Future: Configuration As Code Plugin

Configuring Jenkins with groovy scripts can be tedious. You have to go through the plugin’s code, find the constructor and properly use it in groovy code in order to configure it.

However, in 2018 a new approach arised in the form of a plugin. It is called the configuration-as-code plugin. The goal of this plugin is to describe your jenkins configuration in a single .yml file. The idea looks very promising. I haven’t used this plugin yet, but it seems it reached a rather mature status in September 2018. I recently stopped working on Jenkins topics in order to focus on Information Security Engineering, but once I get back to Jenkins one day I will definitely also have a look at that plugin. Maybe I will also write a blog post about it.

Summary

We now have a fully configured Jenkins. The configuration is part of our shared library. The configuration is executed via a single pre-baked configuration and seeding pipeline which uses our shared library. We can change a configuration by pushing the change to the shared library and running the pre-baked configuration and seeding pipeline in Jenkins.

In the next part of this series we will have a quick look at Jenkins JobDSL plugin for job interfaces as-code.