Disable Jenkins CLI

Article ID:234709648
3 minute readKnowledge base

Issue

  • I would like to disable the Jenkins CLI on my Jenkins controller.

  • You would like to prevent remote access to Jenkins CLI

Resolution

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

// disable CLI access over HTTP / Websocket
def removal = { lst ->
  lst.each { x -> if (x.getClass().getName()?.contains("CLIAction")) lst.remove(x) }
}
def j = jenkins.model.Jenkins.get();
removal(j.getExtensionList(hudson.cli.CLIAction.class))
removal(j.getExtensionList(hudson.ExtensionPoint.class))
removal(j.getExtensionList(hudson.model.Action.class))
removal(j.getExtensionList(hudson.model.ModelObject.class))
removal(j.getExtensionList(hudson.model.RootAction.class))
removal(j.getExtensionList(hudson.model.UnprotectedRootAction.class))
removal(j.getExtensionList(java.lang.Object.class))
removal(j.getExtensionList(org.kohsuke.stapler.StaplerProxy.class))
removal(j.actions)

// disable CLI access over SSH
if (j.getPlugin('sshd')) {
  hudson.ExtensionList.lookupSingleton(org.jenkinsci.main.modules.sshd.SSHD.class).setPort(-1)
}

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

import java.nio.file.Files
import java.nio.file.Paths

def jenkins_home = Jenkins.get().getRootDir().absolutePath
def initDirPath = Paths.get(jenkins_home, "init.groovy.d")

if (!Files.exists(initDirPath)) {
    println "Creating Post-Initialization directory '${initDirPath}'..."
    Files.createDirectories(initDirPath);
}

def groovyFile = initDirPath.toRealPath().toString() + "/cli-shutdown.groovy"

def codestr="""
// disable CLI access over HTTP / Websocket
def removal = { lst ->
  lst.each { x -> if (x.getClass().getName()?.contains("CLIAction")) lst.remove(x) }
}
def j = jenkins.model.Jenkins.get();
removal(j.getExtensionList(hudson.cli.CLIAction.class))
removal(j.getExtensionList(hudson.ExtensionPoint.class))
removal(j.getExtensionList(hudson.model.Action.class))
removal(j.getExtensionList(hudson.model.ModelObject.class))
removal(j.getExtensionList(hudson.model.RootAction.class))
removal(j.getExtensionList(hudson.model.UnprotectedRootAction.class))
removal(j.getExtensionList(java.lang.Object.class))
removal(j.getExtensionList(org.kohsuke.stapler.StaplerProxy.class))
removal(j.actions)

// disable CLI access over SSH
if (j.getPlugin('sshd')) {
  hudson.ExtensionList.lookupSingleton(org.jenkinsci.main.modules.sshd.SSHD.class).setPort(-1)
}
"""

try {
    println "Creating Post-Initialization script '${groovyFile}'..."
    File file = new File(groovyFile)
    file.newWriter().withWriter {it << codestr};
} catch (Exception ex) {
    println "Unable to create '$groovyFile': " + ex.getMessage() + ". If instance restarts, this script must be applied again"
}
When using High Availability (active/active) replicas, as of product version 2.426.3.3, the first groovy script above will only disable the CLI on one of the replicas, to disable the CLI across all replicas, a restart, or rolling restart of the controllers is required, and the script above should be in a Post Initialization Script.
You will not be able to enable / disable the HTTP endpoint for the CLI from the UI. Only CLI access via SSH can be re-enabled while the controller is running.

Known limitations

There are some limitations on the provided script as it will not work as expected in the following cases:

  • 2.276.x and earlier: The script doesn’t disable the SSH port providing access to the CLI via SSH.

  • 2.222.x and earlier: The line including java.lang.Object needs to be removed for it to work. Note that removing this line will result in incomplete protection when applied to newer releases.

  • 2.164.x and earlier: The script doesn’t disable the remoting-based CLI removed in later releases.

  • When using High Availability (active/active) replicas, as of product version 2.426.3.3, the first groovy script above will only disable the CLI on one of the replicas, to disable the CLI across all replicas, a restart, or rolling restart of the controllers is required, and the script above should be in a Post Initialization Script.

Validate if the mitigation script is in place

To validate if the mitigation script is in the correct place, please run this script in the script console of your controller.

import java.nio.file.Files
import java.nio.file.Paths

def jenkins_home = Jenkins.get().getRootDir().absolutePath
def initDirPath = Paths.get(jenkins_home, "init.groovy.d")
def groovyFile = initDirPath.toRealPath().toString() + "/cli-shutdown.groovy"
File file = new File(groovyFile)
if (!file.exists()) {
    println "Warning: This instance does not have the mitigation file in the correct path '${groovyFile}'..."
}else{
    println "This instance is protected by the mitigation script"
}