Jenkins Lesson 37 – Configuration as Code | Dataplexa
Section IV · Lesson 37

Configuration as Code (JCasC)

Lesson 36 put pipelines and jobs into code. This lesson puts the Jenkins master itself into code — its security settings, credentials, agents, plugin configuration, and global environment variables, all in a single human-readable YAML file.

This lesson covers

What JCasC is → Installing the plugin → The jenkins.yaml file → Configuring security, credentials, agents, and tools → Applying config at startup → Exporting existing config → The full reproducible Jenkins setup

The Jenkins Configuration as Code (JCasC) plugin is the missing piece in the Jenkins-as-code story. Jenkinsfiles describe what pipelines do. Job DSL describes which jobs exist. JCasC describes what the Jenkins master is — its identity, its security model, its connections, its tools. Together, these three layers mean a Jenkins server that can be rebuilt from scratch in minutes from Git.

The Analogy

JCasC is like a recipe for the Jenkins server itself. Lesson 27's plugins.txt is the ingredients list. JCasC is the cooking instructions — exactly how to combine and configure everything. Give someone the recipe and the ingredients and they can produce an identical Jenkins server anywhere, anytime, without clicking a single button.

What JCasC Can Configure

Security

  • Authentication realm
  • Authorisation strategy
  • CSRF protection
  • Agent security

Credentials

  • Username/password
  • SSH private keys
  • Secret text / tokens
  • Certificates

Agents & Clouds

  • Static SSH agents
  • Kubernetes cloud config
  • Docker cloud config
  • Agent labels and executors

Global Settings

  • Jenkins URL
  • System message
  • Admin email
  • Environment variables

Tools

  • JDK installations
  • Maven versions
  • Node.js versions
  • Git configuration

Pipeline Libraries

  • Global shared libraries
  • Library Git URLs
  • Default versions
  • Allow overrides

Setting Up JCasC

Install the Configuration as Code plugin (plugin ID: configuration-as-code) from Manage Jenkins → Plugin Manager. After installing, a new item appears at Manage Jenkins → Configuration as Code. By default, Jenkins looks for a jenkins.yaml file at the path set in the CASC_JENKINS_CONFIG environment variable — or at $JENKINS_HOME/jenkins.yaml if the variable isn't set.

Writing a Complete jenkins.yaml

The scenario:

You're a platform engineer building a new Jenkins instance for your company's EU infrastructure team. Rather than clicking through the setup wizard and manually configuring security, agents, credentials, and the shared library, you want to define everything in a jenkins.yaml file that lives in Git. When Jenkins starts, it reads this file and configures itself automatically.

New terms in this code:

  • jenkins: block — the top-level key in jenkins.yaml for global Jenkins settings — system message, URL, security realm, authorisation strategy.
  • securityRealm — configures authentication. local means Jenkins' own user database. ldap, github, or saml configure external auth providers.
  • authorizationStrategy — configures what authenticated users can do. Uses the same strategies as Lesson 28 and 29, expressed as YAML instead of Groovy.
  • credentials: block — defines all stored credentials. In production, secret values come from environment variables (${ENV_VAR}) rather than being hardcoded — this keeps secrets out of Git while still defining the credential structure.
  • unclassified: block — configuration for plugins that don't fit under the standard top-level keys. Shared library registration and Slack configuration live here.
  • CASC_JENKINS_CONFIG — the environment variable that tells Jenkins where to find the YAML file. Set this in the Jenkins service config or Docker environment.
# jenkins.yaml — complete JCasC configuration for acmecorp EU Jenkins
# Store in Git. Set CASC_JENKINS_CONFIG=/path/to/jenkins.yaml on startup.
# Secret values use ${ENV_VAR} syntax — never hardcode secrets in this file.

