Skip to content

Commit

Permalink
Add a test that the impersonation config option has effect.
Browse files Browse the repository at this point in the history
  • Loading branch information
teo-tsirpanis committed Mar 12, 2024
1 parent 7619b09 commit 9795aa2
Show file tree
Hide file tree
Showing 3 changed files with 79 additions and 12 deletions.
46 changes: 46 additions & 0 deletions test/src/unit-vfs.cc
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,11 @@
#include <azure/storage/blobs.hpp>
#include "tiledb/sm/filesystem/azure.h"
#endif
#ifdef HAVE_GCS
#include <google/cloud/internal/credentials_impl.h>
#include <google/cloud/storage/client.h>
#include "tiledb/sm/filesystem/gcs.h"
#endif
#include "test/support/src/vfs_helpers.h"
#include "tiledb/sm/filesystem/vfs.h"
#include "tiledb/sm/global_state/unit_test_config.h"
Expand Down Expand Up @@ -738,3 +743,44 @@ TEST_CASE("Validate vfs.s3.custom_headers.*", "[s3][custom-headers]") {
REQUIRE_THROWS_WITH(s3.flush_object(uri), matcher);
}
#endif

#ifdef HAVE_GCS
TEST_CASE(
"Validate GCS service account impersonation", "[gcs][impersonation]") {
ThreadPool thread_pool(2);
Config cfg = set_config_params(true);
GCS gcs;
std::string impersonate_service_account, target_service_account;
std::vector<std::string> delegates;

SECTION("Simple") {
impersonate_service_account = "account1";
target_service_account = "account1";
delegates = {};
}

SECTION("Nested") {
impersonate_service_account = "account1,account2,account3";
target_service_account = "account3";
delegates = {"account1", "account2"};
}

require_tiledb_ok(cfg.set(
"vfs.gcs.impersonate_service_account", impersonate_service_account));

require_tiledb_ok(gcs.init(cfg, &thread_pool));

auto credentials = gcs.make_credentials({});

// We are using an internal class only for inspection purposes.
auto impersonate_credentials =
dynamic_cast<google::cloud::internal::ImpersonateServiceAccountConfig*>(
credentials.get());

REQUIRE(impersonate_credentials != nullptr);
REQUIRE(
impersonate_credentials->target_service_account() ==
target_service_account);
REQUIRE(impersonate_credentials->delegates() == delegates);
}
#endif
24 changes: 14 additions & 10 deletions tiledb/sm/filesystem/gcs.cc
Original file line number Diff line number Diff line change
Expand Up @@ -180,6 +180,17 @@ static shared_ptr<google::cloud::Credentials> apply_impersonation(
std::move(credentials), std::move(service_accounts), std::move(options));
}

std::shared_ptr<google::cloud::Credentials> GCS::make_credentials(
const google::cloud::Options& options) const {
shared_ptr<google::cloud::Credentials> creds = nullptr;
if (!endpoint_.empty() || getenv("CLOUD_STORAGE_EMULATOR_ENDPOINT")) {
creds = google::cloud::MakeInsecureCredentials();
} else {
creds = google::cloud::MakeGoogleDefaultCredentials(options);
}
return apply_impersonation(creds, impersonate_service_account_, options);
}

Status GCS::init_client() const {
assert(state_ == State::INITIALIZED);

Expand All @@ -201,7 +212,7 @@ Status GCS::init_client() const {
}

// Note that the order here is *extremely important*
// We must call MakeGoogleDefaultCredentials *with* a ca_options
// We must call make_credentials *with* a ca_options
// argument, or else the Curl handle pool will be default-initialized
// with no root dir (CURLOPT_CAINFO), defaulting to build host path.
// Later initializations of ClientOptions/Client with the ca_options
Expand All @@ -211,16 +222,9 @@ Status GCS::init_client() const {
// Creates the client using the credentials file pointed to by the
// env variable GOOGLE_APPLICATION_CREDENTIALS
try {
shared_ptr<google::cloud::Credentials> creds = nullptr;
if (!endpoint_.empty() || getenv("CLOUD_STORAGE_EMULATOR_ENDPOINT")) {
creds = google::cloud::MakeInsecureCredentials();
} else {
creds = google::cloud::MakeGoogleDefaultCredentials(ca_options);
}
creds =
apply_impersonation(creds, impersonate_service_account_, ca_options);
auto client_options = ca_options;
client_options.set<google::cloud::UnifiedCredentialsOption>(creds);
client_options.set<google::cloud::UnifiedCredentialsOption>(
make_credentials(ca_options));
if (!endpoint_.empty()) {
client_options.set<google::cloud::storage::RestEndpointOption>(endpoint_);
}
Expand Down
21 changes: 19 additions & 2 deletions tiledb/sm/filesystem/gcs.h
Original file line number Diff line number Diff line change
Expand Up @@ -49,11 +49,17 @@

using namespace tiledb::common;

namespace google::cloud::storage {
namespace google::cloud {
GOOGLE_CLOUD_CPP_INLINE_NAMESPACE_BEGIN
class Credentials;
class Options;
GOOGLE_CLOUD_CPP_INLINE_NAMESPACE_END
namespace storage {
GOOGLE_CLOUD_CPP_INLINE_NAMESPACE_BEGIN
class Client;
GOOGLE_CLOUD_CPP_INLINE_NAMESPACE_END
} // namespace google::cloud::storage
} // namespace storage
} // namespace google::cloud

namespace tiledb {

Expand Down Expand Up @@ -309,6 +315,17 @@ class GCS {
*/
Status flush_object(const URI& uri);

/**
* Creates a GCS credentials object.
*
* This method is intended to be used by testing code only.
*
* @param options Options to configure the credentials.
* @return shared pointer to credentials
*/
std::shared_ptr<google::cloud::Credentials> make_credentials(
const google::cloud::Options& options) const;

private:
/* ********************************* */
/* PRIVATE DATATYPES */
Expand Down

0 comments on commit 9795aa2

Please sign in to comment.