aboutsummaryrefslogtreecommitdiffstats
path: root/security-tools/src/main
diff options
context:
space:
mode:
authorBjørn Christian Seime <bjorncs@verizonmedia.com>2019-05-31 16:18:56 +0200
committerBjørn Christian Seime <bjorncs@verizonmedia.com>2019-05-31 16:18:56 +0200
commit628432bf640ef1c20c39718dcbb508e4a56bf8b8 (patch)
tree48142da36f0a1e716424dcfe5aaa27c9c963df8a /security-tools/src/main
parentb0c953ea8f0c6ad4e757797001de85639b3ccdda (diff)
Add implementation of the 'vespa-security-env' tool
Diffstat (limited to 'security-tools/src/main')
-rw-r--r--security-tools/src/main/java/com/yahoo/vespa/security/tool/securityenv/CliOptions.java69
-rw-r--r--security-tools/src/main/java/com/yahoo/vespa/security/tool/securityenv/Main.java78
-rw-r--r--security-tools/src/main/java/com/yahoo/vespa/security/tool/securityenv/OutputVariable.java29
-rw-r--r--security-tools/src/main/java/com/yahoo/vespa/security/tool/securityenv/UnixShell.java74
4 files changed, 249 insertions, 1 deletions
diff --git a/security-tools/src/main/java/com/yahoo/vespa/security/tool/securityenv/CliOptions.java b/security-tools/src/main/java/com/yahoo/vespa/security/tool/securityenv/CliOptions.java
new file mode 100644
index 00000000000..f3ec73236c4
--- /dev/null
+++ b/security-tools/src/main/java/com/yahoo/vespa/security/tool/securityenv/CliOptions.java
@@ -0,0 +1,69 @@
+// Copyright 2019 Oath Inc. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root.
+package com.yahoo.vespa.security.tool.securityenv;
+
+import com.yahoo.security.tls.TransportSecurityUtils;
+import org.apache.commons.cli.CommandLine;
+import org.apache.commons.cli.CommandLineParser;
+import org.apache.commons.cli.DefaultParser;
+import org.apache.commons.cli.HelpFormatter;
+import org.apache.commons.cli.Option;
+import org.apache.commons.cli.Options;
+import org.apache.commons.cli.ParseException;
+
+import java.io.PrintStream;
+import java.io.PrintWriter;
+import java.util.Arrays;
+
+import static java.util.stream.Collectors.joining;
+
+/**
+ * Defines the program's command line parameters.
+ *
+ * @author bjorncs
+ */
+class CliOptions {
+ static final String SHELL_OPTION = "shell";
+ static final String HELP_OPTION = "help";
+
+ private static final Options OPTIONS = new Options()
+ .addOption(
+ Option.builder("s")
+ .longOpt(SHELL_OPTION)
+ .hasArg(true)
+ .required(false)
+ .desc(String.format("Shell type. Shell type is auto-detected if option not present. Valid values: %s.",
+ Arrays.stream(UnixShell.values())
+ .map(shell -> String.format("'%s'", shell.configName()))
+ .collect(joining(", ", "[", "]"))))
+ .build())
+ .addOption(Option.builder("h")
+ .longOpt(HELP_OPTION)
+ .hasArg(false)
+ .required(false)
+ .desc("Show help")
+ .build());
+
+ static CommandLine parseCliArguments(String[] cliArgs) throws ParseException {
+ CommandLineParser parser = new DefaultParser();
+ return parser.parse(OPTIONS, cliArgs);
+ }
+
+ static void printHelp(PrintStream out) {
+ HelpFormatter formatter = new HelpFormatter();
+ PrintWriter writer = new PrintWriter(out);
+ formatter.printHelp(
+ writer,
+ formatter.getWidth(),
+ "vespa-security-env <options>",
+ String.format("Generates shell commands that defines environments variables based on the content of %s.",
+ TransportSecurityUtils.CONFIG_FILE_ENVIRONMENT_VARIABLE),
+ OPTIONS,
+ formatter.getLeftPadding(),
+ formatter.getDescPadding(),
+ String.format("The output may include the following variables:\n%s\n",
+ Arrays.stream(OutputVariable.values())
+ .map(variable -> String.format(" - '%s': %s", variable.variableName(), variable.description()))
+ .collect(joining("\n"))));
+ writer.flush();
+ }
+}
diff --git a/security-tools/src/main/java/com/yahoo/vespa/security/tool/securityenv/Main.java b/security-tools/src/main/java/com/yahoo/vespa/security/tool/securityenv/Main.java
index f57575b406a..74c08c2d602 100644
--- a/security-tools/src/main/java/com/yahoo/vespa/security/tool/securityenv/Main.java
+++ b/security-tools/src/main/java/com/yahoo/vespa/security/tool/securityenv/Main.java
@@ -1,11 +1,87 @@
// Copyright 2019 Oath Inc. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root.
package com.yahoo.vespa.security.tool.securityenv;
+import com.yahoo.security.tls.MixedMode;
+import com.yahoo.security.tls.TransportSecurityOptions;
+import com.yahoo.security.tls.TransportSecurityUtils;
+import org.apache.commons.cli.CommandLine;
+import org.apache.commons.cli.ParseException;
+
+import java.io.PrintStream;
+import java.util.Map;
+import java.util.Optional;
+import java.util.TreeMap;
+
+import static com.yahoo.vespa.security.tool.securityenv.CliOptions.HELP_OPTION;
+import static com.yahoo.vespa.security.tool.securityenv.CliOptions.SHELL_OPTION;
+
/**
+ * Implementation of the 'vespa-security-env' command line utility.
+ *
* @author bjorncs
*/
public class Main {
+
+ private final PrintStream stdOut;
+ private final PrintStream stdError;
+
+ Main(PrintStream stdOut, PrintStream stdError) {
+ this.stdOut = stdOut;
+ this.stdError = stdError;
+ }
+
public static void main(String[] args) {
- System.out.println("TODO implementation");
+ Main program = new Main(System.out, System.err);
+ int statusCode = program.execute(args, System.getenv());
+ System.exit(statusCode);
+ }
+
+ int execute(String[] cliArgs, Map<String, String> envVars) {
+ boolean debugMode = envVars.containsKey("VESPA_DEBUG");
+ try {
+ CommandLine arguments = CliOptions.parseCliArguments(cliArgs);
+ if (arguments.hasOption(HELP_OPTION)) {
+ CliOptions.printHelp(stdOut);
+ return 0;
+ }
+ UnixShell shell = arguments.hasOption(SHELL_OPTION)
+ ? UnixShell.fromConfigName(arguments.getOptionValue(SHELL_OPTION))
+ : UnixShell.detect(envVars.get("SHELL"));
+
+ Optional<TransportSecurityOptions> options = TransportSecurityUtils.getOptions(envVars);
+ if (options.isEmpty()) {
+ return 0;
+ }
+ Map<String, String> outputVariables = new TreeMap<>();
+ options.get().getCaCertificatesFile()
+ .ifPresent(caCertFile -> addOutputVariable(outputVariables, OutputVariable.CA_CERTIFICATE, caCertFile.toString()));
+ MixedMode mixedMode = TransportSecurityUtils.getInsecureMixedMode(envVars);
+ if (mixedMode != MixedMode.PLAINTEXT_CLIENT_MIXED_SERVER) {
+ options.get().getCertificatesFile()
+ .ifPresent(certificateFile -> addOutputVariable(outputVariables, OutputVariable.CERTIFICATE, certificateFile.toString()));
+ options.get().getPrivateKeyFile()
+ .ifPresent(privateKeyFile -> addOutputVariable(outputVariables, OutputVariable.PRIVATE_KEY, privateKeyFile.toString()));
+ }
+ shell.writeOutputVariables(stdOut, outputVariables);
+ return 0;
+ } catch (ParseException e) {
+ return handleException("Failed to parse command line arguments: " + e.getMessage(), e, debugMode);
+ } catch (IllegalArgumentException e) {
+ return handleException("Invalid command line arguments: " + e.getMessage(), e, debugMode);
+ } catch (Exception e) {
+ return handleException("Failed to generate security environment variables: " + e.getMessage(), e, debugMode);
+ }
+ }
+
+ private static void addOutputVariable(Map<String, String> outputVariables, OutputVariable variable, String value) {
+ outputVariables.put(variable.variableName(), value);
+ }
+
+ private int handleException(String message, Exception exception, boolean debugMode) {
+ stdError.println(message);
+ if (debugMode) {
+ exception.printStackTrace(stdError);
+ }
+ return 1;
}
}
diff --git a/security-tools/src/main/java/com/yahoo/vespa/security/tool/securityenv/OutputVariable.java b/security-tools/src/main/java/com/yahoo/vespa/security/tool/securityenv/OutputVariable.java
new file mode 100644
index 00000000000..9cd4cc1fc67
--- /dev/null
+++ b/security-tools/src/main/java/com/yahoo/vespa/security/tool/securityenv/OutputVariable.java
@@ -0,0 +1,29 @@
+// Copyright 2019 Oath Inc. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root.
+package com.yahoo.vespa.security.tool.securityenv;
+
+/**
+ * Define the possible environment variables that the program may output.
+ *
+ * @author bjorncs
+ */
+enum OutputVariable {
+ CA_CERTIFICATE("VESPA_TLS_CA_CERT", "Path to CA certificates file"),
+ CERTIFICATE("VESPA_TLS_CERT", "Path to certificate file"),
+ PRIVATE_KEY("VESPA_TLS_PRIVATE_KEY", "Path to private key file");
+
+ private final String variableName;
+ private final String description;
+
+ OutputVariable(String variableName, String description) {
+ this.variableName = variableName;
+ this.description = description;
+ }
+
+ String variableName() {
+ return variableName;
+ }
+
+ String description() {
+ return description;
+ }
+}
diff --git a/security-tools/src/main/java/com/yahoo/vespa/security/tool/securityenv/UnixShell.java b/security-tools/src/main/java/com/yahoo/vespa/security/tool/securityenv/UnixShell.java
new file mode 100644
index 00000000000..1b4a9696c69
--- /dev/null
+++ b/security-tools/src/main/java/com/yahoo/vespa/security/tool/securityenv/UnixShell.java
@@ -0,0 +1,74 @@
+// Copyright 2019 Oath Inc. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root.
+package com.yahoo.vespa.security.tool.securityenv;
+
+import java.io.PrintStream;
+import java.util.Arrays;
+import java.util.List;
+import java.util.Map;
+
+/**
+ * Definition of some unix shell variants and how to export environments variable for those supported.
+ * The output format is inspired by ssh-agent's output.
+ *
+ * @author bjorncs
+ */
+enum UnixShell {
+ BOURNE("bourne", List.of("bash", "sh")) {
+ @Override
+ void writeOutputVariables(PrintStream out, Map<String, String> outputVariables) {
+ outputVariables.forEach((name, value) -> {
+ out.print(name);
+ out.print('=');
+ out.print(value); // note: value is assumed to need no escaping
+ out.print("; export ");
+ out.print(name);
+ out.println(';');
+ });
+ }
+ },
+ CSHELL("cshell", List.of("csh", "fish")) {
+ @Override
+ void writeOutputVariables(PrintStream out, Map<String, String> outputVariables) {
+ outputVariables.forEach((name, value) -> {
+ out.print("setenv ");
+ out.print(name);
+ out.print(' ');
+ out.print(value); // note: value is assumed to need no escaping
+ out.println(';');
+ });
+ }
+ };
+
+ private static final UnixShell DEFAULT = BOURNE;
+
+ private final String configName;
+ private final List<String> knownShellBinaries;
+
+ UnixShell(String configName, List<String> knownShellBinaries) {
+ this.configName = configName;
+ this.knownShellBinaries = knownShellBinaries;
+ }
+
+ abstract void writeOutputVariables(PrintStream out, Map<String, String> outputVariables);
+
+ String configName() {
+ return configName;
+ }
+
+ static UnixShell fromConfigName(String configName) {
+ return Arrays.stream(values())
+ .filter(shell -> shell.configName.equals(configName))
+ .findAny()
+ .orElseThrow(() -> new IllegalArgumentException("Unknown shell: " + configName));
+ }
+
+ static UnixShell detect(String shellEnvVariable) {
+ if (shellEnvVariable == null || shellEnvVariable.isEmpty()) return DEFAULT;
+ int lastSlash = shellEnvVariable.lastIndexOf('/');
+ String shellName = lastSlash != -1 ? shellEnvVariable.substring(lastSlash + 1) : shellEnvVariable;
+ return Arrays.stream(values())
+ .filter(shell -> shell.knownShellBinaries.contains(shellName))
+ .findAny()
+ .orElse(DEFAULT);
+ }
+}