Skip main navigation
/user/kayd @ karandeepsingh.ca :~$ cat jenkins-configuration-as-code-jcasc-guide.md

Jenkins Configuration as Code: The Definitive JCasC Guide Jenkins Configuration as Code: The Definitive JCasC Guide

QR Code linking to: Jenkins Configuration as Code: The Definitive JCasC Guide
Karandeep Singh
Karandeep Singh
• 9 minutes

Summary

Learn how to manage your entire Jenkins setup through version-controlled YAML files using Jenkins Configuration as Code (JCasC), with practical examples for Kubernetes, security, and shared libraries.

Why Jenkins Configuration as Code Matters

If you have ever spent hours clicking through the Jenkins UI to configure a new controller, only to realize you cannot reproduce that setup reliably, Jenkins Configuration as Code (JCasC) is the answer. JCasC lets you define your entire Jenkins configuration in human-readable YAML files that live in version control alongside your application code.

The Jenkins Configuration as Code plugin transforms how teams manage their CI/CD infrastructure. Instead of brittle Groovy init scripts or manual UI clicks, you declare your desired state in YAML and JCasC applies it automatically. Every security setting, cloud configuration, credential, and plugin setting becomes auditable, reproducible, and reviewable through pull requests.

Getting Started with JCasC

Installing the Plugin

The Configuration as Code plugin is available from the Jenkins Update Center. Install it like any other plugin:

  1. Navigate to Manage Jenkins > Manage Plugins > Available
  2. Search for “Configuration as Code”
  3. Install and restart Jenkins

Alternatively, if you are deploying Jenkins via Docker or Helm, include configuration-as-code in your plugin list from the start.

Your First JCasC File

Create a file called jenkins.yaml and place it where Jenkins can find it. By default, JCasC looks at the path defined by the CASC_JENKINS_CONFIG environment variable.

jenkins:
  systemMessage: "This Jenkins is fully configured via JCasC"
  numExecutors: 0
  mode: EXCLUSIVE

  securityRealm:
    local:
      allowsSignup: false
      users:
        - id: "admin"
          password: "${JENKINS_ADMIN_PASSWORD}"

  authorizationStrategy:
    globalMatrix:
      permissions:
        - "Overall/Administer:admin"
        - "Overall/Read:authenticated"

This simple configuration sets a system message, disables builds on the controller node (a security best practice), creates a local admin user with an environment variable for the password, and applies a basic authorization matrix.

Applying the Configuration

Set the environment variable and start Jenkins:

export CASC_JENKINS_CONFIG=/var/jenkins_home/casc_configs/jenkins.yaml
export JENKINS_ADMIN_PASSWORD=your-secure-password

JCasC applies the configuration on startup. You can also reload it without restarting by navigating to Manage Jenkins > Configuration as Code > Reload existing configuration.

Structuring JCasC for Production

Splitting Configuration into Multiple Files

For production environments, a single monolithic YAML file becomes unwieldy fast. JCasC supports pointing CASC_JENKINS_CONFIG to a directory, and it merges all YAML files it finds.

A recommended structure:

casc_configs/
├── jenkins.yaml          # Core settings, executors, mode
├── security.yaml         # Auth, RBAC, CSRF, agent protocols
├── credentials.yaml      # Credentials and secrets
├── clouds.yaml           # Kubernetes/Docker cloud agents
├── shared-libraries.yaml # Global pipeline libraries
└── tool-installations.yaml # JDK, Maven, Node, Git

This separation makes changes reviewable. A security change only touches security.yaml. Adding a new cloud agent only touches clouds.yaml. Your pull request diffs stay clean and focused.

    graph TD
    A[casc_configs/] --> B[jenkins.yaml]
    A --> C[security.yaml]
    A --> D[credentials.yaml]
    A --> E[clouds.yaml]
    A --> F[shared-libraries.yaml]
    A --> G[tool-installations.yaml]
    B --> H[JCasC Plugin]
    C --> H
    D --> H
    E --> H
    F --> H
    G --> H
    H --> I[Jenkins Controller]
  

Managing Secrets Securely

Never put plain-text secrets in your JCasC files. The plugin supports variable substitution from multiple sources:

Environment Variables (most common):

credentials:
  system:
    domainCredentials:
      - credentials:
          - usernamePassword:
              id: "github-creds"
              username: "${GITHUB_USERNAME}"
              password: "${GITHUB_TOKEN}"

AWS Secrets Manager (for cloud deployments):

credentials:
  system:
    domainCredentials:
      - credentials:
          - string:
              id: "sonar-token"
              secret: "${AWS_SECRET:/jenkins/sonar-token}"

Kubernetes Secrets (when deployed on K8s): Mount secrets as environment variables in your Jenkins pod spec, and JCasC resolves them automatically.

JCasC with Kubernetes

Configuring the Kubernetes Cloud Plugin

One of the most powerful JCasC use cases is configuring Jenkins to dynamically provision build agents as Kubernetes pods. This eliminates permanently running agent VMs and lets your CI/CD scale to zero when idle.

jenkins:
  clouds:
    - kubernetes:
        name: "kubernetes"
        serverUrl: "https://kubernetes.default.svc.cluster.local"
        namespace: "jenkins-agents"
        jenkinsUrl: "http://jenkins.jenkins.svc.cluster.local:8080"
        jenkinsTunnel: "jenkins-agent.jenkins.svc.cluster.local:50000"
        containerCapStr: "50"
        maxRequestsPerHostStr: "32"
        retentionTimeout: 5
        templates:
          - name: "default-agent"
            label: "jenkins-agent"
            nodeUsageMode: NORMAL
            containers:
              - name: "jnlp"
                image: "jenkins/inbound-agent:latest-jdk21"
                resourceRequestCpu: "500m"
                resourceRequestMemory: "512Mi"
                resourceLimitCpu: "1000m"
                resourceLimitMemory: "1Gi"
            volumes:
              - hostPathVolume:
                  mountPath: "/var/run/docker.sock"
                  hostPath: "/var/run/docker.sock"
            idleMinutes: 10
            activeDeadlineSeconds: 3600

This configuration tells Jenkins to spin up agent pods in the jenkins-agents namespace, use the official inbound-agent image with JDK 21, and shut them down after 10 minutes of inactivity.

Deploying with Helm

The official Jenkins Helm chart has first-class JCasC support. Your values.yaml can embed JCasC configuration directly:

controller:
  JCasC:
    configScripts:
      welcome-message: |
        jenkins:
          systemMessage: "Production Jenkins — managed by Helm + JCasC"
      security: |
        jenkins:
          securityRealm:
            ldap:
              configurations:
                - server: "ldap.example.com"
                  rootDN: "dc=example,dc=com"
  sidecars:
    configAutoReload:
      enabled: true

When configAutoReload is enabled, the Helm sidecar watches for ConfigMap changes and triggers JCasC reload automatically — no Jenkins restart needed. This is powerful for GitOps workflows where a merge to main triggers a Helm upgrade.

    graph LR
    A[Git Push] --> B[Helm Upgrade]
    B --> C[ConfigMap Updated]
    C --> D[Sidecar Detects Change]
    D --> E[JCasC Reload]
    E --> F[Jenkins Reconfigured]
  

Configuring Shared Libraries with JCasC

Shared Pipeline Libraries let you centralize common pipeline logic. JCasC makes configuring them reproducible:

unclassified:
  globalLibraries:
    libraries:
      - name: "pipeline-library"
        defaultVersion: "main"
        implicit: true
        retriever:
          modernSCM:
            scm:
              git:
                remote: "https://github.com/your-org/pipeline-library.git"
                credentialsId: "github-creds"
      - name: "devops-utils"
        defaultVersion: "v2.0"
        implicit: false
        retriever:
          modernSCM:
            scm:
              git:
                remote: "https://github.com/your-org/devops-utils.git"
                credentialsId: "github-creds"

Setting implicit: true makes the library available to all pipelines without an explicit @Library annotation in the Jenkinsfile.

Security Hardening with JCasC

RBAC with the Role Strategy Plugin

For production Jenkins instances, the matrix-based security or folder-level permissions are common patterns:

jenkins:
  authorizationStrategy:
    roleBased:
      roles:
        global:
          - name: "admin"
            permissions:
              - "Overall/Administer"
            entries:
              - user: "admin"
          - name: "developer"
            permissions:
              - "Overall/Read"
              - "Job/Build"
              - "Job/Read"
              - "Job/Workspace"
            entries:
              - group: "developers"
          - name: "viewer"
            permissions:
              - "Overall/Read"
              - "Job/Read"
            entries:
              - group: "stakeholders"

Disabling Unsafe Features

Lock down your Jenkins controller with these JCasC security settings:

jenkins:
  remotingSecurity:
    enabled: true

  crumbIssuer:
    standard:
      excludeClientIPFromCrumb: false

security:
  scriptApproval:
    approvedSignatures: []
  globalJobDslSecurityConfiguration:
    useScriptSecurity: true

unclassified:
  buildDiscarders:
    configuredBuildDiscarders:
      - "jobBuildDiscarder"

Validating and Testing JCasC

Schema Validation

The JCasC plugin generates a JSON schema for your installed plugins. Export it from Manage Jenkins > Configuration as Code > Download Configuration and use it in your IDE for autocompletion and validation.

