You are viewing a plain text version of this content. The canonical link for it is here.
Posted to dev@directory.apache.org by Colm O hEigeartaigh <co...@apache.org> on 2018/05/03 08:29:39 UTC
Re: directory-kerby git commit: Add HTTPS certification deployment tool.
Hi,
Shouldn't this commit go on trunk instead? What is the current difference
between the has_project and trunk branches?
Colm.
On Thu, May 3, 2018 at 3:10 AM, <ze...@apache.org> wrote:
> Repository: directory-kerby
> Updated Branches:
> refs/heads/has-project aab4c7409 -> b5b9595f1
>
>
> Add HTTPS certification deployment tool.
>
>
> Project: http://git-wip-us.apache.org/repos/asf/directory-kerby/repo
> Commit: http://git-wip-us.apache.org/repos/asf/directory-kerby/
> commit/b5b9595f
> Tree: http://git-wip-us.apache.org/repos/asf/directory-kerby/tree/b5b9595f
> Diff: http://git-wip-us.apache.org/repos/asf/directory-kerby/diff/b5b9595f
>
> Branch: refs/heads/has-project
> Commit: b5b9595f19b4509168b9dbc08cfe6247d925e7e1
> Parents: aab4c74
> Author: zenglinx <fr...@intel.com>
> Authored: Thu May 3 10:10:29 2018 +0800
> Committer: zenglinx <fr...@intel.com>
> Committed: Thu May 3 10:10:29 2018 +0800
>
> ----------------------------------------------------------------------
> has/doc/deploy-https.md | 28 +-
> has/doc/has-start.md | 4 +-
> .../src/main/resources/ssl-client.conf.template | 1 +
> .../server/hadmin/local/HadminLocalTool.java | 8 +-
> .../cmd/AddPrincipalsAndDeployKeytabsCmd.java | 15 +-
> .../hadmin/local/cmd/DeployHTTPSCertsCmd.java | 310 +++++++++++++++++++
> 6 files changed, 355 insertions(+), 11 deletions(-)
> ----------------------------------------------------------------------
>
>
> http://git-wip-us.apache.org/repos/asf/directory-kerby/
> blob/b5b9595f/has/doc/deploy-https.md
> ----------------------------------------------------------------------
> diff --git a/has/doc/deploy-https.md b/has/doc/deploy-https.md
> index 4ae328c..05568fc 100644
> --- a/has/doc/deploy-https.md
> +++ b/has/doc/deploy-https.md
> @@ -38,7 +38,33 @@ When you finish, the {trustAll} file will have the
> certificates from all nodes.
> keytool -list -v -keystore {trustAll}
> ```
>
> -## 7. Edit the Configuration files
> +## 7. Use Hadmin tool to create new certificate files when adding
> machines of cluster
> +When adding machines of cluster, we also provide shell tool to create
> keystore files and update the truststore file.
> +With this tool, user just need one operation, and the certificate and
> configuration files will be generated and deployed.
> +
> +```
> +cd HAS/has-dist
> +echo node1,node2,node3 > hosts.txt
> +
> +// Start local hadmin tool
> +sh bin/hadmin-local.sh <conf_dir> -k <keytab>
> +
> +// deploy_certs [Hosts-File] [truststore_file] [truststore_password]
> [Where-to-Deploy] [SSH-Port] [UserName] [Password]
> +// truststore_file: The absolute path of the above trustAll file
> +// truststore_password: Password of the truststore file
> +// Where-to-Deploy: The place to store the keystore, truststore,
> ssl-client.conf
> +// SSH-Port: The port of SSH
> +// UserName: The host user name
> +// Password: The host password
> +// All the hosts with the same user and password
> +HadminLocalTool.local: deploy_https hosts.txt /etc/has/truststore.jks
> 123456 /etc/has 22 username password
> +HadminLocalTool.local: exit
> +```
> +
> +> Note that the same keypassword and password of keystore is given in the
> generated ssl-client.conf.
> +
> +
> +## 8. Edit the Configuration files
> > Deploy {keystore} and {trustAll} files and config
> /<conf-dir>/ssl-server.conf for HAS server
> ```
> ssl.server.keystore.location = {path to keystore}
>
> http://git-wip-us.apache.org/repos/asf/directory-kerby/
> blob/b5b9595f/has/doc/has-start.md
> ----------------------------------------------------------------------
> diff --git a/has/doc/has-start.md b/has/doc/has-start.md
> index 5d92ae7..46b1d95 100644
> --- a/has/doc/has-start.md
> +++ b/has/doc/has-start.md
> @@ -201,12 +201,12 @@ echo { \
> // Start local hadmin tool
> sh bin/hadmin-local.sh <conf_dir> -k <keytab>
>
> -// deploy_keytabs [HostRoles-File] [Where-to-Deploy] [UserName] [Password]
> +// deploy_keytabs [HostRoles-File] [Where-to-Deploy] [SSH-Port]
> [UserName] [Password]
> // Where-to-Deploy: The place to store the keytabs
> // UserName: The host user name
> // Password: The host password
> // All the hosts with the same user and password
> -HadminLocalTool.local: deploy_keytabs hosts.txt /etc/has/ username
> password
> +HadminLocalTool.local: deploy_keytabs hosts.txt 22 /etc/has/ username
> password
> HadminLocalTool.local: exit
> ```
> Note: The admin.keytab file is created by the kdcinit. In local hadmin
> tool, you can type "?" for help.
>
> http://git-wip-us.apache.org/repos/asf/directory-kerby/
> blob/b5b9595f/has/has-client/src/main/resources/ssl-client.conf.template
> ----------------------------------------------------------------------
> diff --git a/has/has-client/src/main/resources/ssl-client.conf.template
> b/has/has-client/src/main/resources/ssl-client.conf.template
> index c5ca70a..ed5a63f 100644
> --- a/has/has-client/src/main/resources/ssl-client.conf.template
> +++ b/has/has-client/src/main/resources/ssl-client.conf.template
> @@ -18,3 +18,4 @@
>
> ssl.client.truststore.location = _location_
> ssl.client.truststore.password = _password_
> +ssl.server.keystore.password = _keyPassword_
> \ No newline at end of file
>
> http://git-wip-us.apache.org/repos/asf/directory-kerby/
> blob/b5b9595f/has/has-tool/has-server-tool/src/main/java/
> org/apache/kerby/has/tool/server/hadmin/local/HadminLocalTool.java
> ----------------------------------------------------------------------
> diff --git a/has/has-tool/has-server-tool/src/main/java/org/apache/
> kerby/has/tool/server/hadmin/local/HadminLocalTool.java
> b/has/has-tool/has-server-tool/src/main/java/org/apache/
> kerby/has/tool/server/hadmin/local/HadminLocalTool.java
> index 7e4741a..267501a 100644
> --- a/has/has-tool/has-server-tool/src/main/java/org/apache/
> kerby/has/tool/server/hadmin/local/HadminLocalTool.java
> +++ b/has/has-tool/has-server-tool/src/main/java/org/apache/
> kerby/has/tool/server/hadmin/local/HadminLocalTool.java
> @@ -27,6 +27,7 @@ import org.apache.kerby.has.tool.
> server.hadmin.local.cmd.AddPrincipalsAndDeployK
> import org.apache.kerby.has.tool.server.hadmin.local.cmd.
> AddPrincipalsCmd;
> import org.apache.kerby.has.tool.server.hadmin.local.cmd.
> ChangePasswordCmd;
> import org.apache.kerby.has.tool.server.hadmin.local.cmd.
> DeletePrincipalCmd;
> +import org.apache.kerby.has.tool.server.hadmin.local.cmd.
> DeployHTTPSCertsCmd;
> import org.apache.kerby.has.tool.server.hadmin.local.cmd.
> DisableConfigureCmd;
> import org.apache.kerby.has.tool.server.hadmin.local.cmd.
> EnableConfigureCmd;
> import org.apache.kerby.has.tool.server.hadmin.local.cmd.
> ExportKeytabsCmd;
> @@ -103,7 +104,9 @@ public class HadminLocalTool {
> + "disable_configure, disable\n"
> + " Disable configure\n"
> + "deploy_keytabs, depkeytabs\n"
> - + " Deploy keytabs\n";
> + + " Deploy keytabs\n"
> + + "deploy_https, dephttps\n"
> + + " Deploy https\n";
>
> private static void execute(LocalHasAdmin hadmin, String input)
> throws HasException {
> // Omit the leading and trailing whitespace.
> @@ -155,6 +158,9 @@ public class HadminLocalTool {
> } else if (cmd.startsWith("deploy_keytabs")
> || cmd.startsWith("depkeytabs")) {
> executor = new AddPrincipalsAndDeployKeytabsCmd(hadmin);
> + } else if (cmd.startsWith("deploy_https")
> + || cmd.startsWith("dephttps")) {
> + executor = new DeployHTTPSCertsCmd(hadmin);
> } else {
> System.out.println(LEGAL_COMMANDS);
> return;
>
> http://git-wip-us.apache.org/repos/asf/directory-kerby/
> blob/b5b9595f/has/has-tool/has-server-tool/src/main/java/
> org/apache/kerby/has/tool/server/hadmin/local/cmd/
> AddPrincipalsAndDeployKeytabsCmd.java
> ----------------------------------------------------------------------
> diff --git a/has/has-tool/has-server-tool/src/main/java/org/apache/
> kerby/has/tool/server/hadmin/local/cmd/AddPrincipalsAndDeployKeytabsCmd.java
> b/has/has-tool/has-server-tool/src/main/java/org/apache/
> kerby/has/tool/server/hadmin/local/cmd/AddPrincipalsAndDeployKeytabsC
> md.java
> index 21edf20..991ff56 100644
> --- a/has/has-tool/has-server-tool/src/main/java/org/apache/
> kerby/has/tool/server/hadmin/local/cmd/AddPrincipalsAndDeployKeytabsC
> md.java
> +++ b/has/has-tool/has-server-tool/src/main/java/org/apache/
> kerby/has/tool/server/hadmin/local/cmd/AddPrincipalsAndDeployKeytabsC
> md.java
> @@ -41,9 +41,9 @@ import java.util.List;
>
> public class AddPrincipalsAndDeployKeytabsCmd extends HadminCmd {
> private static final String USAGE
> - = "\nUsage: deploy_keytabs [HostRoles-File] [Where-to-Deploy]
> [UserName] [Password]\n"
> + = "\nUsage: deploy_keytabs [HostRoles-File] [Where-to-Deploy]
> [SSH-Port] [UserName] [Password]\n"
> + "\tExample:\n"
> - + "\t\tdeploy_keytabs hostroles.txt /etc/has/ username
> password\n";
> + + "\t\tdeploy_keytabs hostroles.txt /etc/has/ 22 username
> password\n";
>
> public AddPrincipalsAndDeployKeytabsCmd(LocalHasAdmin hadmin) {
> super(hadmin);
> @@ -52,7 +52,7 @@ public class AddPrincipalsAndDeployKeytabsCmd extends
> HadminCmd {
> @Override
> public void execute(String[] items) throws HasException {
>
> - if (items.length < 4 || items.length > 5) {
> + if (items.length < 5 || items.length > 6) {
> System.err.println(USAGE);
> return;
> }
> @@ -62,10 +62,11 @@ public class AddPrincipalsAndDeployKeytabsCmd extends
> HadminCmd {
> throw new HasException("HostRoles file is not exists.");
> }
> String pathToDeploy = items[2];
> - String username = items[3];
> + int port = Integer.valueOf(items[3]);
> + String username = items[4];
> String password = "";
> - if (items.length == 5) {
> - password = items[4];
> + if (items.length == 6) {
> + password = items[5];
> }
>
> BufferedReader reader;
> @@ -123,7 +124,7 @@ public class AddPrincipalsAndDeployKeytabsCmd extends
> HadminCmd {
> JSch jsch = new JSch();
> Session session;
> try {
> - session = jsch.getSession(username, hostname);
> + session = jsch.getSession(username, hostname, port);
> } catch (JSchException e) {
> throw new HasException(e.getMessage());
> }
>
> http://git-wip-us.apache.org/repos/asf/directory-kerby/
> blob/b5b9595f/has/has-tool/has-server-tool/src/main/java/
> org/apache/kerby/has/tool/server/hadmin/local/cmd/DeployHTTPSCertsCmd.java
> ----------------------------------------------------------------------
> diff --git a/has/has-tool/has-server-tool/src/main/java/org/apache/
> kerby/has/tool/server/hadmin/local/cmd/DeployHTTPSCertsCmd.java
> b/has/has-tool/has-server-tool/src/main/java/org/apache/
> kerby/has/tool/server/hadmin/local/cmd/DeployHTTPSCertsCmd.java
> new file mode 100644
> index 0000000..4a16f65
> --- /dev/null
> +++ b/has/has-tool/has-server-tool/src/main/java/org/apache/
> kerby/has/tool/server/hadmin/local/cmd/DeployHTTPSCertsCmd.java
> @@ -0,0 +1,310 @@
> +/**
> + * Licensed to the Apache Software Foundation (ASF) under one
> + * or more contributor license agreements. See the NOTICE file
> + * distributed with this work for additional information
> + * regarding copyright ownership. The ASF licenses this file
> + * to you under the Apache License, Version 2.0 (the
> + * "License"); you may not use this file except in compliance
> + * with the License. You may obtain a copy of the License at
> + *
> + * http://www.apache.org/licenses/LICENSE-2.0
> + *
> + * Unless required by applicable law or agreed to in writing,
> + * software distributed under the License is distributed on an
> + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
> + * KIND, either express or implied. See the License for the
> + * specific language governing permissions and limitations
> + * under the License.
> + *
> + */
> +package org.apache.kerby.has.tool.server.hadmin.local.cmd;
> +
> +import com.jcraft.jsch.ChannelSftp;
> +import com.jcraft.jsch.JSch;
> +import com.jcraft.jsch.JSchException;
> +import com.jcraft.jsch.Session;
> +import com.jcraft.jsch.SftpException;
> +import org.apache.commons.text.CharacterPredicates;
> +import org.apache.commons.text.RandomStringGenerator;
> +import org.apache.kerby.has.common.HasException;
> +import org.apache.kerby.has.server.admin.LocalHasAdmin;
> +import org.apache.kerby.util.IOUtil;
> +import org.bouncycastle.x509.X509V1CertificateGenerator;
> +
> +import javax.security.auth.x500.X500Principal;
> +import java.io.BufferedReader;
> +import java.io.File;
> +import java.io.FileInputStream;
> +import java.io.FileNotFoundException;
> +import java.io.FileOutputStream;
> +import java.io.FileReader;
> +import java.io.InputStream;
> +import java.io.IOException;
> +import java.math.BigInteger;
> +import java.net.InetAddress;
> +import java.net.UnknownHostException;
> +import java.security.GeneralSecurityException;
> +import java.security.InvalidKeyException;
> +import java.security.KeyPair;
> +import java.security.KeyStore;
> +import java.security.KeyPairGenerator;
> +import java.security.NoSuchAlgorithmException;
> +import java.security.SecureRandom;
> +import java.security.SignatureException;
> +import java.security.cert.Certificate;
> +import java.security.cert.CertificateEncodingException;
> +import java.security.cert.X509Certificate;
> +import java.util.Date;
> +import java.util.Map;
> +import java.util.HashMap;
> +import java.util.List;
> +import java.util.ArrayList;
> +
> +/**
> + * HTTPS certifications deploy tool.
> + */
> +public class DeployHTTPSCertsCmd extends HadminCmd {
> + private static final String USAGE
> + = "\nUsage: deploy_certs [Hosts-File] [truststore_file]
> [truststore_password]"
> + + " [Where-to-Deploy] [SSH-Port] [UserName] [Password]\n"
> + + "\tExample:\n"
> + + "\t\tdeploy_https hosts.txt /etc/has/truststore.jks 123456
> /etc/has 22 username password\n";
> +
> + public DeployHTTPSCertsCmd(LocalHasAdmin hadmin) {
> + super(hadmin);
> + }
> +
> + private static KeyPair generateKeyPair() throws
> NoSuchAlgorithmException {
> + KeyPairGenerator keyGen = KeyPairGenerator.getInstance("RSA");
> + keyGen.initialize(1024);
> + return keyGen.genKeyPair();
> + }
> +
> + private static X509Certificate generateCertificate(String args,
> KeyPair pair)
> + throws CertificateEncodingException, InvalidKeyException,
> IllegalStateException,
> + NoSuchAlgorithmException, SignatureException {
> +
> + Date from = new Date();
> + Date to = new Date(from.getTime() + 90 * 86400000L);
> + BigInteger sn = new BigInteger(64, new SecureRandom());
> + X509V1CertificateGenerator certGen = new
> X509V1CertificateGenerator();
> + X500Principal dnName = new X500Principal(args);
> +
> + certGen.setSerialNumber(sn);
> + certGen.setIssuerDN(dnName);
> + certGen.setNotBefore(from);
> + certGen.setNotAfter(to);
> + certGen.setSubjectDN(dnName);
> + certGen.setPublicKey(pair.getPublic());
> + certGen.setSignatureAlgorithm("SHA1withRSA");
> +
> + return certGen.generate(pair.getPrivate());
> + }
> +
> + private static File saveKeyStore(String fileName, KeyStore ks, String
> password)
> + throws GeneralSecurityException, IOException {
> + File keystoreFile = new File(fileName);
> + if (keystoreFile.exists() && !keystoreFile.delete()) {
> + throw new IOException("Failed to delete original file: " +
> fileName);
> + }
> + FileOutputStream out = new FileOutputStream(keystoreFile);
> + ks.store(out, password.toCharArray());
> + out.close();
> + return keystoreFile;
> + }
> +
> + private File createClientSSLConfig(String trustStorePath, String
> trustStorePassword,
> + String keyStorePassword) throws
> HasException {
> + String resourcePath = "/ssl-client.conf.template";
> + InputStream templateResource = getClass().getResourceAsStream(
> resourcePath);
> + File sslConfigFile = new File("ssl-client.conf");
> + try {
> + String content = IOUtil.readInput(templateResource);
> + content = content.replaceAll("_location_", trustStorePath);
> + content = content.replaceAll("_password_",
> trustStorePassword);
> + content = content.replaceAll("_keyPassword_",
> keyStorePassword);
> +
> + IOUtil.writeFile(content, sslConfigFile);
> + return sslConfigFile;
> + } catch (IOException e) {
> + throw new HasException("Failed to create client ssl
> configuration file", e);
> + }
> + }
> +
> + private final class KeyStoreInfo {
> + KeyStore keyStore;
> + String keyPasswd;
> +
> + private KeyStoreInfo(KeyStore keyStore, String keyPasswd) {
> + this.keyStore = keyStore;
> + this.keyPasswd = keyPasswd;
> + }
> +
> + private String getKeyPasswd() {
> + return this.keyPasswd;
> + }
> +
> + private KeyStore getKeyStore() {
> + return this.keyStore;
> + }
> + }
> +
> + @Override
> + public void execute(String[] items) throws HasException {
> +
> + if (items.length < 7 || items.length > 8) {
> + System.err.println(USAGE);
> + return;
> + }
> +
> + File hostFile = new File(items[1]);
> + if (!hostFile.exists()) {
> + throw new HasException("Host file is not exist.");
> + }
> + String truststoreFile = items[2];
> + String truststoreSecret = items[3];
> + String pathToDeploy = items[4];
> + int port = Integer.valueOf(items[5]);
> + String username = items[6];
> + String password = "";
> + if (items.length == 8) {
> + password = items[7];
> + }
> +
> + // Get hosts from host file
> + BufferedReader reader;
> + try {
> + reader = new BufferedReader(new FileReader(hostFile));
> + } catch (FileNotFoundException e) {
> + throw new HasException("The hosts file: " + hostFile
> + + "is not exist. " + e.getMessage());
> + }
> + StringBuilder sb = new StringBuilder();
> + String tempString;
> + try {
> + while ((tempString = reader.readLine()) != null) {
> + sb.append(tempString);
> + }
> + } catch (IOException e1) {
> + throw new HasException("Failed to read file: " +
> e1.getMessage());
> + }
> + String[] hostArray = sb.toString().replace(" ", "").split(",");
> +
> + // Get truststore from truststore file
> + Map<String, KeyStoreInfo> keyStoreInfoMap = new HashMap<>(16);
> + KeyStore trustStore;
> + try {
> + trustStore = KeyStore.getInstance("JKS");
> + FileInputStream in = new FileInputStream(truststoreFile);
> + trustStore.load(in, truststoreSecret.toCharArray());
> + } catch (Exception e2) {
> + throw new HasException("Failed to get truststore from the
> file: "
> + + truststoreFile, e2);
> + }
> + RandomStringGenerator generator = new
> RandomStringGenerator.Builder()
> + .withinRange('a', 'z')
> + .filteredBy(CharacterPredicates.LETTERS,
> CharacterPredicates.DIGITS)
> + .build();
> +
> + // Generate keystore map
> + for (String hostname : hostArray) {
> + try {
> + InetAddress inetAddress = InetAddress.getLocalHost();
> + String localHostname = inetAddress.getHostName();
> + if (hostname.equals(localHostname)) {
> + continue;
> + }
> + } catch (UnknownHostException e3) {
> + throw new HasException("Failed to get local hostname.",
> e3);
> + }
> +
> + KeyStore ks;
> + try {
> + KeyPair cKP = generateKeyPair();
> + String keyPassword = generator.generate(15);
> + X509Certificate cert = generateCertificate("CN=" +
> hostname + ", O=has", cKP);
> + ks = KeyStore.getInstance("JKS");
> + ks.load(null, null);
> + ks.setKeyEntry(hostname, cKP.getPrivate(),
> keyPassword.toCharArray(),
> + new Certificate[]{cert});
> + KeyStoreInfo keyStoreInfo = new KeyStoreInfo(ks,
> keyPassword);
> + keyStoreInfoMap.put(hostname, keyStoreInfo);
> + trustStore.setCertificateEntry(hostname, cert);
> + } catch (Exception e4) {
> + throw new HasException("Failed to generate keystore.",
> e4);
> + }
> + }
> +
> + File finalTrustStoreFile;
> + try {
> + finalTrustStoreFile = saveKeyStore(truststoreFile,
> trustStore, password);
> + } catch (Exception e5) {
> + throw new HasException("Failed to generate trust store
> files.", e5);
> + }
> +
> + // Generate keystore, truststore, ssl config files and transfer
> them to destination
> + for (String hostname : hostArray) {
> + List<File> files = new ArrayList<>(3);
> + try {
> + KeyStoreInfo keyStoreInfo = keyStoreInfoMap.get(hostname);
> + File file = saveKeyStore(hostname + "_keystore.jks",
> + keyStoreInfo.getKeyStore(),
> keyStoreInfo.getKeyPasswd());
> + files.add(file);
> + files.add(finalTrustStoreFile);
> + files.add(createClientSSLConfig(pathToDeploy +
> "/truststore.jks",
> + truststoreSecret, keyStoreInfo.getKeyPasswd()));
> + } catch (Exception e6) {
> + throw new HasException("Failed to generate key store
> files.", e6);
> + }
> +
> + JSch jsch = new JSch();
> + Session session;
> + try {
> + session = jsch.getSession(username, hostname, port);
> + } catch (JSchException e7) {
> + throw new HasException(e7.getMessage());
> + }
> + session.setPassword(password);
> +
> + java.util.Properties config = new java.util.Properties();
> + config.put("StrictHostKeyChecking", "no");
> + session.setConfig(config);
> +
> + ChannelSftp channel;
> + try {
> + session.connect();
> + channel = (ChannelSftp) session.openChannel("sftp");
> + channel.connect();
> + } catch (JSchException e8) {
> + throw new HasException("Failed to set the session: " +
> e8.getMessage());
> + }
> + try {
> + String path = "";
> + String[] paths = pathToDeploy.split("/");
> + for (int i = 1; i < paths.length; i++) {
> + path = path + "/" + paths[i];
> + try {
> + channel.cd(path);
> + } catch (SftpException e9) {
> + if (e9.id == ChannelSftp.SSH_FX_NO_SUCH_FILE) {
> + channel.mkdir(path);
> + } else {
> + throw new HasException(e9.getMessage());
> + }
> + }
> + }
> + } catch (SftpException e10) {
> + throw new HasException("Failed to mkdir path: " + e10);
> + }
> +
> + for (File file : files) {
> + try {
> + channel.put(file.getAbsolutePath(), file.getName());
> + } catch (SftpException e10) {
> + throw new HasException("Failed to send the https cert
> files.", e10);
> + }
> + }
> + channel.disconnect();
> + }
> + }
> +}
>
>
--
Colm O hEigeartaigh
Talend Community Coder
http://coders.talend.com