Repository: brooklyn-library Updated Branches: refs/heads/master a06cb1554 -> 532f373f7
Support proxying with TLS client certificates in Nginx Project: http://git-wip-us.apache.org/repos/asf/brooklyn-library/repo Commit: http://git-wip-us.apache.org/repos/asf/brooklyn-library/commit/835ba7e9 Tree: http://git-wip-us.apache.org/repos/asf/brooklyn-library/tree/835ba7e9 Diff: http://git-wip-us.apache.org/repos/asf/brooklyn-library/diff/835ba7e9 Branch: refs/heads/master Commit: 835ba7e92e277524ed8f6e566b4bfa8774fe8e58 Parents: 7b1a9f7 Author: Andrew Donald Kennedy <andrew.kenn...@cloudsoftcorp.com> Authored: Thu Jul 14 18:12:36 2016 +0100 Committer: Andrew Donald Kennedy <andrew.kenn...@cloudsoftcorp.com> Committed: Fri Jul 29 16:09:19 2016 +0100 ---------------------------------------------------------------------- .../brooklyn/entity/proxy/ProxySslConfig.java | 51 ++++++++++++++++++- .../nginx/NginxDefaultConfigGenerator.java | 52 ++++++++++++++++++-- 2 files changed, 99 insertions(+), 4 deletions(-) ---------------------------------------------------------------------- http://git-wip-us.apache.org/repos/asf/brooklyn-library/blob/835ba7e9/software/webapp/src/main/java/org/apache/brooklyn/entity/proxy/ProxySslConfig.java ---------------------------------------------------------------------- diff --git a/software/webapp/src/main/java/org/apache/brooklyn/entity/proxy/ProxySslConfig.java b/software/webapp/src/main/java/org/apache/brooklyn/entity/proxy/ProxySslConfig.java index 71a8bf1..95bfdf8 100644 --- a/software/webapp/src/main/java/org/apache/brooklyn/entity/proxy/ProxySslConfig.java +++ b/software/webapp/src/main/java/org/apache/brooklyn/entity/proxy/ProxySslConfig.java @@ -41,8 +41,11 @@ public class ProxySslConfig implements Serializable { public static class Builder { @SetFromFlag protected String certificateSourceUrl; @SetFromFlag protected String keySourceUrl; + @SetFromFlag protected String clientCertificateSourceUrl; @SetFromFlag protected String certificateDestination; @SetFromFlag protected String keyDestination; + @SetFromFlag protected String clientCertificateDestination; + @SetFromFlag protected boolean verifyClient = false; @SetFromFlag protected boolean targetIsSsl = false; @SetFromFlag protected boolean reuseSessions = false; @@ -52,12 +55,21 @@ public class ProxySslConfig implements Serializable { public Builder keySourceUrl(String val) { keySourceUrl = val; return this; } + public Builder clientCertificateSourceUrl(String val) { + clientCertificateSourceUrl = val; return this; + } public Builder certificateDestination(String val) { certificateDestination = val; return this; } public Builder keyDestination(String val) { keyDestination = val; return this; } + public Builder clientCertificateDestination(String val) { + clientCertificateDestination = val; return this; + } + public Builder verifyClient(boolean val) { + verifyClient = val; return this; + } public Builder targetIsSsl(boolean val) { targetIsSsl = val; return this; } @@ -79,8 +91,11 @@ public class ProxySslConfig implements Serializable { private String certificateSourceUrl; private String keySourceUrl; + private String clientCertificateSourceUrl; private String certificateDestination; private String keyDestination; + private String clientCertificateDestination; + private boolean verifyClient = false; private boolean targetIsSsl = false; private boolean reuseSessions = false; @@ -89,8 +104,11 @@ public class ProxySslConfig implements Serializable { protected ProxySslConfig(Builder builder) { certificateSourceUrl = builder.certificateSourceUrl; keySourceUrl = builder.keySourceUrl; + clientCertificateSourceUrl = builder.clientCertificateSourceUrl; certificateDestination = builder.certificateDestination; keyDestination = builder.keyDestination; + clientCertificateDestination = builder.clientCertificateDestination; + verifyClient = builder.verifyClient; targetIsSsl = builder.targetIsSsl; reuseSessions = builder.reuseSessions; } @@ -131,6 +149,14 @@ public class ProxySslConfig implements Serializable { this.keySourceUrl = keySourceUrl; } + public String getClientCertificateSourceUrl() { + return clientCertificateSourceUrl; + } + + public void setClientCertificateSourceUrl(String clientCertificateSourceUrl) { + this.clientCertificateSourceUrl = clientCertificateSourceUrl; + } + /** * Sets the {@code ssl_certificate_path} to be used within the generated * {@link LoadBalancer} configuration. @@ -171,6 +197,25 @@ public class ProxySslConfig implements Serializable { this.keyDestination = keyDestination; } + public String getClientCertificateDestination() { + return clientCertificateDestination; + } + + public void setClientCertificateDestination(String clientCertificateDestination) { + this.clientCertificateDestination = clientCertificateDestination; + } + + /** + * Whether to verify the client using certificates; default false. + */ + public boolean getVerifyClient() { + return verifyClient; + } + + public void setVerifyClient(boolean verifyClient) { + this.verifyClient = verifyClient; + } + /** * Whether the downstream server (if mapping) also expects https; default false. */ @@ -197,7 +242,8 @@ public class ProxySslConfig implements Serializable { @Override public int hashCode() { - return Objects.hashCode(certificateSourceUrl, keySourceUrl, certificateDestination, keyDestination, reuseSessions, targetIsSsl); + return Objects.hashCode(certificateSourceUrl, keySourceUrl, certificateDestination, keyDestination, + clientCertificateSourceUrl, clientCertificateDestination, verifyClient, reuseSessions, targetIsSsl); } @Override @@ -212,6 +258,9 @@ public class ProxySslConfig implements Serializable { Objects.equal(certificateDestination, other.certificateDestination) && Objects.equal(keyDestination, other.keyDestination) && Objects.equal(keySourceUrl, other.keySourceUrl) && + Objects.equal(clientCertificateSourceUrl, other.clientCertificateSourceUrl) && + Objects.equal(clientCertificateDestination, other.clientCertificateDestination) && + Objects.equal(verifyClient, other.verifyClient) && Objects.equal(reuseSessions, other.reuseSessions) && Objects.equal(targetIsSsl, other.targetIsSsl); } http://git-wip-us.apache.org/repos/asf/brooklyn-library/blob/835ba7e9/software/webapp/src/main/java/org/apache/brooklyn/entity/proxy/nginx/NginxDefaultConfigGenerator.java ---------------------------------------------------------------------- diff --git a/software/webapp/src/main/java/org/apache/brooklyn/entity/proxy/nginx/NginxDefaultConfigGenerator.java b/software/webapp/src/main/java/org/apache/brooklyn/entity/proxy/nginx/NginxDefaultConfigGenerator.java index 0d82cc4..bbe81aa 100644 --- a/software/webapp/src/main/java/org/apache/brooklyn/entity/proxy/nginx/NginxDefaultConfigGenerator.java +++ b/software/webapp/src/main/java/org/apache/brooklyn/entity/proxy/nginx/NginxDefaultConfigGenerator.java @@ -78,6 +78,7 @@ public class NginxDefaultConfigGenerator implements NginxConfigFileGenerator { config.append(" }\n"); config.append(" server {\n"); config.append(getCodeForServerConfig()); + appendCodeForProxySSLConfig(nginx.getId(), config, " ", globalSslConfig); config.append(" listen "+nginx.getPort()+";\n"); if (nginx.getDomain()!=null) config.append(" server_name "+nginx.getDomain()+";\n"); @@ -146,6 +147,7 @@ public class NginxDefaultConfigGenerator implements NginxConfigFileGenerator { } if (localSslConfig != null) { appendSslConfig(domain, config, " ", localSslConfig, true, true); + appendCodeForProxySSLConfig(domain, config, " ", localSslConfig); } for (UrlMapping mappingInDomain : mappingsByDomain.get(domain)) { @@ -188,7 +190,7 @@ public class NginxDefaultConfigGenerator implements NginxConfigFileGenerator { protected String getCodeForServerConfig() { // See http://wiki.nginx.org/HttpProxyModule - return ""+ + return "" + // this prevents nginx from reporting version number on error pages " server_tokens off;\n"+ @@ -203,6 +205,37 @@ public class NginxDefaultConfigGenerator implements NginxConfigFileGenerator { " proxy_set_header X-Real-IP $remote_addr;\n"; } + protected void appendCodeForProxySSLConfig(String id, StringBuilder out, String prefix, ProxySslConfig ssl) { + if (ssl.getTargetIsSsl() && ssl.getVerifyClient()) { + // Send 403 if not verified, otherwise pass on the client certificate we received + out.append(prefix).append("if ($ssl_client_verify != SUCCESS) { return 403; }\n"); + out.append(prefix).append("proxy_set_header ssl.client_cert $ssl_client_cert;\n"); + + // Use the configured SSL certificate and key for the proxied server + String cert; + if (Strings.isEmpty(ssl.getCertificateDestination())) { + cert = "" + id + ".crt"; + } else { + cert = ssl.getCertificateDestination(); + } + out.append(prefix); + out.append("proxy_ssl_certificate " + cert + ";\n"); + + String key; + if (!Strings.isEmpty(ssl.getKeyDestination())) { + key = ssl.getKeyDestination(); + } else if (!Strings.isEmpty(ssl.getKeySourceUrl())) { + key = "" + id + ".key"; + } else { + key = null; + } + if (key != null) { + out.append(prefix); + out.append("proxy_ssl_certificate_key " + key + ";\n"); + } + } + } + protected String getCodeFor404() { return " return 404;\n"; } @@ -231,7 +264,6 @@ public class NginxDefaultConfigGenerator implements NginxConfigFileGenerator { } else { cert = ssl.getCertificateDestination(); } - out.append(prefix); out.append("ssl_certificate " + cert + ";\n"); @@ -243,12 +275,26 @@ public class NginxDefaultConfigGenerator implements NginxConfigFileGenerator { } else { key = null; } - if (key != null) { out.append(prefix); out.append("ssl_certificate_key " + key + ";\n"); } + if (ssl.getVerifyClient()) { + out.append("ssl_verify_client on;\n"); + + String client; + if (Strings.isEmpty(ssl.getClientCertificateDestination())) { + client = "" + id + ".cli"; + } else { + client = ssl.getClientCertificateDestination(); + } + if (client != null) { + out.append(prefix); + out.append("ssl_client_certificate " + client + ";\n"); + } + } + out.append("ssl_protocols TLSv1 TLSv1.1 TLSv1.2;\n"); } return true;