Search code examples
gogoogle-cloud-platformauthorizationservice-accounts

How can I authenticate to GCP using a service account key that was uploaded (not generated)?


Im writing a service that requires access to GCP services by different tenants. My micro-service will run on different host (no GCP). One of the constraints I have is to authorize api calls by using service account key. Second constraint is that my micro-service is responsible for generating the key pair for the service account and share the public key with the tenant so they can upload it to their service account.

My current problem is that Im not able to find any documentation that explains how I can authenticate to GCP golang libraries using the key pair I have. All the documentation I have read always addresses the service account key authentication from the assumption that you will let GCP generate the key pair for you and you already have the json file with all the details required.

Documentation I have reviewed:

- https://cloud.google.com/docs/authentication/client-libraries#adc
- https://cloud.google.com/docs/authentication#service-accounts
- https://cloud.google.com/docs/authentication/provide-credentials-adc#local-key
- https://github.com/GoogleCloudPlatform/golang-samples/blob/main/auth/id_token_from_service_account.go

Google libraries use a mechanism called Application Default Credentials that lets all their libraries find the credentials to use for authentication. Specifically in this scenario, ADC always requires a json file in order to get the details of the credentials.

The json file looks like the following:

{
    "type": "service_account",
    "project_id": "my-project",
    "private_key_id": "1ed3aae07f98f3e6da78ad308b41232133d006cf",
    "private_key": "-----BEGIN PRIVATE KEY-----\n...==\n-----END PRIVATE KEY-----\n",
    "client_email": "<EMAIL HERE>",
    "client_id": "1234567890102",
    "auth_uri": "<GOOGLE AUTH URI HERE>",
    "token_uri": "<GOOGLE TOKEN URI HERE>",
    "auth_provider_x509_cert_url": "<SOME GOOGLE URL HERE>",
    "client_x509_cert_url": "<MORE GOOGLE URL HERE>",
    "universe_domain": "googleapis.com"
}

So my question is, how can I build this json file from my generated key pair? If this is no possible (GCP constraints), then why am I able to upload a key pair? Is there any example out there someone could point me towards to help me with this scenario?

Any help is greatly appreciated

I have looked into all the GCP official documentation, the API reference and the Github script samples. None of them make reference to uploaded service account keys


Solution

  • Took a some time to come back to this question. Thanks to @guillaume-blaquiere answer I started testing with a minimum required file.

    And finally came up with this:

    {
      "type": "service_account",
      "private_key": "<Your generated private_key.pem>",
      "client_email": "<service account email>",
    }
    

    These are the minimum required attributes for google SDK's to successfully authenticate to GCP

    The private key must be the one used to generate the public key uploaded to GCP's service account.

    In terms of the golang code, this information can be put into an structure and then parse that structure to json:

    type JSONFile struct {
      Type     string `json:"type"`
      PrivKey  []byte `json:"private_key"`
      Email    string `json:"client_email"`
    }
    

    Then:

    file := JSONFile{
        Type:        "service_account",
        PrivKey:  "<PK bytes here>",
        Email: "[email protected]",
    }
    result, err := json.Marshal(file)
    if err != nil {
        panic(1)
    }
    credentials, err := google.CredentialsFromJSON(context.Background(), result, secretmanager.DefaultAuthScopes()...)
    if err != nil {
        panic(1)
    }
    projectsClient, err := resourcemanager.NewProjectsClient(context.Background(), option.WithCredentials(credentials))