How to find JNLP Node's secret key remotely?

Issue

I have got the jenkins-cli working and able to create a slave. How can I dynamically get the secret key to start up the slave? 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 slave-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 “slave-agent.jnlp” file at $NODE_URL/slave-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/slave-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:$JENKINS_PASSWORD_OR_API_TOKEN -H “Jenkins-Crumb:${JENKINS_CRUMB}” $NODE_URL/slave-agent.jnlp | sed “s/.<application-desc main-class="hudson.remoting.jnlp.Main">([a-z0-9]).*/\1/”

With the following variables:

VariableDescription
JENKINS_USERA Jenkins user with permissions to view nodes
JENKINS_PASSWORD_OR_API_TOKENPassword or API token of the Jenkins user
JENKINS_CRUMBThe crumb issued by Jenkins (see CSRF Protection Explained)
NODE_URLThe 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 ".crumb:dac7ce5614f8cb32a6ce75153aaf2398" -X GET https://owood.ci.cloudbees.com/computer/jnlpAgentTest/slave-agent.jnlp | sed "s/.*<application-desc main-class=\"hudson.remoting.jnlp.Main\"><argument>\([a-z0-9]*\).*/\1/"
b8c80148ce36de10c9358384fac9e28fbba941055a9a6ab2277e75ddc29a8744

Note: 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:

Have more questions? Submit a request

0 Comments

Please sign in to leave a comment.