Disable Jenkins CLI

Issue

  • I would like to disable the Jenkins CLI on my Jenkins Master.
  • You would like to prevent remote access to Jenkins CLI

Environment

  • Jenkins
  • CloudBees Jenkins Enterprise (CJE)
  • CloudBees Jenkins Operations Center (CJOC)

Resolution

There are several solution to disable the CLI and some depends on the version of Jenkins Core.

Solution: via the UI (2.46.2 and later)

Under Manage Jenkins > Configure Global Security > Agent protocols, disable the CLI protocols:

Solution: Groovy Script (2.46.2 and later)

(Since version 2.46.2 JENKINS-41745)

You can disable the CLI by executing the following groovy script under Manage Jenkins > Script Console:

jenkins.CLI.get().setEnabled(false)

This configuration survives a restart. If you want to re-enable the CLI, you can use the following groovy script:

jenkins.CLI.get().setEnabled(true)

Note: You will not be able to enable / disable the CLI from the UI.

Solution: Java Argument (2.19.3 and later)

Add the java argument -Djenkins.CLI.disabled=true on Jenkins startup.

Note: Upon Jenkins startup, you will not be able to enable / disable the CLI from the UI.

Solution: Groovy Script / Post Initialization Script (any version)

You can disable the CLI by executing the following groovy script under Manage Jenkins > Script Console:

println "Disabling the Jenkins CLI..."

// disabled CLI access over TCP listener (separate port)
def p = jenkins.AgentProtocol.all()
p.each { x ->
    if (x.name?.contains("CLI")) {
        println "Removing protocol ${x.name}"
        p.remove(x)
    }
}

// disable CLI access over /cli URL
def removal = { lst ->
    lst.each { x ->
        if (x.getClass().name.contains("CLIAction")) {
            println "Removing extension ${x.getClass().name}"
            lst.remove(x)
        }
    }
}
def j = jenkins.model.Jenkins.instance
removal(j.getExtensionList(hudson.model.RootAction.class))
removal(j.actions)
println "CLI disabled"

But this will not survive a restart. To disable the CLI on startup using a groovy script, you can create a Post Initialization Script:

import jenkins.*
import jenkins.model.*
import hudson.model.*
import java.util.logging.Logger

Logger logger = Logger.getLogger("cli-shutdown.groovy")
logger.info("Disabling the Jenkins CLI...")

// disabled CLI access over TCP listener (separate port)
def p = AgentProtocol.all()
p.each { x ->
    if (x.name?.contains("CLI")) {
        logger.info("Removing protocol ${x.name}")
        p.remove(x)
    }
}

// disable CLI access over /cli URL
def removal = { lst ->
    lst.each { x ->
        if (x.getClass().name.contains("CLIAction")) {
            logger.info("Removing extension ${x.getClass().name}")
            lst.remove(x)
        }
    }
}
def j = Jenkins.instance
removal(j.getExtensionList(RootAction.class))
removal(j.actions)
logger.info("CLI disabled")

Note: Upon Jenkins startup, you will not be able to enable / disable the CLI from the UI.

Solution: At System Level (deprecated)

Other ways to prevent access to the Jenkins CLI are by tweaking system rules like for example:

  • limiting accesses to the TCP port for CLI
  • filtering out accesses to http://JENKINS/cli URL

1) CLI is accessed via Remoting (the TCP port for JNLP slave agents set under Manage Jenkins > Configure Global Security). You can therefore disable the Jenkins CLI by dropping accesses to that port:

iptables -A INPUT -p tcp –dport $JNLP_PORT -j REJECT –reject-with icmp-port-unreachable

Be-aware that blocking accesses to that port prevents connections to Operations Center and JNLP slaves. You may want to tweak this rule to allow accesses from specific hosts.

2) Blocking JNLP port is not enough though, as Jenkins CLI falls back to HTTP transport in that case. You also need to filter out HTTP request to http://JENKINS/cli URL. This can be done with CloudBees Request Filter plugin.

Other Resources

Disable Jenkins CLI Across All Masters
Enable Jenkins CLI Across All Masters
Jenkins CLI

Have more questions? Submit a request

2 Comments

  • 0
    Avatar
    Henry Dobson

    Just been looking at this functionality myself and found I was able to disable CLI in a much simplier way:

    ```

    #!groovy
    import jenkins.*

    def enableCli = CLI.get()
    enableCli.setEnabled(false)

    ```

    Being fairly green with Groovy and the Jenkins classes, how do these approaches differ?

  • 0
    Avatar
    Denys Digtiar

    Hi Henry,

    This script automates the creation of the init script on top of disabling the CLI using the approach in an original security advisory. The approach has since been improved and this script is a bit outdated now

    Please refer to https://github.com/jenkinsci-cert/SECURITY-218 

Please sign in to leave a comment.