Skip to content

Commit

Permalink
Stop relying on deprecated /computer/${NAME}/jenkins-agent.jnlp end…
Browse files Browse the repository at this point in the history
…point
  • Loading branch information
basil committed Dec 8, 2023
1 parent f759630 commit 433c5bf
Show file tree
Hide file tree
Showing 5 changed files with 30 additions and 19 deletions.
6 changes: 2 additions & 4 deletions client/src/main/java/hudson/plugins/swarm/Client.java
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,6 @@
import java.nio.file.InvalidPathException;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.util.List;
import java.util.Optional;
import java.util.logging.Level;
import java.util.logging.Logger;
Expand Down Expand Up @@ -216,10 +215,9 @@ static void run(SwarmClient swarmClient, Options options, String... args) throws

/*
* Note that any instances of InterruptedException or RuntimeException thrown
* internally by the next two lines get wrapped in RetryException.
* internally by the next line get wrapped in RetryException.
*/
List<String> jnlpArgs = swarmClient.getJnlpArgs(url);
swarmClient.connect(jnlpArgs, url);
swarmClient.connect(url);
if (options.noRetryAfterConnected) {
logger.warning("Connection closed, exiting...");
swarmClient.exitWithStatus(0);
Expand Down
24 changes: 20 additions & 4 deletions client/src/main/java/hudson/plugins/swarm/SwarmClient.java
Original file line number Diff line number Diff line change
Expand Up @@ -69,6 +69,7 @@ public class SwarmClient {

private final Options options;
private final String hash;
private String secret;
private String name;
private HttpServer prometheusServer = null;

Expand Down Expand Up @@ -125,8 +126,10 @@ public URL getUrl() {
/**
* @param url The URL
* @return The JNLP arguments, as returned from {@link Launcher#parseJnlpArguments()}.
* @deprecated removed without replacement
*/
List<String> getJnlpArgs(URL url) throws IOException, RetryException {
@Deprecated
private List<String> getJnlpArgs(URL url) throws IOException, RetryException {
logger.fine("connect() invoked");

Launcher launcher = new Launcher();
Expand Down Expand Up @@ -157,14 +160,22 @@ List<String> getJnlpArgs(URL url) throws IOException, RetryException {
*
* <p>Interrupt the thread to abort it and try connecting again.
*/
void connect(List<String> jnlpArgs, URL url) throws IOException, RetryException {
void connect(URL url) throws IOException, RetryException {
List<String> args = new ArrayList<>();

args.add("-url");
args.add(url.toString());

args.add("-secret");
args.add(jnlpArgs.get(0));
if (secret == null) {
List<String> jnlpArgs = getJnlpArgs(url);
if (!jnlpArgs.isEmpty()) {
secret = jnlpArgs.get(0);
}
}
if (secret != null) {
args.add("-secret");
args.add(secret);
}

args.add("-name");
args.add(name);
Expand Down Expand Up @@ -368,6 +379,11 @@ void createSwarmAgent(URL url) throws IOException, InterruptedException, RetryEx
props.load(stream);
}

String secret = props.getProperty("secret");
if (secret != null) {
this.secret = secret.trim();
}

String name = props.getProperty("name");
if (name == null) {
this.name = options.name;
Expand Down
7 changes: 3 additions & 4 deletions docs/security.adoc
Original file line number Diff line number Diff line change
Expand Up @@ -29,28 +29,27 @@ Swarm requires a user with the following permissions:

* *Overall/Read*
* *Agent/Create*
* *Agent/Connect*
* *Agent/Configure* (_not_ required when using the project-based Matrix Authorization Strategy)

== Examples

=== Matrix-based security

A common practice is to grant *Overall/Read* permission to either anonymous or authenticated users, leaving the dedicated Swarm user with only *Agent/Create*, *Agent/Connect*, and *Agent/Configure* permissions:
A common practice is to grant *Overall/Read* permission to either anonymous or authenticated users, leaving the dedicated Swarm user with only the *Agent/Create* and *Agent/Configure* permissions:

image:images/matrixBasedSecurity.png[image]

=== Project-based Matrix Authorization Strategy

A common practice is to grant *Overall/Read* permission to either anonymous or authenticated users, leaving the dedicated Swarm user with only *Agent/Create* and *Agent/Connect* permissions:
A common practice is to grant *Overall/Read* permission to either anonymous or authenticated users, leaving the dedicated Swarm user with only the *Agent/Create* permission:

image:images/projectBasedMatrixAuthorizationStrategy.png[image]

NOTE: Unlike matrix-based security, the project-based Matrix Authorization Strategy does not require *Agent/Configure* permission.

=== Role-Based Strategy

A common practice is to create a read-only role with *Overall/Read* permission, leaving a dedicated Swarm role with only *Agent/Create*, *Agent/Connect*, and *Agent/Configure* permissions:
A common practice is to create a read-only role with *Overall/Read* permission, leaving a dedicated Swarm role with only the *Agent/Create* and *Agent/Configure* permissions:

image:images/roleBasedStrategyManage.png[image]

Expand Down
2 changes: 2 additions & 0 deletions plugin/src/main/java/hudson/plugins/swarm/PluginImpl.java
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@
import java.util.Set;
import javax.servlet.http.HttpServletResponse;
import jenkins.model.Jenkins;
import jenkins.slaves.JnlpAgentReceiver;
import org.apache.commons.lang.ArrayUtils;
import org.kohsuke.stapler.QueryParameter;
import org.kohsuke.stapler.StaplerRequest;
Expand Down Expand Up @@ -210,6 +211,7 @@ public void doCreateSlave(
try (OutputStream outputStream = rsp.getCompressedOutputStream(req)) {
Properties props = new Properties();
props.put("name", name);
props.put("secret", JnlpAgentReceiver.SLAVE_SECRET.mac(name));
props.store(outputStream, "");
}
} catch (FormException e) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -104,9 +104,8 @@ public void build() throws IOException {
// Needed for the [optional] Jenkins version check as well as CSRF.
strategy.add(Jenkins.READ, new PermissionEntry(AuthorizationType.EITHER, "authenticated"));

// Needed to create and connect the agent.
// Needed to create the agent.
strategy.add(Computer.CREATE, new PermissionEntry(AuthorizationType.EITHER, swarmUsername));
strategy.add(Computer.CONNECT, new PermissionEntry(AuthorizationType.EITHER, swarmUsername));

/*
* The following is necessary because
Expand All @@ -120,11 +119,8 @@ public void build() throws IOException {
} else if (authorizationStrategy instanceof RoleBasedAuthorizationStrategy) {
Role admin = new Role("admin", ".*", Set.of(Jenkins.ADMINISTER.getId()), "Jenkins administrators");
Role readOnly = new Role("readonly", ".*", Set.of(Jenkins.READ.getId()), "Read-only users");
Role swarm = new Role(
"swarm",
".*",
Set.of(Computer.CREATE.getId(), Computer.CONNECT.getId(), Computer.CONFIGURE.getId()),
"Swarm users");
Role swarm =
new Role("swarm", ".*", Set.of(Computer.CREATE.getId(), Computer.CONFIGURE.getId()), "Swarm users");

SortedMap<Role, Set<String>> roleMap = new TreeMap<>();
roleMap.put(admin, Set.of(adminUsername));
Expand Down

0 comments on commit 433c5bf

Please sign in to comment.