jenkins:
  systemMessage: "Acmecorp EU Jenkins — managed by JCasC. Do not configure manually."
  numExecutors: 0             # master runs zero builds — agents only
  mode: NORMAL
  remotingSecurity:
    enabled: true             # agent-to-master security

  # Authentication — Jenkins' own user database
  securityRealm:
    local:
      allowsSignup: false     # no self-registration — admin creates accounts
      users:
        - id: "admin"
          name: "Jenkins Admin"
          password: "${JENKINS_ADMIN_PASSWORD}"   # from environment variable

  # Authorisation — matrix-based, developers can build, admin can administer
  authorizationStrategy:
    globalMatrix:
      permissions:
        - "hudson.model.Hudson.Administer:admin"
        - "hudson.model.Hudson.Read:authenticated"
        - "hudson.model.Item.Build:authenticated"
        - "hudson.model.Item.Read:authenticated"
        - "hudson.model.Item.Cancel:authenticated"

  # CSRF protection — always on
  crumbIssuer:
    standard:
      excludeClientIPFromCrumb: false

  # Static build agents
  nodes:
    - permanent:
        name: "agent-linux-eu-01"
        labelString: "linux docker eu-west"
        numExecutors: 4
        remoteFS: "/var/jenkins-agent"
        launcher:
          ssh:
            host: "10.0.2.10"
            port: 22
            credentialsId: "agent-linux-ssh-key"
            launchTimeoutSeconds: 60

    - permanent:
        name: "agent-linux-eu-02"
        labelString: "linux docker eu-west"
        numExecutors: 4
        remoteFS: "/var/jenkins-agent"
        launcher:
          ssh:
            host: "10.0.2.11"
            port: 22
            credentialsId: "agent-linux-ssh-key"
            launchTimeoutSeconds: 60

# Global credentials — secrets injected from environment variables at startup
credentials:
  system:
    domainCredentials:
      - credentials:
          - usernamePassword:
              id: "docker-registry-credentials"
              description: "Docker registry push credentials"
              username: "${DOCKER_REGISTRY_USER}"
              password: "${DOCKER_REGISTRY_PASS}"
              scope: GLOBAL

          - basicSSHUserPrivateKey:
              id: "agent-linux-ssh-key"
              description: "SSH key for Linux build agents"
              username: "jenkins-agent"
              privateKeySource:
                directEntry:
                  privateKey: "${AGENT_SSH_PRIVATE_KEY}"
              scope: GLOBAL

          - string:
              id: "slack-webhook-url"
              description: "Slack incoming webhook URL"
              secret: "${SLACK_WEBHOOK_URL}"
              scope: GLOBAL

          - string:
              id: "github-token"
              description: "GitHub API token for repo scanning"
              secret: "${GITHUB_TOKEN}"
              scope: GLOBAL

# Plugin-specific configuration lives in unclassified
unclassified:

  # Jenkins URL — used in build notifications and links
  location:
    url: "https://jenkins-eu.acmecorp.com/"
    adminAddress: "jenkins-admin@acmecorp.com"

  # Register the shared library so all Jenkinsfiles can use @Library('acme-pipelines')
  globalLibraries:
    libraries:
      - name: "acme-pipelines"
        defaultVersion: "main"
        allowVersionOverride: true
        implicit: false
        retriever:
          modernSCM:
            scm:
              git:
                remote: "https://github.com/acmecorp/acme-pipeline-library.git"
                credentialsId: "github-token"

  # Slack global configuration
  slackNotifier:
    teamDomain: "acmecorp"
    tokenCredentialId: "slack-webhook-url"
    room: "#deployments"

Where to practice: Install the configuration-as-code plugin. Go to Manage Jenkins → Configuration as Code → Download Configuration to export your current Jenkins config as YAML — that's the fastest way to see the correct syntax for your specific setup. Then modify it and reload via Apply new configuration. Full reference at jenkins.io/projects/jcasc.

# Jenkins startup log with JCasC:
INFO: CASC_JENKINS_CONFIG=/etc/jenkins/jenkins.yaml
INFO: Configuration as Code loaded from /etc/jenkins/jenkins.yaml

Applying JCasC configuration...
  ✓ jenkins.systemMessage set
  ✓ jenkins.numExecutors set to 0
  ✓ securityRealm: local (1 user configured)
  ✓ authorizationStrategy: globalMatrix (5 permissions)
  ✓ crumbIssuer: standard CSRF protection enabled
  ✓ nodes: agent-linux-eu-01 added (labels: linux docker eu-west)
  ✓ nodes: agent-linux-eu-02 added (labels: linux docker eu-west)
  ✓ credentials: docker-registry-credentials created
  ✓ credentials: agent-linux-ssh-key created
  ✓ credentials: slack-webhook-url created
  ✓ credentials: github-token created
  ✓ unclassified.location.url set
  ✓ globalLibraries: acme-pipelines registered
  ✓ slackNotifier configured

