Skip to content

Commit

Permalink
Support operator users in LocalClusterSpec
Browse files Browse the repository at this point in the history
This adds a new paramter to LocalClusterSpecBuilder.user(..) to
indicate whether the user should be an operator or not.

Users added with the simplified user(username, password) method are
operators (and have the "_es_test_root" role).
  • Loading branch information
tvernum committed Jul 4, 2023
1 parent 0cb0120 commit 5768e69
Show file tree
Hide file tree
Showing 16 changed files with 56 additions and 23 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -75,9 +75,9 @@ public static void init() throws URISyntaxException, FileNotFoundException {
.configFile("node.key", Resource.fromClasspath("ssl/node.key"))
.configFile("node.crt", Resource.fromClasspath("ssl/node.crt"))
.configFile("ca.crt", Resource.fromClasspath("ssl/ca.crt"))
.user("test_admin", PASSWORD, "superuser")
.user("test_data_stream_lifecycle", PASSWORD, "manage_data_stream_lifecycle")
.user("test_non_privileged", PASSWORD, "not_privileged")
.user("test_admin", PASSWORD, "superuser", false)
.user("test_data_stream_lifecycle", PASSWORD, "manage_data_stream_lifecycle", false)
.user("test_non_privileged", PASSWORD, "not_privileged", false)
.rolesFile(Resource.fromClasspath("roles.yml"))
.build();

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -114,7 +114,7 @@ public class RcsCcsCommonYamlTestSuiteIT extends ESClientYamlSuiteTestCase {
return (String) API_KEY_MAP_REF.get().get("encoded");
})
.rolesFile(Resource.fromClasspath("roles.yml"))
.user("remote_search_user", "x-pack-test-password", "remote_search_role")
.user("remote_search_user", "x-pack-test-password", "remote_search_role", false)
.build();

private static Map<String, Object> createCrossClusterAccessApiKey() throws IOException {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -96,8 +96,8 @@ public AbstractLocalClusterSpecBuilder<T> user(String username, String password)
}

