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

HPCC-30411 Add support for dynamically updating TLS config #17851

Merged
merged 1 commit into from
Nov 15, 2023
Merged
Show file tree
Hide file tree
Changes from all 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
5 changes: 4 additions & 1 deletion common/thorhelper/thorsoapcall.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1242,7 +1242,10 @@ class CWSCHelper : implements IWSCHelper, public CInterface
if (!ownedSC)
{
if (clientCert != NULL)
ownedSC.setown(createSecureSocketContextEx(clientCert->certificate, clientCert->privateKey, clientCert->passphrase, ClientSocket));
{
Owned<IPropertyTree> config = createSecureSocketConfig(clientCert->certificate, clientCert->privateKey, clientCert->passphrase);
ownedSC.setown(createSecureSocketContextEx2(config, ClientSocket));
}
else if (clientCertIssuer.length())
ownedSC.setown(createSecureSocketContextSecret(clientCertIssuer.str(), ClientSocket));
afishbeck marked this conversation as resolved.
Show resolved Hide resolved
else
Expand Down
2 changes: 1 addition & 1 deletion esp/bindings/http/client/httpclient.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -123,7 +123,7 @@ IHttpClient* CHttpClientContext::createHttpClient(const char* proxy, const char*
if (xproc)
m_ssctx.setown(xproc(m_config.get(),ClientSocket));
else
throw MakeStringException(-1, "procedure createSecureSocketContext can't be loaded");
throw MakeStringException(-1, "procedure createSecureSocketContextEx2 can't be loaded");

}
if(m_ssctx.get() == NULL)
Expand Down
25 changes: 12 additions & 13 deletions esp/clients/wsdfuaccess/wsdfuaccess.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -534,7 +534,6 @@ StringBuffer &encodeDFUFileMeta(StringBuffer &metaInfoBlob, IPropertyTree *metaI
metaInfo->serialize(metaInfoBlob);
const char *keyPairName = metaInfo->queryProp("keyPairName"); // NB: in container mode, this is the name of the secret containing the cert.

const char *privateKeyFName = nullptr;
Owned<IPropertyTree> metaInfoEnvelope = createPTree();
#ifdef _CONTAINERIZED
/* Encode the public certificate in the request. NB: this is an approach used for JWT token delegation.
Expand All @@ -543,24 +542,24 @@ StringBuffer &encodeDFUFileMeta(StringBuffer &metaInfoBlob, IPropertyTree *metaI
* If the size of this initial request was ever a concern, we could consider other ways to ensure a one-off
* delivery of this esp public signing cert. to dafilesrv, e.g. by dafilesrv reaching out to esp to request it.
*/
Owned<IPropertyTree> info = getIssuerTlsServerConfig(keyPairName);
if (!info)
Owned<const ISyncedPropertyTree> config = getIssuerTlsSyncedConfig(keyPairName);
if (!config || !config->isValid())
throw makeStringExceptionV(-1, "encodeDFUFileMeta: No '%s' MTLS certificate detected.", keyPairName);
privateKeyFName = info->queryProp("privatekey");
if (isEmptyString(privateKeyFName))
throw makeStringException(-1, "encodeDFUFileMeta: MTLS - private path missing");
const char *certPath = info->queryProp("certificate");
verifyex(certPath);
StringBuffer certificate;
certificate.loadFile(certPath);
verifyex(certificate.length());

Owned<const IPropertyTree> info = config->getTree();
const char *privateKeyText = info->queryProp("privatekey");
if (isEmptyString(privateKeyText))
throw makeStringException(-1, "encodeDFUFileMeta: MTLS - private key missing");
const char *certificate = info->queryProp("certificate");
verifyex(certificate);
metaInfoEnvelope->setProp("certificate", certificate);
Owned<CLoadedKey> privateKey = loadPrivateKeyFromMemory(privateKeyText, nullptr);
#else
privateKeyFName = environment->getPrivateKeyPath(keyPairName);
const char *privateKeyFName = environment->getPrivateKeyPath(keyPairName);
if (isEmptyString(privateKeyFName))
throw makeStringExceptionV(-1, "Key name '%s' is not found in environment settings: /EnvSettings/Keys/KeyPair.", keyPairName);
#endif
Owned<CLoadedKey> privateKey = loadPrivateKeyFromFile(privateKeyFName, nullptr);
#endif
StringBuffer metaInfoSignature;
digiSign(metaInfoSignature, metaInfoBlob.length(), metaInfoBlob.bytes(), *privateKey);

Expand Down
6 changes: 2 additions & 4 deletions esp/services/ws_dfu/ws_dfuService.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -6113,8 +6113,7 @@ void CWsDfuEx::dFUFileAccessCommon(IEspContext &context, const CDfsLogicalFileNa
StringBuffer dafilesrvHost;
#ifdef _CONTAINERIZED
keyPairName.set("signing");
Owned<IPropertyTree> info = getIssuerTlsServerConfig(keyPairName);
if (!info)
if (!hasIssuerTlsConfig(keyPairName))
throw makeStringExceptionV(-1, "dFUFileAccessCommon: file signing certificate ('%s') not defined in configuration.", keyPairName.str());

auto externalService = k8s::getDafileServiceFromConfig("stream");
Expand Down Expand Up @@ -6490,8 +6489,7 @@ bool CWsDfuEx::onDFUFileCreateV2(IEspContext &context, IEspDFUFileCreateV2Reques

#ifdef _CONTAINERIZED
keyPairName.set("signing");
Owned<IPropertyTree> info = getIssuerTlsServerConfig(keyPairName);
if (!info)
if (!hasIssuerTlsConfig(keyPairName))
throw makeStringExceptionV(-1, "onDFUFileCreateV2: file signing certificate ('%s' ) not defined in configuration.", keyPairName.str());

const char *planeName = clusterName;
Expand Down
15 changes: 3 additions & 12 deletions esp/test/httptest/httptest.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -152,10 +152,7 @@ HttpClient::HttpClient(int threads, int times, const char* host, int port, FILE*
if(use_ssl)
{
#ifdef _USE_OPENSSL
if(sslconfig != NULL)
m_ssctx.setown(createSecureSocketContextEx2(sslconfig, ClientSocket));
else
m_ssctx.setown(createSecureSocketContext(ClientSocket));
m_ssctx.setown(createSecureSocketContextEx2(sslconfig, ClientSocket));
#else
throw MakeStringException(-1, "HttpClient: failure to create SSL connection to host '%s': OpenSSL not enabled in build", host);
#endif
Expand Down Expand Up @@ -614,10 +611,7 @@ HttpServer::HttpServer(int port, const char* in, FILE* ofile, bool use_ssl, IPro
if(use_ssl)
{
#ifdef _USE_OPENSSL
if(sslconfig != NULL)
m_ssctx.setown(createSecureSocketContextEx2(sslconfig, ServerSocket));
else
m_ssctx.setown(createSecureSocketContext(ServerSocket));
m_ssctx.setown(createSecureSocketContextEx2(sslconfig, ServerSocket));
#else
throw MakeStringException(-1, "HttpServer: failure to create SSL socket - OpenSSL not enabled in build");
#endif
Expand Down Expand Up @@ -1180,10 +1174,7 @@ HttpProxy::HttpProxy(int localport, const char* host, int port, FILE* ofile, boo
if(use_ssl)
{
#if _USE_OPENSSL
if(sslconfig != NULL)
m_ssctx.setown(createSecureSocketContextEx2(sslconfig, ClientSocket));
else
m_ssctx.setown(createSecureSocketContext(ClientSocket));
m_ssctx.setown(createSecureSocketContextEx2(sslconfig, ClientSocket));
#else
throw MakeStringException(-1, "HttpProxy: failure to create SSL connection to host '%s': OpenSSL not enabled in build", host);
#endif
Expand Down
5 changes: 1 addition & 4 deletions esp/tools/soapplus/http.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -505,10 +505,7 @@ HttpClient::HttpClient(IProperties* globals, const char* url, const char* inname
if (cfg && *cfg)
cfgtree.setown(createPTreeFromXMLFile(cfg));
}
if (cfgtree)
m_ssctx.setown(createSecureSocketContextEx2(cfgtree, ClientSocket));
else
m_ssctx.setown(createSecureSocketContext(ClientSocket));
m_ssctx.setown(createSecureSocketContextEx2(cfgtree, ClientSocket));
}
#else
throw MakeStringException(-1, "HttpClient: failure to create SSL socket - OpenSSL not enabled in build");
Expand Down
5 changes: 1 addition & 4 deletions esp/tools/soapplus/httpproxy.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -582,10 +582,7 @@ HttpProxy::HttpProxy(int localport, const char* host, int port, FILE* ofile, boo
if(use_ssl)
{
#ifdef _USE_OPENSSL
if(sslconfig != NULL)
m_ssctx.setown(createSecureSocketContextEx2(sslconfig, ClientSocket));
else
m_ssctx.setown(createSecureSocketContext(ClientSocket));
m_ssctx.setown(createSecureSocketContextEx2(sslconfig, ClientSocket));
#else
throw MakeStringException(-1, "HttpProxy: failure to create SSL socket - OpenSSL not enabled in build");
#endif
Expand Down
3 changes: 1 addition & 2 deletions fs/dafilesrv/dafilesrv.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -397,8 +397,7 @@ int main(int argc, const char* argv[])
// Use the "public" certificate issuer, unless it's visibility is "cluster" (meaning internal only)
const char *visibility = getComponentConfigSP()->queryProp("service/@visibility");
const char *certScope = strsame("cluster", visibility) ? "local" : "public";
Owned<IPropertyTree> info = getIssuerTlsServerConfig(certScope);
connectMethod = info ? SSLOnly : SSLNone;
connectMethod = hasIssuerTlsConfig(certScope) ? SSLOnly : SSLNone;
// NB: connectMethod will direct the CRemoteFileServer on accept to create a secure socket based on the same issuer certificates

dedicatedRowServicePort = 0; // row service always runs on same secure ssl port in containerized mode
Expand Down
30 changes: 15 additions & 15 deletions fs/dafsclient/rmtclient.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -112,6 +112,12 @@ static class _securitySettingsClient
}
}

const IPropertyTree * getSecureConfig()
{
//Later: return a synced tree...
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

When? Is that for a different PR? Is there a Jira open to revisit if so?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

HPCC-30753

return createSecureSocketConfig(queryCertificate(), queryPrivateKey(), queryPassPhrase());
}

protected:
DAFSConnectCfg connectMethod;
unsigned short daFileSrvPort;
Expand Down Expand Up @@ -156,10 +162,10 @@ static ISecureSocket *createSecureSocket(ISocket *sock, const char *issuer)
auto it = secureCtxClientIssuerMap.find(issuer);
if (it == secureCtxClientIssuerMap.end())
{
Owned<IPropertyTree> info = getIssuerTlsServerConfig(issuer);
if (!info)
Owned<const ISyncedPropertyTree> info = getIssuerTlsSyncedConfig(issuer);
if (!info || !info->isValid())
throw makeStringExceptionV(-1, "createSecureSocket() : missing MTLS configuration for issuer: %s", issuer);
secureContext.setown(createSecureSocketContextEx2(info, ClientSocket));
secureContext.setown(createSecureSocketContextSynced(info, ClientSocket));
secureCtxClientIssuerMap.emplace(issuer, secureContext.getLink());
}
else
Expand All @@ -168,7 +174,10 @@ static ISecureSocket *createSecureSocket(ISocket *sock, const char *issuer)
else
{
if (!secureContextClient)
secureContextClient.setown(createSecureSocketContextEx(securitySettings.queryCertificate(), securitySettings.queryPrivateKey(), securitySettings.queryPassPhrase(), ClientSocket));
{
Owned<const IPropertyTree> config = securitySettings.getSecureConfig();
secureContextClient.setown(createSecureSocketContextEx2(config, ClientSocket));
}
secureContext.set(secureContextClient);
}
}
Expand Down Expand Up @@ -751,17 +760,8 @@ void CRemoteBase::connectSocket(SocketEndpoint &ep, unsigned connectTimeoutMs, u
}
else
{
Owned<IPropertyTree> secretPTree = getSecret("storage", storageSecret);
if (!secretPTree)
throw makeStringExceptionV(-1, "secret %s.%s not found", "storage", storageSecret.str());

StringBuffer certSecretBuf;
getSecretKeyValue(certSecretBuf, secretPTree, "tls.crt");

StringBuffer privKeySecretBuf;
getSecretKeyValue(privKeySecretBuf, secretPTree, "tls.key");

Owned<ISecureSocketContext> secureContext = createSecureSocketContextEx(certSecretBuf, privKeySecretBuf, nullptr, ClientSocket);
Owned<ISyncedPropertyTree> config = createStorageTlsConfig(storageSecret, false);
Owned<ISecureSocketContext> secureContext = createSecureSocketContextSynced(config, ClientSocket);
ssock.setown(secureContext->createSecureSocket(socket.getClear(), loglevel));
}
}
Expand Down
26 changes: 11 additions & 15 deletions fs/dafsserver/dafsserver.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -112,6 +112,13 @@ static class _securitySettingsServer
{
queryDafsSecSettings(&connectMethod, &daFileSrvPort, &daFileSrvSSLPort, &certificate, &privateKey, &passPhrase);
}

const IPropertyTree * getSecureConfig()
{
//Later: return a synced tree...
return createSecureSocketConfig(certificate, privateKey, passPhrase);
}

} securitySettings;
#endif

Expand All @@ -133,23 +140,12 @@ static ISecureSocket *createSecureSocket(ISocket *sock, bool disableClientCertVe
*/

const char *certScope = strsame("cluster", getComponentConfigSP()->queryProp("service/@visibility")) ? "local" : "public";
Owned<IPropertyTree> info = getIssuerTlsServerConfig(certScope);
if (!info)
Owned<const ISyncedPropertyTree> info = getIssuerTlsSyncedConfig(certScope, nullptr, disableClientCertVerification);
if (!info || !info->isValid())
throw makeStringException(-1, "createSecureSocket() : missing MTLS configuration");
Owned<IPropertyTree> cloneInfo;
if (disableClientCertVerification)
{
// do not insist clients provide a cerificate for verification.
// This is used when the connection is TLS, but the authentication is done via other means
// e.g. in the case of the streaming service a opaque signed blob is transmitted and must
// be verified before proceeding.
cloneInfo.setown(createPTreeFromIPT(info));
cloneInfo->setPropBool("verify/@enable", false);
info = cloneInfo;
}
secureContextServer.setown(createSecureSocketContextEx2(info, ServerSocket));
secureContextServer.setown(createSecureSocketContextSynced(info, ServerSocket));
#else
secureContextServer.setown(createSecureSocketContextEx(securitySettings.certificate, securitySettings.privateKey, securitySettings.passPhrase, ServerSocket));
secureContextServer.setown(createSecureSocketContextEx2(securitySettings.getSecureConfig(), ServerSocket));
#endif
}
}
Expand Down
2 changes: 1 addition & 1 deletion roxie/ccd/ccd.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -410,7 +410,7 @@ extern int backgroundCopyClass;
extern int backgroundCopyPrio;

extern unsigned roxiePort; // If listening on multiple, this is the first. Used for lock cascading
extern IPropertyTree *roxiePortTlsClientConfig;
extern ISyncedPropertyTree *roxiePortTlsClientConfig;


extern unsigned udpMulticastBufferSize;
Expand Down
4 changes: 2 additions & 2 deletions roxie/ccd/ccdlistener.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -79,7 +79,7 @@ class CascadeManager : public CInterface
CriticalSection revisionCrit;
int myEndpoint;
const IRoxieContextLogger &logctx;
IPropertyTree *tlsConfig = nullptr;
ISyncedPropertyTree *tlsConfig = nullptr;

void unlockChildren()
{
Expand Down Expand Up @@ -135,7 +135,7 @@ class CascadeManager : public CInterface
assertex(sock);
if (tlsConfig)
{
Owned<ISecureSocketContext> secureCtx = createSecureSocketContextEx2(tlsConfig, ClientSocket);
Owned<ISecureSocketContext> secureCtx = createSecureSocketContextSynced(tlsConfig, ClientSocket);
if (!secureCtx)
throw makeStringException(ROXIE_TLS_ERROR, "Roxie CascadeManager failed creating secure context for roxie control message");
Owned<ISecureSocket> ssock = secureCtx->createSecureSocket(sock.getClear());
Expand Down
Loading