From f350b6d9f9bb106d8f6c7dc8d27dda0f11cc6afa Mon Sep 17 00:00:00 2001 From: Jake Smith Date: Wed, 15 Jan 2025 19:09:17 +0000 Subject: [PATCH] HPCCC-33260 Allow a BM DFS service+dafilesrv to be secured 1) Ensure BM DFS meta is remapped to point to the BM dafilesrv and correct secure port. 2) Allow dafilesrv to be configured with a CA/certs/trusted peers, so that it can be configured to only accepts connections from trusted clients. Signed-off-by: Jake Smith --- dali/base/dautils.cpp | 9 ++++- dali/base/dautils.hpp | 4 ++- esp/services/ws_dfsservice/ws_dfsservice.cpp | 29 +++++++++++++-- esp/services/ws_dfsservice/ws_dfsservice.hpp | 1 + fs/dafilesrv/dafilesrv.cpp | 9 +++++ fs/dafsserver/dafsserver.cpp | 38 ++++++++++++-------- 6 files changed, 72 insertions(+), 18 deletions(-) diff --git a/dali/base/dautils.cpp b/dali/base/dautils.cpp index d25e0a7ef9a..e2e18d90e79 100644 --- a/dali/base/dautils.cpp +++ b/dali/base/dautils.cpp @@ -3675,6 +3675,13 @@ static CConfigUpdateHook directIOUpdateHook; static CriticalSection dafileSrvNodeCS; static Owned tlsDirectIONode, nonTlsDirectIONode; +#ifndef _CONTAINERIZED +unsigned getBareMetalDaFsServerPort() +{ + return getPreferredDafsClientPort(true); +} +#endif + void remapGroupsToDafilesrv(IPropertyTree *file, bool foreign, bool secure) { Owned iter = file->getElements("Cluster"); @@ -3683,7 +3690,7 @@ void remapGroupsToDafilesrv(IPropertyTree *file, bool foreign, bool secure) IPropertyTree &cluster = iter->query(); const char *planeName = cluster.queryProp("@name"); Owned plane = getDataStoragePlane(planeName, true); - if ((0 == plane->queryHosts().size()) && isAbsolutePath(plane->queryPrefix())) // if hosts group, or url, don't touch + if (isAbsolutePath(plane->queryPrefix())) // if url (i.e. not absolute prefix path) don't touch { if (isContainerized()) { diff --git a/dali/base/dautils.hpp b/dali/base/dautils.hpp index 7cb0edeaceb..e7ea13d31cb 100644 --- a/dali/base/dautils.hpp +++ b/dali/base/dautils.hpp @@ -583,7 +583,9 @@ inline unsigned calcStripeNumber(unsigned partNum, const char *lfnName, unsigned } interface INamedGroupStore; extern da_decl void remapGroupsToDafilesrv(IPropertyTree *file, bool foreign, bool secure); - +#ifndef _CONTAINERIZED +unsigned getBareMetalDaFsServerPort(); +#endif #ifdef NULL_DALIUSER_STACKTRACE extern da_decl void logNullUser(IUserDescriptor *userDesc); #else diff --git a/esp/services/ws_dfsservice/ws_dfsservice.cpp b/esp/services/ws_dfsservice/ws_dfsservice.cpp index d79e3afdd7a..be01e544755 100644 --- a/esp/services/ws_dfsservice/ws_dfsservice.cpp +++ b/esp/services/ws_dfsservice/ws_dfsservice.cpp @@ -126,6 +126,24 @@ static void populateLFNMeta(IUserDescriptor *userDesc, const char *logicalName, { VStringBuffer storagePlaneXPath("storage/%s", planeXPath.str()); Owned dataPlane = getGlobalConfigSP()->getPropTree(storagePlaneXPath); + + const char *hostGroupName = dataPlane->queryProp("@hostGroup"); + if (!isEmptyString(hostGroupName)) + { + Owned hostGroup = getHostGroup(hostGroupName, false); + if (hostGroup) + { + dataPlane.setown(createPTreeFromIPT(dataPlane)); + unsigned daFsSrvPort = getBareMetalDaFsServerPort(); + Owned iter = hostGroup->getElements("hosts"); + ForEach(*iter) + { + VStringBuffer endpoint("%s:%u", iter->query().queryProp(nullptr), daFsSrvPort); + dataPlane->addProp("hosts", endpoint); + } + dataPlane->removeProp("@hostGroup"); + } + } metaRoot->addPropTree("planes", dataPlane.getClear()); } } @@ -135,6 +153,8 @@ static void populateLFNMeta(IUserDescriptor *userDesc, const char *logicalName, void CWsDfsEx::init(IPropertyTree *cfg, const char *process, const char *service) { DBGLOG("Initializing %s service [process = %s]", service, process); + VStringBuffer xpath("Software/EspProcess/EspBinding[@service=\"%s\"]/@protocol", service); + isHttps = strsame("https", cfg->queryProp(xpath)); } bool CWsDfsEx::onGetLease(IEspContext &context, IEspLeaseRequest &req, IEspLeaseResponse &resp) @@ -177,8 +197,13 @@ bool CWsDfsEx::onDFSFileLookup(IEspContext &context, IEspDFSFileLookupRequest &r if (req.getAccessViaDafilesrv()) opts |= LfnMOptRemap; - // NB: if we ever have some services with tls, and some without in bare-metal, this may need revisiting. - if (getComponentConfigSP()->getPropBool("@tls")) + if (isContainerized()) + { + // NB: if we ever have some services with tls, and some without in bare-metal, this may need revisiting. + if (getComponentConfigSP()->getPropBool("@tls")) + opts |= LfnMOptTls; + } + else if (isHttps) opts |= LfnMOptTls; Owned responseTree = createPTree(); diff --git a/esp/services/ws_dfsservice/ws_dfsservice.hpp b/esp/services/ws_dfsservice/ws_dfsservice.hpp index a56ac006ec9..a1b8f3d2894 100644 --- a/esp/services/ws_dfsservice/ws_dfsservice.hpp +++ b/esp/services/ws_dfsservice/ws_dfsservice.hpp @@ -26,6 +26,7 @@ class CWsDfsEx : public CWsDfs { + bool isHttps = false; public: virtual ~CWsDfsEx() {} virtual void init(IPropertyTree *cfg, const char *process, const char *service); diff --git a/fs/dafilesrv/dafilesrv.cpp b/fs/dafilesrv/dafilesrv.cpp index 6a5b4d449c1..0fa14b26e73 100644 --- a/fs/dafilesrv/dafilesrv.cpp +++ b/fs/dafilesrv/dafilesrv.cpp @@ -590,6 +590,15 @@ int main(int argc, const char* argv[]) if (componentExpert) synchronizePTree(expert, componentExpert, false, true); + // merge in bare-metal dafilesrv component cert settings into newConfig + IPropertyTree *componentCert = nullptr; + componentCert = daFileSrv->queryPropTree("cert"); + if (componentCert) + { + IPropertyTree *cert = ensurePTree(newConfig, "cert"); + synchronizePTree(cert, componentCert, false, true); + } + // any overrides by Instance definitions? Owned iter = daFileSrv->getElements("Instance"); ForEach(*iter) diff --git a/fs/dafsserver/dafsserver.cpp b/fs/dafsserver/dafsserver.cpp index f3ffc8fd5df..5319a3250d4 100644 --- a/fs/dafsserver/dafsserver.cpp +++ b/fs/dafsserver/dafsserver.cpp @@ -132,21 +132,31 @@ static ISecureSocket *createSecureSocket(ISocket *sock, bool disableClientCertVe CriticalBlock b(secureContextCrit); if (!secureContextServer) { -#ifdef _CONTAINERIZED - /* Connections are expected from 3rd parties via TLS, - * we do not expect them to provide a valid certificate for verification. - * Currently the server (this dafilesrv), will use either the "public" certificate issuer, - * unless it's visibility is "cluster" (meaning internal only) - */ + if (isContainerized()) + { + /* Connections are expected from 3rd parties via TLS, + * we do not expect them to provide a valid certificate for verification. + * Currently the server (this dafilesrv), will use either the "public" certificate issuer, + * unless it's visibility is "cluster" (meaning internal only) + */ - const char *certScope = strsame("cluster", getComponentConfigSP()->queryProp("service/@visibility")) ? "local" : "public"; - Owned info = getIssuerTlsSyncedConfig(certScope, nullptr, disableClientCertVerification); - if (!info || !info->isValid()) - throw makeStringException(-1, "createSecureSocket() : missing MTLS configuration"); - secureContextServer.setown(createSecureSocketContextSynced(info, ServerSocket)); -#else - secureContextServer.setown(createSecureSocketContextEx2(securitySettings.getSecureConfig(), ServerSocket)); -#endif + const char *certScope = strsame("cluster", getComponentConfigSP()->queryProp("service/@visibility")) ? "local" : "public"; + Owned info = getIssuerTlsSyncedConfig(certScope, nullptr, disableClientCertVerification); + if (!info || !info->isValid()) + throw makeStringException(-1, "createSecureSocket() : missing MTLS configuration"); + secureContextServer.setown(createSecureSocketContextSynced(info, ServerSocket)); + } + else + { + IPropertyTree *cert = getComponentConfigSP()->getPropTree("cert"); + if (cert) + { + Owned certSyncedWrapper = createSyncedPropertyTree(cert); + secureContextServer.setown(createSecureSocketContextSynced(certSyncedWrapper, ServerSocket)); + } + else + secureContextServer.setown(createSecureSocketContextEx2(securitySettings.getSecureConfig(), ServerSocket)); + } } } int loglevel = SSLogNormal;