From 77930607230eccdcb7011f6c70465bab3c32cc38 Mon Sep 17 00:00:00 2001 From: Grant Limberg Date: Fri, 16 Feb 2018 14:30:27 -0800 Subject: [PATCH] Add HashiCorp Vault storage of ZeroTier's public & secret identity Adds a "vault" section to local.conf. Example local.conf: { "config": { "vault": { "vaultURL": "https://some.vault.host:8200", "vaultToken": "my-super-secret-vault-token", "vaultPath": "secure/place/to/put/identity" } } Additionally, the following environment variables can be set. Environment variables override local.conf: VAULT_ADDR VAULT_TOKEN VAULT_PATH Identities will be placed in the keys "public" and "secret" under the user specified path. If no path is specified, they will be placed in the token specific cubbyhole. If identity.public and identity.secret exist on disk and vault is configured, they will be automatically added to Vault and removed from disk. TODO: * Decide behavior for if Vault cannot be reached. * Add libcurl as a dependency in Linux & Mac builds * Add libcurl as a requirement for linux packages --- service/OneService.cpp | 262 +++++++++++++++++++++++++++++++++++------ 1 file changed, 224 insertions(+), 38 deletions(-) diff --git a/service/OneService.cpp b/service/OneService.cpp index 672e3799b..7013d9dc8 100644 --- a/service/OneService.cpp +++ b/service/OneService.cpp @@ -81,6 +81,12 @@ #include "../ext/http-parser/http_parser.h" #endif +#if ZT_VAULT_SUPPORT +extern "C" { +#include +} +#endif + #include "../ext/json/json.hpp" using json = nlohmann::json; @@ -158,6 +164,14 @@ namespace ZeroTier { typedef BSDEthernetTap EthernetTap; } // TCP activity timeout #define ZT_TCP_ACTIVITY_TIMEOUT 60000 +#if ZT_VAULT_SUPPORT +size_t curlResponseWrite(void *ptr, size_t size, size_t nmemb, std::string *data) +{ + data->append((char*)ptr, size * nmemb); + return size * nmemb; +} +#endif + namespace ZeroTier { namespace { @@ -478,10 +492,12 @@ public: #endif // HashiCorp Vault Settings +#if ZT_VAULT_SUPPORT bool _vaultEnabled; std::string _vaultURL; std::string _vaultToken; std::string _vaultPath; // defaults to cubbyhole/zerotier/identity.secret for per-access key storage +#endif // Set to false to force service to stop volatile bool _run; @@ -518,12 +534,16 @@ public: ,_vaultEnabled(false) ,_vaultURL() ,_vaultToken() - ,_vaultPath("cubbyhole/zerotier/identity.secret") + ,_vaultPath("cubbyhole/zerotier") ,_run(true) { _ports[0] = 0; _ports[1] = 0; _ports[2] = 0; + +#if ZT_VAULT_SUPPORT + curl_global_init(CURL_GLOBAL_DEFAULT); +#endif } virtual ~OneServiceImpl() @@ -560,20 +580,6 @@ public: _authToken = _trimString(_authToken); } - { - struct ZT_Node_Callbacks cb; - cb.version = 0; - cb.stateGetFunction = SnodeStateGetFunction; - cb.statePutFunction = SnodeStatePutFunction; - cb.wirePacketSendFunction = SnodeWirePacketSendFunction; - cb.virtualNetworkFrameFunction = SnodeVirtualNetworkFrameFunction; - cb.virtualNetworkConfigFunction = SnodeVirtualNetworkConfigFunction; - cb.eventCallback = SnodeEventCallback; - cb.pathCheckFunction = SnodePathCheckFunction; - cb.pathLookupFunction = SnodePathLookupFunction; - _node = new Node(this,(void *)0,&cb,OSUtils::now()); - } - // Read local configuration std::vector explicitBind; { @@ -663,14 +669,25 @@ public: for(std::map::iterator i(ppc.begin());i!=ppc.end();++i) _node->setPhysicalPathConfiguration(reinterpret_cast(&(i->first)),&(i->second)); } - - json &vaultConfig = _localConfig["vault"]; - } // Apply other runtime configuration from local.conf applyLocalConfig(); + { + struct ZT_Node_Callbacks cb; + cb.version = 0; + cb.stateGetFunction = SnodeStateGetFunction; + cb.statePutFunction = SnodeStatePutFunction; + cb.wirePacketSendFunction = SnodeWirePacketSendFunction; + cb.virtualNetworkFrameFunction = SnodeVirtualNetworkFrameFunction; + cb.virtualNetworkConfigFunction = SnodeVirtualNetworkConfigFunction; + cb.eventCallback = SnodeEventCallback; + cb.pathCheckFunction = SnodePathCheckFunction; + cb.pathLookupFunction = SnodePathLookupFunction; + _node = new Node(this, (void *)0, &cb, OSUtils::now()); + } + // Make sure we can use the primary port, and hunt for one if configured to do so const int portTrials = (_primaryPort == 0) ? 256 : 1; // if port is 0, pick random for(int k=0;k= 0) return retval; // else continue file based lookup } +#endif char p[4096]; switch(type) { @@ -2229,15 +2413,17 @@ public: if (f) { int n = (int)fread(data,1,maxlen,f); fclose(f); - - if (_vaultEnabled && type == ZT_STATE_OBJECT_IDENTITY_SECRET) { +#if ZT_VAULT_SUPPORT + if (_vaultEnabled && (type == ZT_STATE_OBJECT_IDENTITY_SECRET || type == ZT_STATE_OBJECT_IDENTITY_PUBLIC)) { // If we've gotten here while Vault is enabled, Vault does not know the key and it's been // read from disk instead. // // We should put the value in Vault and remove the local file. - nodeVaultPutIdentitySecret(data, n); - unlink(p); + if (nodeVaultPutIdentity(type, data, n)) { + unlink(p); + } } +#endif if (n >= 0) return n; }