Run Jenkins with Docker
Run Pomerium with Docker Compose to secure your Jenkins application with JWT authentication and custom claims.
What is Jenkins?
Jenkins is an automation server you can use to build, test, and deploy applications.
Why use Pomerium with Jenkins?
You can set up role-based permissions in Jenkins to control a user’s privileges with Jenkins’ built-in authorization matrix. However, this method requires a username and password to sign in and relies on Jenkins’ user database to store credentials.
JWT authentication is a more secure method of identity verification that authenticates and authorizes users against an identity provider, eliminating the need to store or share credentials to access your Jenkins application.
Jenkins doesn’t support JWT authentication out of the box. With Pomerium, you can implement JWT authentication and apply claims to your route’s authorization policy to determine a user’s role and privileges before granting a user access to Jenkins.
Once you’ve configured JWT authentication, you can assign permissions within Jenkins for a specific user, any authenticated user, anonymous users, or a user group.
Before you begin
To complete this guide, you need:
- Docker and Docker Compose
- An identity provider (IdP)
If you haven’t, complete the Pomerium Core quickstart to familiarize yourself with running Pomerium in a container environment.
Pomerium Enterprise customers can complete the Enterprise quickstart using Docker containers as well.
Run Jenkins with Docker Compose
- Core
- Enterprise
Create a project and add a file called docker-compose.yaml
.
In the docker-compose.yaml
file, add the following code:
jenkins:
networks:
main: {}
image: jenkins/jenkins:lts-jdk11
privileged: true
user: root
ports:
- 8080:8080
- 50000:50000
volumes:
# File path to Jenkins_home -- stores configs, build logs, and artifacts
- ./home/jenkins_compose/jenkins_configuration:/var/jenkins_home
# "sock" is the Unix socket the Docker daemon listens on by default
- ./var/run/docker.sock:/var/run/docker.sock
Run docker compose up
.
Set up your Jenkins instance
If your Jenkins container is set up correctly, the Setup Wizard will guide you through several prompts before you can access your dashboard.
To set up your Jenkins instance:
- Go to
localhost:8080
and enter the admin user password to continue
You can find the admin user password in your Docker logs or in /var/jenkins_home/secrets/initialAdminPassword
.
- Install the suggested plugins
- Create an admin user
You can create your first admin user or select Skip and continue as admin. If you skip and continue as admin, the default username is admin and the password is the admin user password.
- In the Instance Configuration window, accept the default hostname
After completing the Setup Wizard prompts, you can access the Jenkins dashboard.
Run docker compose stop
so you can configure Pomerium.
Configure Pomerium
Create a Pomerium configuration file
In your project’s root folder, create a config.yaml
file.
In your config.yaml
file, add the following code:
authenticate_service_url: https://authenticate.localhost.pomerium.io
idp_provider: REPLACE_ME
idp_provider_url: REPLACE_ME
idp_client_id: REPLACE_ME
idp_client_secret: REPLACE_ME
signing_key: REPLACE_ME
routes:
- from: https://verify.localhost.pomerium.io
to: http://verify:8000
pass_identity_headers: true
policy:
- allow:
and:
email:
is: user@example.com
- from: https://jenkins.localhost.pomerium.io
to: http://jenkins:8080/
host_rewrite_header: true
pass_identity_headers: true
policy:
- allow:
and:
- domain:
is: example.com
- user:
is: username
Next, you need to:
- Update the identity provider configuration variables with your own
- Replace
user@example.com
with the email associated with your IdP - Replace
example.com
with your organization’s domain name - Replace
username
with the username associated with your IdP - Generate a signing key
To generate a signing key, use the commands below:
# Generates a P-256 (ES256) signing key
openssl ecparam -genkey -name prime256v1 -noout -out ec_private.pem
# Prints the base64 encoded value of the signing key
cat ec_private.pem | base64
Add the base64-encoded signing key to the signing_key
variable in your config.yaml
file.
Run Pomerium services with Docker Compose
In your docker-compose.yaml
file, replace the code in the file with the Pomerium and Jenkins services below:
version: '3'
networks:
main: {}
services:
pomerium:
image: pomerium/pomerium:latest
volumes:
- ./config.yaml:/pomerium/config.yaml:ro
ports:
- 443:443
networks:
main:
aliases:
- authenticate.localhost.pomerium.io
verify:
networks:
main: {}
image: pomerium/verify:latest
expose:
- 8000
jenkins:
networks:
main: {}
image: jenkins/jenkins:lts-jdk11
privileged: true
user: root
ports:
- 8080:8080
- 50000:50000
volumes:
# File path to Jenkins_home -- stores configs, build logs, and artifacts
- ./home/jenkins_compose/jenkins_configuration:/var/jenkins_home
# "sock" is the Unix socket the Docker daemon listens on by default
- ./var/run/docker.sock:/var/run/docker.sock
Run docker compose up
and navigate to the external Jenkins route at https://jenkins.localhost.pomerium.io
.
Jenkins will prompt you to sign in with your username and password.
Sign in to continue to the Jenkins dashboard.
This guide assumes you can access the Enterprise Console.
First, add Jenkins to the same docker-compose
file running your Pomerium Core, Console, and PostgreSQL services:
jenkins:
networks:
main: {}
image: jenkins/jenkins:lts-jdk11
privileged: true
user: root
ports:
- 8080:8080
- 50000:50000
volumes:
# File path to Jenkins_home -- stores configs, build logs, and artifacts
- ./home/jenkins_compose/jenkins_configuration:/var/jenkins_home
# "sock" is the Unix socket the Docker daemon listens on by default
- ./var/run/docker.sock:/var/run/docker.sock
In your Enterprise Console, create a policy:
- Give your policy a name (for example, Jenkins Admin), then select the Builder tab
- Select ADD ALLOW BLOCK, then select the + icon to add an AND operator
- In the Criteria field, select Email
- In the Value field, enter the email address associated with your IdP
Save your policy.
Create an external route to access Jenkins:
- Name your route and enter the external route in the from: field
- Enter the scheme and hostname in the to: field
- In the Policies field, select the policy you built for Jenkins
- Select Pass Identity Headers
Configure your route to rewrite the host header:
- Select Headers from the sidebar
- In the Host Headers dropdown, select Rewrite to Header
- In the Host Rewrite to Header field, enter the external route without the protocol
Save your route.
Set up your Jenkins instance
- Go to your external Jenkins route and enter the admin user password to continue
You can find the admin user password in your Docker logs or in /var/jenkins_home/secrets/initialAdminPassword
.
- Install the suggested plugins
- Create an admin user
You can create your first admin user or select Skip and continue as admin. If you skip and continue as admin, the default username is admin and the password is the admin user password.
- In the Instance Configuration window, accept the default hostname
After completing the Setup Wizard prompts, you can access the Jenkins dashboard.
Install Jenkins plugins
Next, you need to add plugins to enable JWT authentication and bypass TLS validation.
Install the JWT Auth plugin:
- Select Manage Jenkins
- Under System Configuration, select Manage Plugins
- Select Available Plugins
- In the search bar, enter JWT Auth
- Select the JWT Auth plugin and Install without restart
Install the skip-certificate-check plugin:
- Select Available Plugins
- In the search bar, enter skip-certificate-check
- Select the skip-certificate-check plugin and Install without restart
Once you’ve installed both plugins, stop your containers (you don't need to stop your containers if you're using the Enterprise Console).
Configure JWT authentication
Go to your external Jenkins route.
To configure JWT authentication:
- Go to Manage Jenkins
- Under Security, select Configure Global Security
- Under Authentication > Security Realm, select JWT Header Authentication Plugin
Under Global JWT Auth Settings, you’ll see form fields where you can enter JWT claims. Pomerium forwards a user’s associated identity information in a signed attestation JWT that’s included in upstream requests in an X-Pomerium-Jwt-Assertion
header.
With the JWT Auth plugin installed, Jenkins can receive and parse the assertion header to authenticate users – you just need to give it the right instructions to find the header and JWT claims.
Enter the following information in the Global JWT Auth Settings field:
Field | Value |
---|---|
Header name | x-pomerium-jwt-assertion |
Username claim name | name or email |
Groups claim name | groups |
Groups claim list seperator | , |
Email claim name | email |
Acceptable issuers | authenticate.corp.example.com |
Acceptable audiences | jenkins.corp.example.com |
JWKS JSON URL | https://jenkins.corp.example.com/.well-known/pomerium/jwks.json |
Note the following details about the fields above:
- Username claim name can be either your name or email
- Acceptable issuers must be the URL of the authentication domain that issued the JWT. The
iss
claim tells the target application who the issuing authority is and provides context about the subject. - Acceptable audiences must be the URL of the target application. The
aud
claim defines what application the JWT is intended for. - JWKS JSON URL appends
/.well-known/pomerium/jwks.json
to the external route URL. The JWKS endpoint provides Jenkins the user’s public key to verify their JWT signature.
Go to the external verify
route defined in your policy to view your JWT claims.
In the Authorization dropdown, configure Jenkins permissions so that Anonymous has Administer privileges.
- Select Matrix-based security
- Under Overall, assign Administer to Anonymous and Authenticated Users
If JWT authentication doesn't authenticate you successfully, Jenkins will sign you in as an anonymous user. With administer privileges, you can troubleshoot JWT settings as an anonymous user and try again.
Select save to apply the security settings.
Test JWT authentication
Restart your container. If the JWT authentication worked, you will see your name in the dashboard instead of admin. To see more details about the request, add /whoAmI
to the URL. For example, https://jenkins.localhost.pomerium.io/whoAmI
.
Update your Jenkins authorization settings
Now, you can configure your Jenkins authorization settings:
- Select Matrix-based security
- Select Add user… and enter the name or email associated with your IdP (the value depends on what claim you entered for Username claim name)
Assign yourself Administer privileges and whatever privileges seem appropriate to Authenticated Users and Anonymous users.
Select save to apply the security changes.
Next steps: Add more context to your policies
You can adjust the authorization policy within Jenkins to limit or broaden what privileges authenticated and anonymous users have, but you can also extend your authorization policies with Pomerium.
For example:
- You can build a policy that only allows users to access Jenkins at certain times of day or days of the week, or limit access to certain devices
- You can import custom groups claims from your IdP and only allow access to members of the group