Configuration applied successfully — 14 items configured.
Jenkins is fully up and running.

What just happened?

  • 14 configuration items applied on startup — security realm, authorisation strategy, CSRF, two agents, four credentials, Jenkins URL, shared library, and Slack — all from a single YAML file. What would take 20–30 minutes of UI clicking happened automatically before the first developer logged in.
  • No secrets in Git — every secret value uses ${ENV_VAR} syntax. Jenkins reads the actual value from the server's environment at startup. The YAML file is safe to commit to a private repository — it contains structure and credential IDs, not passwords or tokens.
  • Shared library registered automatically — the acme-pipelines library is available to all Jenkinsfiles from the first build. Teams don't need to ask an admin to register their library — it's part of the standard config.
  • If Jenkins dies and needs to be rebuilt — restore jenkins.yaml from Git, start Jenkins with the JCasC plugin and the right environment variables. Every configuration setting is restored. Combined with plugins.txt (Lesson 27) and a job DSL seed job (Lesson 36), a complete Jenkins rebuild takes minutes, not hours.
  • Configuration drift is impossible — if someone manually changes a setting through the UI, applying the YAML again resets it to the desired state. JCasC is the authoritative source of truth for the Jenkins master configuration.

Exporting Your Current Configuration

You don't have to write the YAML from scratch. Jenkins can export its current configuration as a JCasC YAML file — the fastest way to start using JCasC on an existing Jenkins instance.

1

Manage Jenkins → Configuration as Code → Download Configuration

Jenkins generates a complete jenkins.yaml representing every current setting. Download it.

2

Replace hardcoded secrets with ${ENV_VAR} references

The exported YAML may contain placeholder strings where secrets were. Replace them with environment variable references before committing to Git.

3

Commit to Git and set CASC_JENKINS_CONFIG

Store the file in your infrastructure repository. Configure Jenkins to read it on startup via the environment variable. Test by rebuilding a staging Jenkins from scratch.

Use "Apply new configuration" for live updates

Once JCasC is set up, you can apply configuration changes without restarting Jenkins by clicking Apply new configuration in the JCasC UI — or via the CLI/API for automation.

The Complete Jenkins-as-Code Stack

Layer Tool What it defines Lesson
Plugins plugins.txt + Dockerfile Which plugins are installed and at what version 27
Master config jenkins.yaml (JCasC) Security, credentials, agents, tools, libraries 37
Jobs Job DSL seed job Which jobs exist, their folders, branch sources 36
Shared logic Shared library repo Reusable pipeline functions: build, deploy, notify 36
Pipelines Jenkinsfile What each service's CI/CD pipeline does Section II

Teacher's Note

The export-first approach is the fastest path to JCasC on an existing server. Click "Download Configuration", replace secrets with environment variables, commit to Git. You now have a reproducible Jenkins — before writing a single line of YAML from scratch.

Practice Questions

1. Which environment variable tells Jenkins where to find the JCasC YAML file on startup?



2. In a jenkins.yaml file, what syntax is used to reference a secret value from the server's environment rather than hardcoding it in the file?



3. In jenkins.yaml, under which top-level key does plugin-specific configuration (such as shared library registration and Slack settings) live?



Quiz

1. An admin manually changes a security setting through the Jenkins UI. The JCasC YAML still has the original setting. What happens when JCasC configuration is re-applied?


2. What is the fastest way to start using JCasC on an existing Jenkins instance that was configured through the UI?


3. What combination of files allows a complete Jenkins server to be rebuilt from scratch with all plugins, configuration, jobs, and pipelines restored?


Up Next · Lesson 38

Mini Project — End-to-End CI/CD Pipeline

Everything comes together. Build a production-grade pipeline from scratch using all the tools, patterns, and best practices from this course — in one complete real-world project.