Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add a tool for creating enrollment tokens #74890

Merged
merged 15 commits into from
Jul 15, 2021
Merged
Show file tree
Hide file tree
Changes from 12 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
59 changes: 59 additions & 0 deletions docs/reference/commands/create-enrollment-token.asciidoc
Original file line number Diff line number Diff line change
@@ -0,0 +1,59 @@
[roles="xpack"]
[[create-enrollment-token]]

== elasticsearch-create-enrollment-token

The `elasticsearch-create-enrollment-token` command creates enrollment tokens for
{es} nodes and {kib} instances.

[discrete]
=== Synopsis

[source,shell]
----
bin/elasticsearch-create-enrollment-token
[-f, --force] [-h, --help] [-E <KeyValuePair>] [-s, --scope]
----

[discrete]
=== Description

This command allows users to create enrollment tokens that can be subsequently
used to enroll new {es} nodes to an existing cluster or configure {kib} instances
to communicate with an existing cluster that has security features enabled.
jkakavas marked this conversation as resolved.
Show resolved Hide resolved
It uses a temporary superuser in the <<file-realm, file realm>> that is automatically
generated and then removed, in order to run the request to create enrollment tokens.
You cannot use this tool if the file realm has been disabled in your `elasticsearch.yml`
file.
jkakavas marked this conversation as resolved.
Show resolved Hide resolved

This command uses an HTTP connection to connect to the cluster and run the user
management requests. The command automatically attempts to establish the connection
over HTTPS by using the `xpack.security.http.ssl` settings in
the `elasticsearch.yml` file. If you do not use the default config directory
location, ensure that the *ES_PATH_CONF* environment variable returns the
jkakavas marked this conversation as resolved.
Show resolved Hide resolved
correct path before you run the `elasticsearch-create-enrollment-token` command. You can
override settings in your `elasticsearch.yml` file by using the `-E` command
option. For more information about debugging connection failures, see
<<trb-security-setup>>.

[discrete]
[[create-enrollment-token-parameters]]
=== Parameters

`-E <KeyValuePair>`:: Configures a standard {es} or {xpack} setting.

`-f, --force`:: Forces the execution of the command against an unhealthy cluster.
jkakavas marked this conversation as resolved.
Show resolved Hide resolved

`-h, --help`:: Shows help information.
jkakavas marked this conversation as resolved.
Show resolved Hide resolved

`-s, --scope`:: Specifies the scope of the generated token. Supported values are `node` and `kibana`.

[discrete]
=== Examples

The following command creates an enrollment token to be used by an {es} node:
jkakavas marked this conversation as resolved.
Show resolved Hide resolved

[source,shell]
----
bin/elasticsearch-create-enrollment-token -s node
----
2 changes: 2 additions & 0 deletions docs/reference/commands/index.asciidoc
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ tasks from the command line:

* <<certgen>>
* <<certutil>>
* <<create-enrollment-token>>
* <<elasticsearch-croneval>>
* <<elasticsearch-keystore>>
* <<node-tool>>
Expand All @@ -22,6 +23,7 @@ tasks from the command line:

include::certgen.asciidoc[]
include::certutil.asciidoc[]
include::create-enrollment-token.asciidoc[]
include::croneval.asciidoc[]
include::keystore.asciidoc[]
include::node-tool.asciidoc[]
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
#!/bin/bash

# Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
# or more contributor license agreements. Licensed under the Elastic License
# 2.0; you may not use this file except in compliance with the Elastic License
# 2.0.

ES_MAIN_CLASS=org.elasticsearch.xpack.security.enrollment.tool.CreateEnrollmentTokenTool \
ES_ADDITIONAL_SOURCES="x-pack-env;x-pack-security-env" \
"`dirname "$0"`"/elasticsearch-cli \
"$@"
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
@echo off

rem Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
rem or more contributor license agreements. Licensed under the Elastic License
rem 2.0; you may not use this file except in compliance with the Elastic License
rem 2.0.

setlocal enabledelayedexpansion
setlocal enableextensions

set ES_MAIN_CLASS=org.elasticsearch.xpack.security.enrollment.tool.CreateEnrollmentTokenTool
set ES_ADDITIONAL_SOURCES=x-pack-env;x-pack-security-env
set ES_ADDITIONAL_CLASSPATH_DIRECTORIES=lib/tools/security-cli
call "%~dp0elasticsearch-cli.bat" ^
%%* ^
|| goto exit

