How to find JNLP Node’s secret key remotely?

Article ID:222520647
2 minute readKnowledge base

Issue

I have got the jenkins-cli working and able to create an agent. How can I dynamically get the secret key to start up the agent? The launch method is via Java Web Start.

Environment

Resolution

Only users with a certain level of permissions can retrieve this information:

  • as a Jenkins non-administrator user, a solution is to download the jenkins-agent.jnlp and parse it to get the secret

  • as a Jenkins administrator, a solution is to run a groovy script using the Jenkins CLI or the Jenkins REST API

For Any Jenkins Users

You can download the "jenkins-agent.jnlp" file at $NODE_URL/jenkins-agent.jnlp. This file actually contains XML content that includes the secret. Here is an example of a JNLP file downloaded from a Jenkins instance at https://cje.example.com/computer/jnlpAgentTest/jenkins-agent.jnlp - the secret is b8c80148ce36de10c9358384fac9e28fbba941055a9a6ab2277e75ddc29a8744:

<jnlp codebase="https://cje.example.com/computer/jnlpAgentTest/" spec="1.0+">
	<information>
		<title>Agent for jnlpAgentTest</title>
		<vendor>Jenkins project</vendor>
		<homepage href="https://jenkins-ci.org/"/>
	</information>
	<security>
		<all-permissions/>
	</security>
	<resources>
		<j2se version="1.8+"/>
		<jar href="https://cje.example.com/jnlpJars/remoting.jar"/>
	</resources>
	<application-desc main-class="hudson.remoting.jnlp.Main">
		<argument>b8c80148ce36de10c9358384fac9e28fbba941055a9a6ab2277e75ddc29a8744</argument>
		<argument>jnlpAgentTest</argument>
		<argument>-workDir</argument>
		<argument>/tmp/jnlpAgenttest</argument>
		<argument>-internalDir</argument>
		<argument>remoting</argument>
		<argument>-url</argument>
		<argument>https://cje.example.com/</argument>
	</application-desc>
</jnlp>

So the solution would be to download this file for a particular Jenkins node and extract the first argument under <application-desc main-class="hudson.remoting.jnlp.Main">. This can be done with curl and sed:

$ curl -L -s -u $JENKINS_USER:$API_TOKEN -H "Jenkins-Crumb:${JENKINS_CRUMB}" $NODE_URL/jenkins-agent.jnlp | sed "s/.*<application-desc main-class=\"hudson.remoting.jnlp.Main\"><argument>\([a-z0-9]*\).*/\1/"

With the following variables:

Variable Description

JENKINS_USER

A Jenkins user with permissions to view nodes

API_TOKEN

Password or API token of the Jenkins user

JENKINS_CRUMB

The crumb issued by Jenkins (see CSRF Protection Explained)

NODE_URL

The URL of the Node (could be a Node or a Shared Agent

Here is an example of the output:

$ curl -L -s -u admin:password -H "Jenkins-Crumb:dac7ce5614f8cb32a6ce75153aaf2398" -X GET https://CONTROLLER_URL/computer/jnlpAgentTest/jenkins-agent.jnlp | sed "s/.*<application-desc main-class=\"hudson.remoting.jnlp.Main\"><argument>\([a-z0-9]*\).*/\1/"
b8c80148ce36de10c9358384fac9e28fbba941055a9a6ab2277e75ddc29a8744
Other solutions can be used to download the file and / or extract the secret.

For Jenkins Administrators Only

As a Jenkins administrator, another solution is to use the Jenkins Script Console. The Jenkins CLI or the Jenkins REST API can also be used to execute script remotely.

Jenkins Nodes

To get the secret of a Jenkins Node, the following script can be used:

jenkins.model.Jenkins.getInstance().getComputer("$NODE_NAME").getJnlpMac()

CJOC Shared Agents

To get the secret of a Shared Agent, the following script can be used - in the Jenkins Script Console of the CJOC:

def sharedAgent = Jenkins.getInstance().getItems(com.cloudbees.opscenter.server.model.SharedSlave.class)
	.find { it.launcher != null && it.launcher.class.name == 'com.cloudbees.opscenter.server.jnlp.slave.JocJnlpSlaveLauncher' && it.name == "shared-dvilladiego"}
return sharedAgent?.launcher.getJnlpMac(sharedAgent)
}

See also: