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, <zengl...@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 <frank.z...@intel.com> > Authored: Thu May 3 10:10:29 2018 +0800 > Committer: zenglinx <frank.z...@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