diff --git a/lockbox/.dockerignore b/lockbox/.dockerignore new file mode 100644 index 00000000..1aa2155b --- /dev/null +++ b/lockbox/.dockerignore @@ -0,0 +1 @@ +Settings.toml \ No newline at end of file diff --git a/lockbox/.env b/lockbox/.env new file mode 100644 index 00000000..c0e78d64 --- /dev/null +++ b/lockbox/.env @@ -0,0 +1,24 @@ +# general settings +# KEY_MANAGER can be one of: google_kms, hashicorp or filesystem +LOCKBOX_DATABASE_URL=postgresql://postgres:postgres@localhost/enclave +LOCKBOX_PORT=18080 +KEY_MANAGER=google_kms + +# filesystem settings +SEED_FILEPATH=./seed + +# google_kms settings +GCLOUD_PROJECT_ID=mercury-441416 +GCLOUD_PROJECT_NUMBER=100600525477 +GCLOUD_LOCATION_ID=global +GCLOUD_SECRET_MANAGER_KEY_NAME=encrypted-key +GCLOUD_KMS_RING=enclave +GCLOUD_CRYPTO_KEY=sealing + +# hashicorp settings +# HASHICORP_HCP_CLIENT_ID= +# HASHICORP_HCP_CLIENT_SECRET= +# HASHICORP_ORGANIZATION_ID= +# HASHICORP_PROJECT_ID= +# HASHICORP_APP_NAME= +# HASHICORP_SECRET_NAME= diff --git a/lockbox/CMakeLists.txt b/lockbox/CMakeLists.txt index cdca62d2..57d2c6b5 100644 --- a/lockbox/CMakeLists.txt +++ b/lockbox/CMakeLists.txt @@ -96,7 +96,7 @@ target_link_libraries(MercuryLockbox PRIVATE OpenSSL::Crypto) # Copy Settings.toml after building MercuryLockbox -add_custom_command(TARGET MercuryLockbox POST_BUILD -COMMAND ${CMAKE_COMMAND} -E copy_if_different -${CMAKE_SOURCE_DIR}/Settings.toml -$/Settings.toml) \ No newline at end of file +# add_custom_command(TARGET MercuryLockbox POST_BUILD +# COMMAND ${CMAKE_COMMAND} -E copy_if_different +# ${CMAKE_SOURCE_DIR}/Settings.toml +# $/Settings.toml) diff --git a/lockbox/Dockerfile b/lockbox/Dockerfile new file mode 100644 index 00000000..26d1ceb8 --- /dev/null +++ b/lockbox/Dockerfile @@ -0,0 +1,46 @@ +# Start with Ubuntu as base image +FROM ubuntu:22.04 + +# Prevent interactive prompts during package installation +ENV DEBIAN_FRONTEND=noninteractive + +# Install essential packages +RUN apt-get update && apt-get install -y \ + build-essential \ + cmake \ + curl \ + git \ + ninja-build \ + pkg-config \ + tar \ + unzip \ + zip \ + libpq-dev \ + autoconf \ + automake \ + libtool \ + && rm -rf /var/lib/apt/lists/* + +# Set up working directory +WORKDIR /app + +# Install vcpkg +RUN git clone https://github.com/Microsoft/vcpkg.git /opt/vcpkg && \ + /opt/vcpkg/bootstrap-vcpkg.sh -disableMetrics + +# Add vcpkg to PATH +ENV PATH="/opt/vcpkg:${PATH}" + +# Set vcpkg root +ENV VCPKG_ROOT=/opt/vcpkg + +# Copy your project files +COPY . . + +# Create build directory and run cmake +RUN mkdir -p build && cd build +RUN cd build && cmake --preset=vcpkg .. +RUN cd build && cmake --build . + +# Set the default command +CMD ["./build/MercuryLockbox"] \ No newline at end of file diff --git a/lockbox/README.md b/lockbox/README.md index c37d7f2a..6c4328fd 100644 --- a/lockbox/README.md +++ b/lockbox/README.md @@ -1,6 +1,6 @@ ## Lockbox server -To run: +### 1. Running from source: 1. Install vcpkg package manager, following the instruction [here](https://learn.microsoft.com/en-us/vcpkg/get_started/get-started?pivots=shell-bash). 2. Install `ninja` build system (`sudo apt-get -y install ninja-build`). @@ -13,4 +13,19 @@ $ cmake --build . ``` 4. Set the desired key manager in `Settings.toml`. Currently, there are 3 available: `google_kms`, `hashicorp`, `filesystem`. -5. Then, to run the server: `./MercuryLockbox`. \ No newline at end of file +5. Then, to run the server: `./MercuryLockbox`. + +### 2. Running from Dockerfile: + +1. Edit the `.env` file according to your personal settings. + +2. Run `$ docker build -t mercury-lockbox .` +3. 1. For `filesystem` or `hashicorp` key manager, you can run `$ docker run --env-file .env mercury-lockbox`. + 2. For `google_kms` key manager, you need to pass your service account key file at runtime: + ```bash + docker run --env-file .env \ + -v /path/to/service-account-key.json:/app/credentials.json \ + -e GOOGLE_APPLICATION_CREDENTIALS=/app/credentials.json \ + mercury-lockbox + ``` + diff --git a/lockbox/include/utils.h b/lockbox/include/utils.h index 0d2a1c33..7b10f6b6 100644 --- a/lockbox/include/utils.h +++ b/lockbox/include/utils.h @@ -10,6 +10,34 @@ namespace utils { + // config vars + struct config_var + { + std::string env_var; + std::string toml_var_1; + std::string toml_var_2; + }; + + static const config_var DATABASE_URL = {"LOCKBOX_DATABASE_URL", "general", "database_connection_string"}; + static const config_var KEY_MANAGER = {"KEY_MANAGER", "general", "key_manager"}; + static const config_var SERVER_PORT = {"LOCKBOX_PORT", "general", "server_port"}; + + static const config_var SEED_FILEPATH = {"SEED_FILEPATH", "filesystem", "seed_filepath"}; + + static const config_var GCLOUD_PROJECT_ID = {"GCLOUD_PROJECT_ID", "gcloud", "project_id"}; + static const config_var GCLOUD_PROJECT_NUMBER = {"GCLOUD_PROJECT_NUMBER", "gcloud", "project_number"}; + static const config_var GCLOUD_SECRET_MANAGER_KEY_NAME = {"GCLOUD_SECRET_MANAGER_KEY_NAME", "secretmanager", "key_name"}; + static const config_var GCLOUD_LOCATION_ID = {"GCLOUD_LOCATION_ID", "gcloud", "location_id"}; + static const config_var GCLOUD_KMS_RING = {"GCLOUD_KMS_RING", "kms", "ring"}; + static const config_var GCLOUD_CRYPTO_KEY = {"GCLOUD_CRYPTO_KEY", "kms", "crypto_key"}; + + static const config_var HASHICORP_HCP_CLIENT_ID = {"HASHICORP_HCP_CLIENT_ID", "hashicorp", "hcp_client_id"}; + static const config_var HASHICORP_HCP_CLIENT_SECRET = {"HASHICORP_HCP_CLIENT_SECRET", "hashicorp", "hcp_client_secret"}; + static const config_var HASHICORP_ORGANIZATION_ID = {"HASHICORP_ORGANIZATION_ID", "hashicorp", "organization_id"}; + static const config_var HASHICORP_PROJECT_ID = {"HASHICORP_PROJECT_ID", "hashicorp", "project_id"}; + static const config_var HASHICORP_APP_NAME = {"HASHICORP_APP_NAME", "hashicorp", "app_name"}; + static const config_var HASHICORP_SECRET_NAME = {"HASHICORP_SECRET_NAME", "hashicorp", "secret_name"}; + struct chacha20_poly1305_encrypted_data { size_t data_len; unsigned char* data; @@ -27,6 +55,8 @@ namespace utils { uint16_t getServerPort(); + std::string getStringConfigVar(const std::string& env_var, const std::string& toml_var_1, const std::string& toml_var_2); + } // namespace utils #endif // UTILS_H \ No newline at end of file diff --git a/lockbox/src/db_manager.cpp b/lockbox/src/db_manager.cpp index 8275272f..e8aeb0b5 100644 --- a/lockbox/src/db_manager.cpp +++ b/lockbox/src/db_manager.cpp @@ -10,14 +10,8 @@ namespace db_manager { std::string getDatabaseConnectionString() { - const char* value = std::getenv("ENCLAVE_DATABASE_URL"); - - if (value == nullptr) { - auto config = toml::parse_file("Settings.toml"); - return config["general"]["database_connection_string"].as_string()->get(); - } else { - return std::string(value); - } + return utils::getStringConfigVar( + utils::DATABASE_URL.env_var, utils::DATABASE_URL.toml_var_1, utils::DATABASE_URL.toml_var_2); } // Assumes the buffer is large enough. In a real application, ensure buffer safety. diff --git a/lockbox/src/filesystem_key_manager.cpp b/lockbox/src/filesystem_key_manager.cpp index 33db57c5..54ea0b85 100644 --- a/lockbox/src/filesystem_key_manager.cpp +++ b/lockbox/src/filesystem_key_manager.cpp @@ -11,14 +11,8 @@ namespace filesystem_key_manager { std::string getSeedFilePath() { - const char* value = std::getenv("SEED_FILEPATH"); - - if (value == nullptr) { - auto config = toml::parse_file("Settings.toml"); - return config["filesystem"]["seed_filepath"].as_string()->get(); - } else { - return std::string(value); - } + return utils::getStringConfigVar( + utils::SEED_FILEPATH.env_var, utils::SEED_FILEPATH.toml_var_1, utils::SEED_FILEPATH.toml_var_2); } std::vector get_seed() { diff --git a/lockbox/src/google_key_manager.cpp b/lockbox/src/google_key_manager.cpp index 4d05e1ae..be9357db 100644 --- a/lockbox/src/google_key_manager.cpp +++ b/lockbox/src/google_key_manager.cpp @@ -5,17 +5,20 @@ #include "google/cloud/location.h" #include #include "utils.h" -#include namespace key_manager { std::string get_encrypted_secret() { - auto config = toml::parse_file("Settings.toml"); + auto project_id = utils::getStringConfigVar( + utils::GCLOUD_PROJECT_ID.env_var, utils::GCLOUD_PROJECT_ID.toml_var_1, utils::GCLOUD_PROJECT_ID.toml_var_2); + + auto project_number = utils::getStringConfigVar( + utils::GCLOUD_PROJECT_NUMBER.env_var, utils::GCLOUD_PROJECT_NUMBER.toml_var_1, utils::GCLOUD_PROJECT_NUMBER.toml_var_2); + + auto key_name = utils::getStringConfigVar( + utils::GCLOUD_SECRET_MANAGER_KEY_NAME.env_var, utils::GCLOUD_SECRET_MANAGER_KEY_NAME.toml_var_1, utils::GCLOUD_SECRET_MANAGER_KEY_NAME.toml_var_2); - auto project_id = config["gcloud"]["project_id"].as_string()->get(); - auto project_number = config["gcloud"]["project_number"].as_string()->get(); - auto key_name = config["secretmanager"]["key_name"].as_string()->get(); auto version = 1; namespace secretmanager = ::google::cloud::secretmanager_v1; @@ -34,12 +37,17 @@ namespace key_manager { std::string decrypt_secret(std::string const& encrypted_secret) { - auto config = toml::parse_file("Settings.toml"); + auto location_id = utils::getStringConfigVar( + utils::GCLOUD_LOCATION_ID.env_var, utils::GCLOUD_LOCATION_ID.toml_var_1, utils::GCLOUD_LOCATION_ID.toml_var_2); + + auto project_id = utils::getStringConfigVar( + utils::GCLOUD_PROJECT_ID.env_var, utils::GCLOUD_PROJECT_ID.toml_var_1, utils::GCLOUD_PROJECT_ID.toml_var_2); + + auto key_ring = utils::getStringConfigVar( + utils::GCLOUD_KMS_RING.env_var, utils::GCLOUD_KMS_RING.toml_var_1, utils::GCLOUD_KMS_RING.toml_var_2); - auto location_id = config["gcloud"]["location_id"].as_string()->get(); - auto project_id = config["gcloud"]["project_id"].as_string()->get(); - auto key_ring = config["kms"]["ring"].as_string()->get(); - auto crypto_key = config["kms"]["crypto_key"].as_string()->get(); + auto crypto_key = utils::getStringConfigVar( + utils::GCLOUD_CRYPTO_KEY.env_var, utils::GCLOUD_CRYPTO_KEY.toml_var_1, utils::GCLOUD_CRYPTO_KEY.toml_var_2); namespace kms = ::google::cloud::kms_v1; auto client = kms::KeyManagementServiceClient(kms::MakeKeyManagementServiceConnection()); diff --git a/lockbox/src/hashicorp_key_manager.cpp b/lockbox/src/hashicorp_key_manager.cpp index ed58fa26..ff5df759 100644 --- a/lockbox/src/hashicorp_key_manager.cpp +++ b/lockbox/src/hashicorp_key_manager.cpp @@ -4,16 +4,16 @@ #include #include #include "utils.h" -#include namespace hashicorp_key_manager { std::string get_access_token() { - auto config = toml::parse_file("Settings.toml"); + const std::string client_id = utils::getStringConfigVar( + utils::HASHICORP_HCP_CLIENT_ID.env_var, utils::HASHICORP_HCP_CLIENT_ID.toml_var_1, utils::HASHICORP_HCP_CLIENT_ID.toml_var_2); - const std::string client_id = config["hashicorp"]["hcp_client_id"].as_string()->get(); - const std::string client_secret = config["hashicorp"]["hcp_client_secret"].as_string()->get(); + const std::string client_secret = utils::getStringConfigVar( + utils::HASHICORP_HCP_CLIENT_SECRET.env_var, utils::HASHICORP_HCP_CLIENT_SECRET.toml_var_1, utils::HASHICORP_HCP_CLIENT_SECRET.toml_var_2); // Make the HTTP POST request using cpr cpr::Response response = cpr::Post( @@ -50,12 +50,17 @@ namespace hashicorp_key_manager { std::string get_secret(const std::string& hcp_api_token) { - auto config = toml::parse_file("Settings.toml"); + const std::string organization_id = utils::getStringConfigVar( + utils::HASHICORP_ORGANIZATION_ID.env_var, utils::HASHICORP_ORGANIZATION_ID.toml_var_1, utils::HASHICORP_ORGANIZATION_ID.toml_var_2); - const std::string organization_id = config["hashicorp"]["organization_id"].as_string()->get(); - const std::string project_id = config["hashicorp"]["project_id"].as_string()->get(); - const std::string app_name = config["hashicorp"]["app_name"].as_string()->get(); - const std::string secret_name = config["hashicorp"]["secret_name"].as_string()->get(); + const std::string project_id = utils::getStringConfigVar( + utils::HASHICORP_PROJECT_ID.env_var, utils::HASHICORP_PROJECT_ID.toml_var_1, utils::HASHICORP_PROJECT_ID.toml_var_2); + + const std::string app_name = utils::getStringConfigVar( + utils::HASHICORP_APP_NAME.env_var, utils::HASHICORP_APP_NAME.toml_var_1, utils::HASHICORP_APP_NAME.toml_var_2); + + const std::string secret_name = utils::getStringConfigVar( + utils::HASHICORP_SECRET_NAME.env_var, utils::HASHICORP_SECRET_NAME.toml_var_1, utils::HASHICORP_SECRET_NAME.toml_var_2); // Construct the URL std::string url = "https://api.cloud.hashicorp.com/secrets/2023-11-28/organizations/" + organization_id + diff --git a/lockbox/src/server.cpp b/lockbox/src/server.cpp index e0492b19..7076bd78 100644 --- a/lockbox/src/server.cpp +++ b/lockbox/src/server.cpp @@ -186,14 +186,8 @@ namespace lockbox { } std::string getKeyManager() { - const char* value = std::getenv("KEY_MANAGER"); - - if (value == nullptr) { - auto config = toml::parse_file("Settings.toml"); - return config["general"]["key_manager"].as_string()->get(); - } else { - return std::string(value); - } + return utils::getStringConfigVar( + utils::KEY_MANAGER.env_var, utils::KEY_MANAGER.toml_var_1, utils::KEY_MANAGER.toml_var_2); } void start_server() { diff --git a/lockbox/src/utils.cpp b/lockbox/src/utils.cpp index 86e4fdbb..96b9a740 100644 --- a/lockbox/src/utils.cpp +++ b/lockbox/src/utils.cpp @@ -107,14 +107,25 @@ namespace utils { } uint16_t getServerPort() { - const char* value = std::getenv("ENCLAVE_PORT"); + const char* value = std::getenv(SERVER_PORT.env_var.c_str()); if (value == nullptr) { auto config = toml::parse_file("Settings.toml"); - int64_t server_port = config["general"]["server_port"].as_integer()->get(); + int64_t server_port = config[SERVER_PORT.toml_var_1][SERVER_PORT.toml_var_2].as_integer()->get(); return convertInt64ToUint16(server_port); } else { return convertStringToUint16(value); } } + + std::string getStringConfigVar(const std::string& env_var, const std::string& toml_var_1, const std::string& toml_var_2) { + const char* value = std::getenv(env_var.c_str()); + + if (value == nullptr) { + auto config = toml::parse_file("Settings.toml"); + return config[toml_var_1][toml_var_2].as_string()->get(); + } else { + return std::string(value); + } + } } diff --git a/lockbox/vcpkg.json b/lockbox/vcpkg.json index 3e283d2b..a686de69 100644 --- a/lockbox/vcpkg.json +++ b/lockbox/vcpkg.json @@ -16,6 +16,10 @@ { "name": "openssl", "version>=": "3.4.0" + }, + { + "name": "cpr", + "version>=": "1.11.1" } ] }