In VS Code, add this to your workspace settings:

{
  "yaml.schemas": {
    "./jenkins-casc-schema.json": "casc_configs/*.yaml"
  }
}

Dry-Run with the REST API

Before applying configuration to production, validate it:

curl -X POST \
  -u admin:$API_TOKEN \
  -F "casc=@jenkins.yaml" \
  "https://jenkins.example.com/configuration-as-code/check"

A 200 response with no errors means the configuration is valid. Integrate this into your CI pipeline to catch misconfigurations before they reach production.

Testing with Docker

Spin up a temporary Jenkins instance to test your JCasC configuration:

docker run -d \
  --name jenkins-test \
  -e CASC_JENKINS_CONFIG=/var/jenkins_home/casc_configs \
  -v $(pwd)/casc_configs:/var/jenkins_home/casc_configs \
  -p 8080:8080 \
  jenkins/jenkins:lts-jdk21

Verify the configuration applied correctly, then tear it down. This pattern works well in a CI pipeline that validates JCasC changes before merging.

Common Pitfalls and How to Avoid Them

Plugin Version Mismatches

JCasC configuration is tightly coupled to the plugins installed. A YAML key that works with Pipeline plugin 2.7 might not exist in 2.6. Always pin your plugin versions and test configuration changes against the same plugin set.

Configuration Drift

JCasC applies configuration on startup or reload, but manual changes through the UI still work. If someone changes a setting through the UI, the next JCasC reload overwrites it. To prevent confusion:

  1. Disable the “Configure” link for non-admins
  2. Add a system message reminding users that configuration is managed by JCasC
  3. Run scheduled JCasC reloads to enforce the declared state

Credential ID Conflicts

If a credential ID in your YAML already exists with a different type, JCasC fails silently or throws a cryptic error. Always use unique, descriptive credential IDs like github-org-token instead of generic names like token.

**Error: "No configurator for type"** — A plugin required by your YAML is not installed. Check that all referenced plugins are in your plugin list. **Error: "Expected mapping"** — YAML indentation error. Use a YAML linter before applying. **Error: "Unable to resolve variable"** — An environment variable referenced with `${VAR}` is not set. Verify all required env vars are exported. **Configuration not applying** — Check that `CASC_JENKINS_CONFIG` points to the correct path. Verify file permissions allow the Jenkins process to read the YAML files.

JCasC vs. Groovy Init Scripts

Before JCasC, teams used Groovy init scripts in /usr/share/jenkins/ref/init.groovy.d/ to configure Jenkins programmatically. Here is how the two approaches compare:

AspectJCasC (YAML)Groovy Init Scripts
ReadabilityHuman-friendly YAMLRequires Groovy knowledge
ValidationJSON schema + dry-run APINo built-in validation
IdempotencyDeclarative, always convergesImperative, may cause side effects
SecurityNo code executionFull Jenkins API access (risky)
Plugin supportAutomatic for compatible pluginsManual API calls per plugin
ReloadHot reload without restartRequires restart

For new deployments, JCasC is the clear choice. For legacy setups with complex Groovy scripts, migrate incrementally — start with security and credentials in JCasC while keeping advanced customizations in Groovy until plugin support catches up.

Putting It All Together

A production-ready Jenkins Configuration as Code setup combines everything covered in this guide. Here is what a complete workflow looks like:

    graph TD
    A[Developer edits casc_configs/] --> B[Pull Request]
    B --> C[CI validates YAML schema]
    C --> D[CI dry-runs against test Jenkins]
    D --> E{Tests pass?}
    E -->|Yes| F[Merge to main]
    E -->|No| G[Fix and re-submit]
    F --> H[Helm upgrade triggers]
    H --> I[ConfigMap updated in K8s]
    I --> J[Sidecar detects change]
    J --> K[JCasC reload applied]
    K --> L[Jenkins reconfigured — zero downtime]
  

Jenkins Configuration as Code is not just a convenience — it is a fundamental shift toward treating your CI/CD platform with the same rigor you apply to application code. Version control, code review, automated testing, and declarative configuration eliminate an entire class of “it worked on the old server” problems.

Start small. Convert your security and credential configuration to JCasC first. Then expand to cloud agents, shared libraries, and tool installations. Within a few iterations, your entire Jenkins setup becomes a reviewable, reproducible artifact that any team member can understand and contribute to.

Question

How do you currently manage your Jenkins configuration — UI clicks, Groovy scripts, or JCasC?

References and Further Reading

Similar Articles

More from jenkins

Knowledge Quiz

Test your general knowledge with this quick quiz!

The quiz consists of 5 multiple-choice questions.

Take as much time as you need.

Your score will be shown at the end.