Search code examples
google-cloud-platformgoogle-cloud-storagegoogle-cloud-cpp

How to set the Project ID for C++ storage client


How does one set the Project ID for the C++ Google Cloud Storage client?

The example code below throws an exception:

Permanent error SignBlob: Received HTTP status code: 404

If I set the environment variable, the code works.

set GOOGLE_CLOUD_PROJECT=example_project_id

My goal is to not use environment variables. The Project ID is retrieved from a JSON configuration file.

#include "google/cloud/storage/client.h"

int main()
{
    namespace gcs = ::google::cloud::storage;
    using ::google::cloud::StatusOr;

    std::string project_id = "example_project_id";
    std::string bucket_name = "example_bucket_name";
    std::string object_name = "example_object_name";

    auto client = gcs::Client(
        google::cloud::Options{}
            .set<gcs::ProjectIdOption>(project_id)
    );

    StatusOr<std::string> signed_url = client.CreateV4SignedUrl(
        "GET",
        std::move(bucket_name),
        std::move(object_name),
        gcs::SignedUrlDuration(std::chrono::minutes(15)));

    if (!signed_url)
    {
        std::cout << signed_url.status().message() << "\n";
        throw std::move(signed_url).status();
    }

    std::cout
        << "The signed url is: " << *signed_url << "\n\n"
        << "You can use this URL with any user agent, for example:\n"
        << "curl '" << *signed_url << "'\n";
}

Update 2023-05-27 after @coryan's answer.

If I remove setting the client option google::cloud::Options{}.set<gcs::ProjectIdOption>(project_id), clear the environment variable GOOGLE_CLOUD_PROJECT, and set the SigningAccount to a valid service account email address that I have IAM permission to use, the following code works.

However, that does not explain why <gcs::ProjectIdOption> does not work in the above example. While setting the environment variable GOOGLE_CLOUD_PROJECT does enable the above example to work.

#include "google/cloud/storage/client.h"

void test1()
{
    namespace gcs = ::google::cloud::storage;
    using ::google::cloud::StatusOr;

    std::string project_id = "example_project_id";
    std::string bucket_name = "example_bucket_name";
    std::string object_name = "example_object_name";
    std::string sa_email = "example_service_account_email";

    auto client = gcs::Client();

    StatusOr<std::string> signed_url = client.CreateV4SignedUrl(
        "GET",
        std::move(bucket_name),
        std::move(object_name),
        gcs::SignedUrlDuration(std::chrono::minutes(15)),
        gcs::SigningAccount(sa_email)
    );

    if (!signed_url)
    {
        std::cout << signed_url.status().message() << "\n";
        throw std::move(signed_url).status();
    }

    std::cout << "The signed url is: " << *signed_url << "\n\n";
}

Solution

  • Why do you think the project id is what is missing here? I suspect this has nothing to do with the ProjectIdOption but with a missing default value for the signing service account email. I have filed #11740 because the error message is not useful at all.

    When the credentials are obtained from a service account key file, the client library create the signed URL locally, using the private key from the key file.

    When the credentials are not a service account key file (user accounts, the GCE metadata service, whatever), the client library can use IAM signBlob to sign the blob.

    In the latter case it needs the service account email of the request to sign. For some credential types there is a default email associated with the credentials. But sometimes there is none, or the value cannot be retrieved, for example, the metadata service may be unresponsive.

    Without a default value for the service account email, the client library sends a request to IAM signBlob with an empty email address. This results in a 404 error without additional details.

    The application can provide a service account email, as shown in the CreateV4SignedURL() examples:

    https://googleapis.dev/cpp/google-cloud-storage/latest/classgoogle_1_1cloud_1_1storage_1_1Client.html#a4600b6b5123e51283168ca2cf53926bf

    If that is not the problem, please let us know and we will try to get this fixed.