endlocal
endlocal
:exit
exit /b %ERRORLEVEL%
Original file line number Diff line number Diff line change
@@ -0,0 +1,89 @@
/*
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
* or more contributor license agreements. Licensed under the Elastic License
* 2.0; you may not use this file except in compliance with the Elastic License
* 2.0.
*/

package org.elasticsearch.xpack.security.enrollment.tool;

import joptsimple.OptionSet;
import joptsimple.OptionSpec;

import org.elasticsearch.cli.ExitCodes;
import org.elasticsearch.cli.Terminal;
import org.elasticsearch.cli.UserException;
import org.elasticsearch.common.settings.KeyStoreWrapper;
import org.elasticsearch.common.settings.SecureString;
import org.elasticsearch.core.CheckedFunction;
import org.elasticsearch.env.Environment;
import org.elasticsearch.xpack.core.XPackSettings;
import org.elasticsearch.xpack.security.enrollment.CreateEnrollmentToken;
import org.elasticsearch.xpack.security.tool.BaseRunAsSuperuserCommand;
import org.elasticsearch.xpack.security.tool.CommandLineHttpClient;

import java.util.List;
import java.util.function.Function;

public class CreateEnrollmentTokenTool extends BaseRunAsSuperuserCommand {

private final OptionSpec<String> scope;
private final CheckedFunction<Environment, CreateEnrollmentToken, Exception> createEnrollmentTokenFunction;
static final List<String> ALLOWED_SCOPES = List.of("node", "kibana");

CreateEnrollmentTokenTool() {
this(
environment -> new CommandLineHttpClient(environment),
environment -> KeyStoreWrapper.load(environment.configFile()),
environment -> new CreateEnrollmentToken(environment)
);
}

CreateEnrollmentTokenTool(
Function<Environment, CommandLineHttpClient> clientFunction,
CheckedFunction<Environment, KeyStoreWrapper, Exception> keyStoreFunction,
CheckedFunction<Environment, CreateEnrollmentToken, Exception> createEnrollmentTokenFunction
) {
super(clientFunction, keyStoreFunction, "Creates enrollment tokens for elasticsearch nodes and kibana instances");
jkakavas marked this conversation as resolved.
Show resolved Hide resolved
this.createEnrollmentTokenFunction = createEnrollmentTokenFunction;
scope = parser.acceptsAll(List.of("scope", "s"), "The scope of this enrollment token, can be either \"node\" or \"kibana\"")
.withRequiredArg()
.required();
}

public static void main(String[] args) throws Exception {
exit(new CreateEnrollmentTokenTool().main(args, Terminal.DEFAULT));
}

@Override
protected void validate(Terminal terminal, OptionSet options, Environment env) throws Exception {
if (XPackSettings.ENROLLMENT_ENABLED.get(env.settings()) == false) {
throw new UserException(
ExitCodes.CONFIG,
"[xpack.security.enrollment.enabled] must be set to `true` to create an enrollment token"
);
}
final String tokenScope = scope.value(options);
if (ALLOWED_SCOPES.contains(tokenScope) == false) {
terminal.errorPrintln("The scope of this enrollment token, can only be one of " + ALLOWED_SCOPES);
jkakavas marked this conversation as resolved.
Show resolved Hide resolved
throw new UserException(ExitCodes.USAGE, "Invalid scope");
}
}

@Override
protected void executeCommand(Terminal terminal, OptionSet options, Environment env) throws Exception {
final String username = getUsername();
final String tokenScope = scope.value(options);
try (SecureString password = getPassword()) {
CreateEnrollmentToken createEnrollmentTokenService = createEnrollmentTokenFunction.apply(env);
if (tokenScope.equals("node")) {
terminal.println(createEnrollmentTokenService.createNodeEnrollmentToken(username, password));
} else {
terminal.println(createEnrollmentTokenService.createKibanaEnrollmentToken(username, password));
}
} catch (Exception e) {
terminal.errorPrintln("Unable to create enrollment token for scope [" + tokenScope + "]");
throw new UserException(ExitCodes.CANT_CREATE, e.getMessage(), e.getCause());
}
}
}
Loading