0

Retrieve an Instance Identity token when configuring Cloud hosts

This CL updates the Cloud host provisioning path to request an Instance
Identity token which will be used for configuring remote access for a
specific Compute Engine Instance (and the policies associated with it),
rather than relying on the configuration set at the Project level.

Bug: 388886766
Change-Id: If796e7a88f862e68412690fbff990f36f4aa7e69
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/6270168
Reviewed-by: Gary Kacmarcik <garykac@chromium.org>
Commit-Queue: Joe Downing <joedow@chromium.org>
Cr-Commit-Position: refs/heads/main@{#1420691}
This commit is contained in:
Joe Downing
2025-02-14 12:50:39 -08:00
committed by Chromium LUCI CQ
parent acc168ed8b
commit 8032831039
4 changed files with 39 additions and 1 deletions

@ -312,6 +312,7 @@ void CloudServiceClient::ProvisionGceInstance(
const std::string& display_name,
const std::string& public_key,
const std::optional<std::string>& existing_directory_id,
const std::optional<std::string>& instance_identity_token,
ProvisionGceInstanceCallback callback) {
constexpr char path[] = "/v1/provisioning:provisionGceInstance";
@ -323,6 +324,10 @@ void CloudServiceClient::ProvisionGceInstance(
if (existing_directory_id.has_value() && !existing_directory_id->empty()) {
request->set_existing_directory_id(*existing_directory_id);
}
if (instance_identity_token.has_value() &&
!instance_identity_token->empty()) {
request->set_instance_identity_token(*instance_identity_token);
}
ExecuteRequest(kProvisionGceInstanceTrafficAnnotation, path, api_key_,
net::HttpRequestHeaders::kPostMethod, std::move(request),

@ -95,6 +95,7 @@ class CloudServiceClient {
const std::string& display_name,
const std::string& public_key,
const std::optional<std::string>& existing_directory_id,
const std::optional<std::string>& instance_identity_token,
ProvisionGceInstanceCallback callback);
void SendHeartbeat(const std::string& directory_id,

@ -19,6 +19,7 @@
#include "remoting/base/http_status.h"
#include "remoting/base/oauth_token_info.h"
#include "remoting/base/passthrough_oauth_token_getter.h"
#include "remoting/base/service_urls.h"
#include "remoting/host/host_config.h"
#include "remoting/host/setup/host_starter.h"
#include "remoting/host/setup/host_starter_base.h"
@ -43,7 +44,9 @@ class CloudHostStarter : public HostStarterBase {
~CloudHostStarter() override;
// ComputeEngineServiceClient callbacks.
void OnApiAccessTokenRetrieved(const HttpStatus& status);
void OnIdentityTokenRetrieved(const HttpStatus& status);
// HostStarterBase implementation.
void RetrieveApiAccessToken() override;
@ -63,6 +66,8 @@ class CloudHostStarter : public HostStarterBase {
std::unique_ptr<PassthroughOAuthTokenGetter> api_access_token_getter_;
std::optional<std::string> instance_identity_token_;
SEQUENCE_CHECKER(sequence_checker_);
base::WeakPtrFactory<CloudHostStarter> weak_ptr_factory_{this};
@ -80,6 +85,27 @@ CloudHostStarter::~CloudHostStarter() = default;
void CloudHostStarter::RetrieveApiAccessToken() {
DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
// Try to retrieve an Instance Identity Token before the access token. Making
// this query first simplifies the logic a bit as we may end up skipping the
// the access token request if an API_KEY is provided but we want to try to
// get the identity token for both scenarios.
compute_engine_service_client_->GetInstanceIdentityToken(
/*audience=*/ServiceUrls::GetInstance()->remoting_cloud_public_endpoint(),
base::BindOnce(&CloudHostStarter::OnIdentityTokenRetrieved,
weak_ptr_factory_.GetWeakPtr()));
}
void CloudHostStarter::OnIdentityTokenRetrieved(const HttpStatus& status) {
if (status.ok() && !status.response_body().empty()) {
instance_identity_token_ = status.response_body();
} else {
int error_code = static_cast<int>(status.error_code());
LOG(WARNING) << "Failed to retrieve an Instance Identity token.\n"
<< " Error code: " << error_code << "\n"
<< " Message: " << status.error_message() << "\n"
<< " Body: " << status.response_body();
}
// The two modes to configure a Cloud host are to generate an API_KEY and use
// that to access the provisioning RPC or to generate an access token using
// the default service-account. If an API_KEY is being used, we can skip the
@ -137,7 +163,7 @@ void CloudHostStarter::RegisterNewHost(
cloud_service_client_->ProvisionGceInstance(
params().owner_email, params().name, key_pair().GetPublicKey(),
existing_host_id(),
existing_host_id(), std::move(instance_identity_token_),
base::BindOnce(&CloudHostStarter::OnProvisionGceInstanceResponse,
weak_ptr_factory_.GetWeakPtr()));
}

@ -31,6 +31,12 @@ message ProvisionGceInstanceRequest {
// backend will validate the other fields in the request and ensure
// `owner_email` owns the previous instance as well.
optional string existing_directory_id = 5;
// An instance identity token which includes GCP project and instance
// information for a specific Compute Engine Instance.
// More information about the contents of the token can be found at:
// https://cloud.google.com/compute/docs/instances/verifying-instance-identity
optional string instance_identity_token = 6;
}
// Represents a service account created for a remote access host instance.