diff --git a/ci/cloudbuild/builds/lib/universe_domain.sh b/ci/cloudbuild/builds/lib/universe_domain.sh index 3ee0ec130f802..306c0d5de4f1e 100644 --- a/ci/cloudbuild/builds/lib/universe_domain.sh +++ b/ci/cloudbuild/builds/lib/universe_domain.sh @@ -32,6 +32,16 @@ if [[ -n "${UD_SERVICE_ACCOUNT}" ]]; then io::log "Created SA key file ${UD_SA_KEY_FILE}" fi +# Only create the IdToken SA key file if the secret is available. +if [[ -n "${UD_IDTOKEN_SA_IMPERSONATION_CRED}" ]]; then + ORIG_UMASK=$(umask) + umask 077 + UD_IDTOKEN_SA_KEY_FILE=$(mktemp) + echo "${UD_IDTOKEN_SA_IMPERSONATION_CRED}" >"${UD_IDTOKEN_SA_KEY_FILE}" + umask "${ORIG_UMASK}" + io::log "Created IdToken SA key file ${UD_IDTOKEN_SA_KEY_FILE}" +fi + function ud::bazel_run() { io::log "Executing bazel run $1 with obscured arguments:" bazel run --ui_event_filters=-info -- "$@" @@ -45,5 +55,6 @@ function ud::bazel_test() { --test_env=UD_REGION="${UD_REGION}" \ --test_env=UD_ZONE="${UD_ZONE}" \ --test_env=UD_IMPERSONATED_SERVICE_ACCOUNT_NAME="${UD_IMPERSONATED_SERVICE_ACCOUNT_NAME}" \ + --test_env=UD_IDTOKEN_SA_KEY_FILE="${UD_IDTOKEN_SA_KEY_FILE}" \ --test_env=UD_PROJECT="${UD_PROJECT}" -- "$@" } diff --git a/ci/cloudbuild/cloudbuild.yaml b/ci/cloudbuild/cloudbuild.yaml index db20831188f05..1355a6260b866 100644 --- a/ci/cloudbuild/cloudbuild.yaml +++ b/ci/cloudbuild/cloudbuild.yaml @@ -78,6 +78,8 @@ availableSecrets: env: 'UD_SERVICE_ACCOUNT_NAME' - versionName: 'projects/${PROJECT_ID}/secrets/UD_IMPERSONATED_SERVICE_ACCOUNT_NAME/versions/latest' env: 'UD_IMPERSONATED_SERVICE_ACCOUNT_NAME' + - versionName: 'projects/${PROJECT_ID}/secrets/UD_IDTOKEN_SA_IMPERSONATION_CRED/versions/latest' + env: 'UD_IDTOKEN_SA_IMPERSONATION_CRED' logsBucket: 'gs://${_LOGS_BUCKET}/logs/google-cloud-cpp/${_TRIGGER_SOURCE}/${COMMIT_SHA}/${_DISTRO}-${_BUILD_NAME}-${_SHARD}' @@ -115,7 +117,7 @@ steps: - name: '${_POOL_REGION}-docker.pkg.dev/${PROJECT_ID}/gcb/${_IMAGE}:${BUILD_ID}' entrypoint: 'ci/cloudbuild/build.sh' args: [ '--local', '--build', '${_BUILD_NAME}' ] - secretEnv: ['CODECOV_TOKEN', 'UD', 'UD_PROJECT', 'UD_REGION', 'UD_ZONE', 'UD_SERVICE_ACCOUNT', 'UD_SERVICE_ACCOUNT_NAME', 'UD_IMPERSONATED_SERVICE_ACCOUNT_NAME'] + secretEnv: ['CODECOV_TOKEN', 'UD', 'UD_PROJECT', 'UD_REGION', 'UD_ZONE', 'UD_SERVICE_ACCOUNT', 'UD_SERVICE_ACCOUNT_NAME', 'UD_IMPERSONATED_SERVICE_ACCOUNT_NAME', 'UD_IDTOKEN_SA_IMPERSONATION_CRED'] env: [ 'BAZEL_REMOTE_CACHE=https://storage.googleapis.com/${_CACHE_BUCKET}/bazel-cache/${_DISTRO}-${_BUILD_NAME}', 'LIBRARIES=${_LIBRARIES}', diff --git a/google/cloud/universe_domain/integration_tests/impersonation_tests.cc b/google/cloud/universe_domain/integration_tests/impersonation_tests.cc index de766e76e59a6..9cb078a47bc07 100644 --- a/google/cloud/universe_domain/integration_tests/impersonation_tests.cc +++ b/google/cloud/universe_domain/integration_tests/impersonation_tests.cc @@ -20,6 +20,7 @@ #include "google/cloud/internal/rest_options.h" #include "google/cloud/location.h" #include "google/cloud/testing_util/integration_test.h" +#include "google/cloud/testing_util/scoped_environment.h" #include "google/cloud/testing_util/status_matchers.h" #include "google/cloud/universe_domain.h" #include "google/cloud/universe_domain_options.h" @@ -33,6 +34,7 @@ GOOGLE_CLOUD_CPP_INLINE_NAMESPACE_BEGIN namespace { namespace gc = ::google::cloud; +using ::google::cloud::testing_util::ScopedEnvironment; using ::google::cloud::testing_util::StatusIs; class DomainUniverseImpersonationTest @@ -45,27 +47,42 @@ class DomainUniverseImpersonationTest ASSERT_FALSE(zone_id_.empty()); region_id_ = gc::internal::GetEnv("UD_REGION").value_or(""); ASSERT_FALSE(region_id_.empty()); + } + + std::string project_id_; + std::string zone_id_; + std::string region_id_; +}; + +class ServiceAccountImpersonationTest : public DomainUniverseImpersonationTest { + protected: + void SetUp() override { + DomainUniverseImpersonationTest::SetUp(); + impersonated_sa_ = gc::internal::GetEnv("UD_IMPERSONATED_SERVICE_ACCOUNT_NAME") .value_or(""); ASSERT_FALSE(impersonated_sa_.empty()); - std::string const sa_key_file = + + std::string const key_file = gc::internal::GetEnv("UD_SA_KEY_FILE").value_or(""); - ASSERT_FALSE(sa_key_file.empty()); + ASSERT_FALSE(key_file.empty()); - auto is = std::ifstream(sa_key_file); + auto is = std::ifstream(key_file); is.exceptions(std::ios::badbit); credential_ = std::string(std::istreambuf_iterator(is.rdbuf()), {}); + + id_token_key_file_ = + gc::internal::GetEnv("UD_IDTOKEN_SA_KEY_FILE").value_or(""); + ASSERT_FALSE(id_token_key_file_.empty()); } - std::string project_id_; - std::string zone_id_; - std::string region_id_; std::string impersonated_sa_; std::string credential_; + std::string id_token_key_file_; }; -TEST_F(DomainUniverseImpersonationTest, SAToSAImpersonationRest) { +TEST_F(ServiceAccountImpersonationTest, SAToSAImpersonationRest) { namespace disks = ::google::cloud::compute_disks_v1; gc::Options options; @@ -84,7 +101,7 @@ TEST_F(DomainUniverseImpersonationTest, SAToSAImpersonationRest) { } } -TEST_F(DomainUniverseImpersonationTest, SAToSAImpersonationGrpc) { +TEST_F(ServiceAccountImpersonationTest, SAToSAImpersonationGrpc) { namespace kms = ::google::cloud::kms_v1; auto const location = gc::Location(project_id_, region_id_); @@ -105,6 +122,21 @@ TEST_F(DomainUniverseImpersonationTest, SAToSAImpersonationGrpc) { } } +TEST_F(ServiceAccountImpersonationTest, IdTokenSAToSAImpersonationRest) { + namespace disks = ::google::cloud::compute_disks_v1; + // Use ADC credential + ScopedEnvironment env("GOOGLE_APPLICATION_CREDENTIALS", id_token_key_file_); + + auto ud_options = gc::AddUniverseDomainOption(gc::ExperimentalTag{}); + ASSERT_STATUS_OK(ud_options); + + auto client = disks::DisksClient(disks::MakeDisksConnectionRest(*ud_options)); + + for (auto disk : client.ListDisks(project_id_, zone_id_)) { + EXPECT_STATUS_OK(disk); + } +} + } // namespace GOOGLE_CLOUD_CPP_INLINE_NAMESPACE_END } // namespace universe_domain