Skip to content

Commit 4ca62e0

Browse files
authored
MINIFICPP-2846 minifi-encrypt-config should encrypt sensitive propert… (#2204)
The minifi-encrypt-config utility should encrypt the additional properties files in the minifi.properties.d directory, too, if they exist. We allow nifi.sensitive.props.additional.keys (the list of additional sensitive property keys) to be in any of the properties files.
1 parent cfeeadc commit 4ca62e0

19 files changed

Lines changed: 606 additions & 199 deletions

encrypt-config/ConfigFile.cpp

Lines changed: 0 additions & 39 deletions
This file was deleted.

encrypt-config/ConfigFileEncryptor.h

Lines changed: 0 additions & 29 deletions
This file was deleted.

encrypt-config/EncryptConfig.cpp

Lines changed: 47 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -24,16 +24,18 @@
2424
#include <stdexcept>
2525

2626
#include "../core-framework/include/Defaults.h"
27-
#include "ConfigFile.h"
28-
#include "ConfigFileEncryptor.h"
2927
#include "FlowConfigEncryptor.h"
30-
#include "utils/Enum.h"
28+
#include "PropertiesFileEncryptor.h"
29+
#include "properties/Properties.h"
30+
#include "properties/PropertiesFile.h"
3131
#include "utils/file/FileUtils.h"
3232

3333
namespace {
3434
constexpr std::string_view ENCRYPTION_KEY_PROPERTY_NAME = "nifi.bootstrap.sensitive.key";
3535
constexpr std::string_view SENSITIVE_PROPERTIES_KEY_PROPERTY_NAME = "nifi.bootstrap.sensitive.properties.key";
3636

37+
namespace minifi = org::apache::nifi::minifi;
38+
3739
std::string readFile(const std::filesystem::path& file_path) {
3840
try {
3941
std::ifstream file_stream{file_path, std::ios::binary};
@@ -43,11 +45,27 @@ std::string readFile(const std::filesystem::path& file_path) {
4345
throw std::runtime_error("Error while reading file \"" + file_path.string() + "\"");
4446
}
4547
}
48+
49+
uint32_t encryptSensitiveValuesInMinifiPropertiesFile(const std::filesystem::path& file_path, const std::vector<std::string>& sensitive_properties,
50+
const minifi::encrypt_config::EncryptionKeys& keys) {
51+
minifi::PropertiesFile properties_file{std::ifstream{file_path}};
52+
if (properties_file.size() == 0) {
53+
std::cout << "Properties file " + file_path.string() + " is missing or empty!\n";
54+
return 0;
55+
}
56+
57+
uint32_t num_properties_encrypted = minifi::encrypt_config::encryptSensitivePropertiesInFile(properties_file, sensitive_properties, keys);
58+
if (num_properties_encrypted > 0) {
59+
properties_file.writeTo(file_path);
60+
std::cout << "Encrypted " << num_properties_encrypted << " sensitive " << (num_properties_encrypted == 1 ? "property" : "properties") << " in " << file_path.string() << '\n';
61+
}
62+
return num_properties_encrypted;
63+
}
4664
} // namespace
4765

4866
namespace org::apache::nifi::minifi::encrypt_config {
4967

50-
EncryptConfig::EncryptConfig(const std::string& minifi_home) : minifi_home_(minifi_home) {
68+
EncryptConfig::EncryptConfig(std::filesystem::path minifi_home) : minifi_home_(std::move(minifi_home)), prev_current_path_(std::filesystem::current_path()) {
5169
if (sodium_init() < 0) {
5270
// encryption/decryption depends on the libsodium library which needs to be initialized
5371
throw std::runtime_error{"Could not initialize the libsodium library!"};
@@ -56,8 +74,12 @@ EncryptConfig::EncryptConfig(const std::string& minifi_home) : minifi_home_(mini
5674
std::filesystem::current_path(minifi_home_);
5775
}
5876

77+
EncryptConfig::~EncryptConfig() {
78+
std::filesystem::current_path(prev_current_path_);
79+
}
80+
5981
bool EncryptConfig::isReEncrypting() const {
60-
encrypt_config::ConfigFile bootstrap_file{std::ifstream{bootstrapFilePath()}};
82+
PropertiesFile bootstrap_file{std::ifstream{bootstrapFilePath()}};
6183

6284
std::string decryption_key_name = utils::string::join_pack(ENCRYPTION_KEY_PROPERTY_NAME, ".old");
6385
std::optional<std::string> decryption_key_hex = bootstrap_file.getValue(decryption_key_name);
@@ -66,7 +88,7 @@ bool EncryptConfig::isReEncrypting() const {
6688
}
6789

6890
std::filesystem::path EncryptConfig::flowConfigPath() const {
69-
encrypt_config::ConfigFile properties_file{std::ifstream{propertiesFilePath()}};
91+
PropertiesFile properties_file{std::ifstream{propertiesFilePath()}};
7092
std::optional<std::filesystem::path> config_path{properties_file.getValue(Configure::nifi_flow_configuration_file)};
7193
if (!config_path) {
7294
config_path = utils::file::PathUtils::resolve(minifi_home_, "conf/config.yml");
@@ -123,7 +145,7 @@ std::filesystem::path EncryptConfig::propertiesFilePath() const {
123145
}
124146

125147
EncryptionKeys EncryptConfig::getEncryptionKeys(std::string_view property_name) const {
126-
encrypt_config::ConfigFile bootstrap_file{std::ifstream{bootstrapFilePath()}};
148+
PropertiesFile bootstrap_file{std::ifstream{bootstrapFilePath()}};
127149

128150
std::string decryption_key_name = utils::string::join_pack(property_name, ".old");
129151
std::optional<std::string> decryption_key_hex = bootstrap_file.getValue(decryption_key_name);
@@ -168,7 +190,7 @@ std::string EncryptConfig::hexDecodeAndValidateKey(const std::string& key, const
168190

169191
void EncryptConfig::writeEncryptionKeyToBootstrapFile(const std::string& encryption_key_name, const utils::crypto::Bytes& encryption_key) const {
170192
std::string key_encoded = utils::string::to_hex(utils::crypto::bytesToString(encryption_key));
171-
encrypt_config::ConfigFile bootstrap_file{std::ifstream{bootstrapFilePath()}};
193+
PropertiesFile bootstrap_file{std::ifstream{bootstrapFilePath()}};
172194

173195
if (bootstrap_file.hasValue(encryption_key_name)) {
174196
bootstrap_file.update(encryption_key_name, key_encoded);
@@ -180,22 +202,28 @@ void EncryptConfig::writeEncryptionKeyToBootstrapFile(const std::string& encrypt
180202
}
181203

182204
void EncryptConfig::encryptSensitiveValuesInMinifiProperties() const {
183-
EncryptionKeys keys = getEncryptionKeys(ENCRYPTION_KEY_PROPERTY_NAME);
205+
const auto base_properties_file = propertiesFilePath();
206+
if (!utils::file::exists(base_properties_file)) {
207+
std::cout << "The minifi properties file " << base_properties_file.string() << " does not exist. Did you specify the minifi home directory correctly?\n";
208+
return;
209+
}
184210

185-
encrypt_config::ConfigFile properties_file{std::ifstream{propertiesFilePath()}};
186-
if (properties_file.size() == 0) {
187-
throw std::runtime_error{"Properties file " + propertiesFilePath().string() + " not found!"};
211+
const std::vector<std::string> sensitive_properties = getSensitiveProperties(base_properties_file);
212+
const EncryptionKeys keys = getEncryptionKeys(ENCRYPTION_KEY_PROPERTY_NAME);
213+
214+
uint32_t num_properties_encrypted = encryptSensitiveValuesInMinifiPropertiesFile(base_properties_file, sensitive_properties, keys);
215+
216+
const auto extra_properties_files_dir = properties::extraPropertiesFilesDirName(base_properties_file);
217+
const auto logger = core::logging::LoggerFactory<EncryptConfig>::getLogger();
218+
const auto extra_properties_file_names = properties::getExtraPropertiesFileNames(extra_properties_files_dir, logger);
219+
220+
for (const auto& file_name : extra_properties_file_names) {
221+
num_properties_encrypted += encryptSensitiveValuesInMinifiPropertiesFile(extra_properties_files_dir / file_name, sensitive_properties, keys);
188222
}
189223

190-
uint32_t num_properties_encrypted = encryptSensitivePropertiesInFile(properties_file, keys);
191224
if (num_properties_encrypted == 0) {
192-
std::cout << "Could not find any (new) sensitive properties to encrypt in " << propertiesFilePath() << '\n';
193-
return;
225+
std::cout << "Could not find any (new) sensitive properties to encrypt.\n";
194226
}
195-
196-
properties_file.writeTo(propertiesFilePath());
197-
std::cout << "Encrypted " << num_properties_encrypted << " sensitive "
198-
<< (num_properties_encrypted == 1 ? "property" : "properties") << " in " << propertiesFilePath() << '\n';
199227
}
200228

201229
void EncryptConfig::encryptSensitiveValuesInFlowConfig(

encrypt-config/EncryptConfig.h

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -25,7 +25,8 @@ namespace org::apache::nifi::minifi::encrypt_config {
2525

2626
class EncryptConfig {
2727
public:
28-
explicit EncryptConfig(const std::string& minifi_home);
28+
explicit EncryptConfig(std::filesystem::path minifi_home);
29+
~EncryptConfig();
2930

3031
void encryptSensitiveValuesInMinifiProperties() const;
3132
void encryptSensitiveValuesInFlowConfig(
@@ -44,6 +45,7 @@ class EncryptConfig {
4445
void writeEncryptionKeyToBootstrapFile(const std::string& encryption_key_name, const utils::crypto::Bytes& encryption_key) const;
4546

4647
const std::filesystem::path minifi_home_;
48+
const std::filesystem::path prev_current_path_;
4749
};
4850

4951
} // namespace org::apache::nifi::minifi::encrypt_config

encrypt-config/EncryptConfigMain.cpp

Lines changed: 11 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,7 @@
2121
#include "EncryptConfig.h"
2222
#include "argparse/argparse.hpp"
2323
#include "minifi-cpp/agent/agent_version.h"
24+
#include "utils/file/FileUtils.h"
2425
#include "utils/StringUtils.h"
2526

2627
namespace minifi = org::apache::nifi::minifi;
@@ -68,7 +69,16 @@ int main(int argc, char* argv[]) try {
6869
return 1;
6970
}
7071

71-
EncryptConfig encrypt_config{argument_parser.get("-m")};
72+
std::filesystem::path minifi_home{argument_parser.get("-m")};
73+
if (!minifi::utils::file::exists(minifi_home)) {
74+
std::cerr << "The minifi home directory " << minifi_home.string() << " does not exist!\n";
75+
return 7;
76+
}
77+
if (!minifi::utils::file::is_directory(minifi_home)) {
78+
std::cerr << "The minifi home is set to " << minifi_home.string() << ", which is not a directory!\n";
79+
return 8;
80+
}
81+
EncryptConfig encrypt_config{std::move(minifi_home)};
7282

7383
std::string operation = argument_parser.get("operation");
7484
const auto re_encrypt = argument_parser.get<bool>("--re-encrypt");

encrypt-config/ConfigFileEncryptor.cpp renamed to encrypt-config/PropertiesFileEncryptor.cpp

Lines changed: 30 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -15,33 +15,50 @@
1515
* limitations under the License.
1616
*/
1717

18-
#include "ConfigFileEncryptor.h"
18+
#include "PropertiesFileEncryptor.h"
1919

2020
#include <iostream>
2121
#include <optional>
2222
#include <string>
2323

24+
#include "properties/Configuration.h"
25+
#include "properties/Properties.h"
2426
#include "utils/StringUtils.h"
2527

26-
namespace org::apache::nifi::minifi::encrypt_config {
27-
28+
namespace {
2829
bool isEncrypted(const std::optional<std::string>& encryption_type) {
2930
return encryption_type && !encryption_type->empty() && *encryption_type != "plaintext";
3031
}
32+
} // namespace
33+
34+
namespace org::apache::nifi::minifi::encrypt_config {
35+
36+
std::vector<std::string> getSensitiveProperties(const std::filesystem::path& properties_file_path) {
37+
auto minifi_properties = PropertiesImpl{PropertiesImpl::PersistTo::MultipleFiles, "MiNiFi properties"};
38+
minifi_properties.loadConfigureFile(properties_file_path);
39+
40+
auto sensitive_properties = Configuration::getSensitiveProperties([&minifi_properties](const std::string& property_name) {
41+
return minifi_properties.getString(property_name);
42+
});
43+
auto not_found = [&minifi_properties](const std::string& property_name) { return !minifi_properties.getString(property_name).has_value(); };
44+
std::erase_if(sensitive_properties, not_found);
45+
46+
return sensitive_properties;
47+
}
3148

32-
uint32_t encryptSensitivePropertiesInFile(ConfigFile& config_file, const utils::crypto::Bytes & encryption_key) {
33-
return encryptSensitivePropertiesInFile(config_file, EncryptionKeys{{}, encryption_key});
49+
uint32_t encryptSensitivePropertiesInFile(PropertiesFile& properties_file, const std::vector<std::string>& sensitive_properties, const utils::crypto::Bytes & encryption_key) {
50+
return encryptSensitivePropertiesInFile(properties_file, sensitive_properties, EncryptionKeys{{}, encryption_key});
3451
}
3552

36-
uint32_t encryptSensitivePropertiesInFile(ConfigFile& config_file, const EncryptionKeys& keys) {
37-
int num_properties_encrypted = 0;
53+
uint32_t encryptSensitivePropertiesInFile(PropertiesFile& properties_file, const std::vector<std::string>& sensitive_properties, const EncryptionKeys& keys) {
54+
uint32_t num_properties_encrypted = 0;
3855

39-
for (const auto& property_key : config_file.getSensitiveProperties()) {
40-
std::optional<std::string> property_value = config_file.getValue(property_key);
56+
for (const auto& property_key : sensitive_properties) {
57+
std::optional<std::string> property_value = properties_file.getValue(property_key);
4158
if (!property_value) { continue; }
4259

4360
std::string encryption_type_key = property_key + ".protected";
44-
std::optional<std::string> encryption_type = config_file.getValue(encryption_type_key);
61+
std::optional<std::string> encryption_type = properties_file.getValue(encryption_type_key);
4562

4663
std::string raw_value = *property_value;
4764
if (isEncrypted(encryption_type)) {
@@ -63,12 +80,12 @@ uint32_t encryptSensitivePropertiesInFile(ConfigFile& config_file, const Encrypt
6380

6481
std::string encrypted_property_value = utils::crypto::encrypt(raw_value, keys.encryption_key);
6582

66-
config_file.update(property_key, encrypted_property_value);
83+
properties_file.update(property_key, encrypted_property_value);
6784

6885
if (encryption_type) {
69-
config_file.update(encryption_type_key, utils::crypto::EncryptionType::name());
86+
properties_file.update(encryption_type_key, utils::crypto::EncryptionType::name());
7087
} else {
71-
config_file.insertAfter(property_key, encryption_type_key, utils::crypto::EncryptionType::name());
88+
properties_file.insertAfter(property_key, encryption_type_key, utils::crypto::EncryptionType::name());
7289
}
7390

7491
std::cout << "Encrypted property: " << property_key << '\n';
Lines changed: 5 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -16,22 +16,16 @@
1616
*/
1717
#pragma once
1818

19-
#include <string>
20-
#include <vector>
21-
22-
#include "utils/crypto/EncryptionUtils.h"
2319
#include "properties/PropertiesFile.h"
20+
#include "utils/crypto/EncryptionUtils.h"
21+
#include "Utils.h"
2422

2523
namespace org::apache::nifi::minifi::encrypt_config {
2624

27-
class ConfigFile : public PropertiesFile {
28-
public:
29-
using PropertiesFile::PropertiesFile;
25+
std::vector<std::string> getSensitiveProperties(const std::filesystem::path& properties_file_path);
3026

31-
[[nodiscard]] std::vector<std::string> getSensitiveProperties() const;
27+
uint32_t encryptSensitivePropertiesInFile(PropertiesFile& properties_file, const std::vector<std::string>& sensitive_properties, const utils::crypto::Bytes& encryption_key);
3228

33-
private:
34-
friend bool operator==(const ConfigFile&, const ConfigFile&);
35-
};
29+
uint32_t encryptSensitivePropertiesInFile(PropertiesFile& properties_file, const std::vector<std::string>& sensitive_properties, const EncryptionKeys& keys);
3630

3731
} // namespace org::apache::nifi::minifi::encrypt_config

0 commit comments

Comments
 (0)