@Override
public AbstractLocalClusterSpecBuilder<T> user(String username, String password, String role) {
this.users.add(new User(username, password, role));
public AbstractLocalClusterSpecBuilder<T> user(String username, String password, String role, boolean operator) {
this.users.add(new User(username, password, role, operator));
return this;
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -44,9 +44,12 @@
import java.time.Duration;
import java.util.Arrays;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Locale;
import java.util.Map;
import java.util.Properties;
import java.util.Set;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.TimeoutException;
Expand Down Expand Up @@ -471,6 +474,7 @@ private void configureSecurity() {
}

LOGGER.info("Creating users for node '{}'", name);
final Set<String> operators = new HashSet<>();
for (User user : spec.getUsers()) {
runToolScript(
"elasticsearch-users",
Expand All @@ -482,6 +486,24 @@ private void configureSecurity() {
"-r",
user.getRole()
);
if (user.isOperator()) {
operators.add(user.getUsername());
}
}

if (operators.isEmpty() == false) {
// TODO: Support service accounts here
Path destination = workingDir.resolve("config").resolve("operator_users.yml");
try (Writer writer = Files.newBufferedWriter(destination, StandardOpenOption.CREATE, StandardOpenOption.APPEND)) {
writer.write(String.format(Locale.ROOT, """
operator:
- usernames: [%s]
realm_type: "file"
auth_type: "realm"
""", operators.stream().collect(Collectors.joining("\",\"", "\"", "\""))));
} catch (IOException e) {
throw new UncheckedIOException("Failed to configure operator users file " + destination, e);
}
}
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -51,14 +51,16 @@ public interface LocalClusterSpecBuilder<T extends ElasticsearchCluster> extends
LocalClusterSpecBuilder<T> node(int index, Consumer<? super LocalNodeSpecBuilder> config);

/**
* Register a user using the default test role.
* Register a user using the default test role, as an operator
*/
LocalClusterSpecBuilder<T> user(String username, String password);

/**
* Register a user using the given role.
* @param operator If true, configure the user as an operator.
* <em>Note</em>: This does <strong>not</strong> automatically enable operator privileges on the cluster
*/
LocalClusterSpecBuilder<T> user(String username, String password, String role);
LocalClusterSpecBuilder<T> user(String username, String password, String role, boolean operator);

/**
* Register a roles file with cluster via the supplied {@link Resource}.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -9,22 +9,26 @@
package org.elasticsearch.test.cluster.local.model;

public class User {
public static final User DEFAULT_USER = new User("test_user", "x-pack-test-password", "_es_test_root");
public static final String ROOT_USER_ROLE = "_es_test_root";
public static final User DEFAULT_USER = new User("test_user", "x-pack-test-password", ROOT_USER_ROLE, true);

private final String username;
private final String password;
private final String role;
private final boolean operator;

public User(String username, String password) {
this.username = username;
this.password = password;
this.role = "_es_test_root";
this.role = ROOT_USER_ROLE;
this.operator = true;
}

public User(String username, String password, String role) {
public User(String username, String password, String role, boolean operator) {
this.username = username;
this.password = password;
this.role = role;
this.operator = operator;
}

public String getUsername() {
Expand All @@ -38,4 +42,8 @@ public String getPassword() {
public String getRole() {
return role;
}

public boolean isOperator() {
return operator;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -61,7 +61,7 @@ public class EnableSecurityOnBasicLicenseIT extends ESRestTestCase {
.configFile("ca.crt", Resource.fromClasspath("ssl/ca.crt"))
.rolesFile(Resource.fromClasspath("roles.yml"))
.user("admin_user", "admin-password")
.user("security_test_user", "security-test-password", "security_test_role")
.user("security_test_user", "security-test-password", "security_test_role", false)
.build();

@Override
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -71,7 +71,7 @@ public class RemoteClusterSecurityCcrIT extends AbstractRemoteClusterSecurityTes
}"""));
return (String) API_KEY_MAP_REF.get().get("encoded");
})
.user("ccr_user", PASS.toString(), "ccr_user_role")
.user("ccr_user", PASS.toString(), "ccr_user_role", false)
.build();
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -66,7 +66,7 @@ public class RemoteClusterSecurityMlIT extends AbstractRemoteClusterSecurityTest
return (String) API_KEY_MAP_REF.get().get("encoded");
})
.rolesFile(Resource.fromClasspath("roles.yml"))
.user(REMOTE_ML_USER, PASS.toString(), "ml_jobs_shared_airline_data")
.user(REMOTE_ML_USER, PASS.toString(), "ml_jobs_shared_airline_data", false)
.build();
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -106,7 +106,7 @@ public class RemoteClusterSecurityRestIT extends AbstractRemoteClusterSecurityTe
return (String) REST_API_KEY_MAP_REF.get().get("encoded");
})
.rolesFile(Resource.fromClasspath("roles.yml"))
.user(REMOTE_METRIC_USER, PASS.toString(), "read_remote_shared_metrics")
.user(REMOTE_METRIC_USER, PASS.toString(), "read_remote_shared_metrics", false)
.build();
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -63,7 +63,7 @@ public class RemoteClusterSecuritySpecialUserIT extends AbstractRemoteClusterSec
.setting("xpack.security.authc.anonymous.roles", "read_remote_shared_logs")
.setting("xpack.security.remote_cluster_client.ssl.enabled", "true")
.setting("xpack.security.remote_cluster_client.ssl.certificate_authorities", "remote-cluster-ca.crt")
.user(REMOTE_SEARCH_USER, PASS.toString(), "read_remote_shared_metrics")
.user(REMOTE_SEARCH_USER, PASS.toString(), "read_remote_shared_metrics", false)
.keystore("cluster.remote.my_remote_cluster.credentials", () -> {
if (API_KEY_MAP_REF.get() == null) {
final Map<String, Object> apiKeyMap = createCrossClusterAccessApiKey("""
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -66,7 +66,7 @@ public class RemoteClusterSecurityTransformIT extends AbstractRemoteClusterSecur
return (String) API_KEY_MAP_REF.get().get("encoded");
})
.rolesFile(Resource.fromClasspath("roles.yml"))
.user(REMOTE_TRANSFORM_USER, PASS.toString(), "transform_admin,transform_remote_shared_index")
.user(REMOTE_TRANSFORM_USER, PASS.toString(), "transform_admin,transform_remote_shared_index", false)
.build();
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@
import org.elasticsearch.http.PemHttpsConfigurator;
import org.elasticsearch.mocksocket.MockHttpServer;
import org.elasticsearch.test.cluster.ElasticsearchCluster;
import org.elasticsearch.test.cluster.local.model.User;
import org.elasticsearch.test.cluster.util.resource.Resource;
import org.elasticsearch.test.junit.RunnableTestRuleAdapter;
import org.elasticsearch.test.rest.ESRestTestCase;
Expand Down Expand Up @@ -106,8 +107,8 @@ private static ElasticsearchCluster initTestCluster() {
.setting("xpack.security.transport.ssl.certificate_authorities", "ca.crt")
.setting("xpack.security.transport.ssl.verification_mode", "certificate")
.keystore("bootstrap.password", "x-pack-test-password")
.user("test_admin", "x-pack-test-password", "_es_test_root")
.user("rest_test", "rest_password")
.user("test_admin", "x-pack-test-password", User.ROOT_USER_ROLE, true)
.user("rest_test", "rest_password", User.ROOT_USER_ROLE, false)
.configFile("node.key", Resource.fromClasspath("ssl/node.key"))
.configFile("node.crt", Resource.fromClasspath("ssl/node.crt"))
.configFile("ca.crt", Resource.fromClasspath("ssl/ca.crt"))
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -247,8 +247,8 @@ public class ServiceAccountIT extends ESRestTestCase {
.configFile("service_tokens", Resource.fromClasspath("service_tokens"))
.rolesFile(Resource.fromClasspath("roles.yml"))
.user("test_admin", "x-pack-test-password")
.user("elastic/fleet-server", "x-pack-test-password", "superuser")
.user("service_account_manager", "x-pack-test-password", "service_account_manager")
.user("elastic/fleet-server", "x-pack-test-password", "superuser", false)
.user("service_account_manager", "x-pack-test-password", "service_account_manager", false)
.build();

@BeforeClass
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,7 @@ public class GlobalCheckpointSyncActionIT extends ESRestTestCase {
.setting("xpack.ml.enabled", "false")
.setting("xpack.license.self_generated.type", "trial")
.rolesFile(Resource.fromClasspath("roles.yml"))
.user("test-user", "x-pack-test-password", "test")
.user("test-user", "x-pack-test-password", "test", false)
.user("super-user", "x-pack-super-password")
.build();

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -171,7 +171,7 @@ public abstract class C2IdOpTestCase extends ESRestTestCase {
.keystore("xpack.security.authc.realms.jwt.op-jwt.client_authentication.shared_secret", "jwt-realm-shared-secret")
.configFile("testnode.jks", Resource.fromClasspath("ssl/testnode.jks"))
.configFile("op-jwks.json", Resource.fromClasspath("op-jwks.json"))
.user("x_pack_rest_user", "x-pack-test-password", "superuser")
.user("x_pack_rest_user", "x-pack-test-password", "superuser", false)
.build();

@Override
Expand Down

0 comments on commit 5768e69

Please sign in to comment.