M. Zro
M. Zro

Reputation: 13

Programmatically authenticate to Google Compute Engine via service access key

After researching the Google Compute Documentation I found out that there is no example of authentication via a generated Service Access Key.

I tried it with the following code (this is line 69)

GoogleCredential credential = new GoogleCredential.Builder()
                .setClientSecrets(authorize())
                .build();

and

private static  GoogleClientSecrets authorize() {
    // initialize client secrets object
    GoogleClientSecrets clientSecrets;
    // load client secrets
    try {
        clientSecrets = GoogleClientSecrets.load(JSON_FACTORY, new InputStreamReader(
                GCEImporter.class.getResourceAsStream("/client_secrets.json")));

    } catch(IOException e){
        e.printStackTrace();
        return null;
    }


    return clientSecrets;
}

the client_secrets.json is the generated file from google which looks like this

{
 "type": "service_account",
 "project_id": "...",
 "private_key_id": "...",
 "private_key": "-----BEGIN PRIVATE KEY-----...-----END PRIVATE KEY-----\n",
 "client_email": "....iam.gserviceaccount.com",
 "client_id": "...",
 "auth_uri": "https://accounts.google.com/o/oauth2/auth",
 "token_uri": "https://accounts.google.com/o/oauth2/token",
 "auth_provider_x509_cert_url": 
 "https://www.googleapis.com/oauth2/v1/certs",
 "client_x509_cert_url": 
 "https://www.googleapis.com/robot/v1/metadata/x509/..."
}

all I receive when executing this code is

java.lang.IllegalArgumentException
at com.google.api.client.repackaged.com.google.common.base.Preconditions.checkArgument(Preconditions.java:111)
at com.google.api.client.util.Preconditions.checkArgument(Preconditions.java:37)
at com.google.api.client.googleapis.auth.oauth2.GoogleClientSecrets.getDetails(GoogleClientSecrets.java:82)
at com.google.api.client.googleapis.auth.oauth2.GoogleCredential$Builder.setClientSecrets(GoogleCredential.java:559)
at net.bytesource.jira.asset.synchronization.importer.google.gce.GCEImporter.getAssets(GCEImporter.java:69)
at net.bytesource.jira.asset.synchronization.importer.google.gce.GoogleImporterTest.getAssets(GoogleImporterTest.java:33)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at java.lang.reflect.Method.invoke(Method.java:498)
at org.junit.runners.model.FrameworkMethod$1.runReflectiveCall(FrameworkMethod.java:45)
at org.junit.internal.runners.model.ReflectiveCallable.run(ReflectiveCallable.java:15)
at org.junit.runners.model.FrameworkMethod.invokeExplosively(FrameworkMethod.java:42)
at org.junit.internal.runners.statements.InvokeMethod.evaluate(InvokeMethod.java:20)
at org.junit.internal.runners.statements.RunBefores.evaluate(RunBefores.java:28)
at org.junit.runners.ParentRunner.runLeaf(ParentRunner.java:263)
at org.junit.runners.BlockJUnit4ClassRunner.runChild(BlockJUnit4ClassRunner.java:68)
at org.junit.runners.BlockJUnit4ClassRunner.runChild(BlockJUnit4ClassRunner.java:47)
at org.junit.runners.ParentRunner$3.run(ParentRunner.java:231)
at org.junit.runners.ParentRunner$1.schedule(ParentRunner.java:60)
at org.junit.runners.ParentRunner.runChildren(ParentRunner.java:229)
at org.junit.runners.ParentRunner.access$000(ParentRunner.java:50)
at org.junit.runners.ParentRunner$2.evaluate(ParentRunner.java:222)
at org.junit.runners.ParentRunner.run(ParentRunner.java:300)
at org.junit.runner.JUnitCore.run(JUnitCore.java:157)
at com.intellij.junit4.JUnit4IdeaTestRunner.startRunnerWithArgs(JUnit4IdeaTestRunner.java:68)
at com.intellij.rt.execution.junit.IdeaTestRunner$Repeater.startRunnerWithArgs(IdeaTestRunner.java:47)
at com.intellij.rt.execution.junit.JUnitStarter.prepareStreamsAndStart(JUnitStarter.java:242)
at com.intellij.rt.execution.junit.JUnitStarter.main(JUnitStarter.java:70)

Does anybody have a solution to this problem?

Upvotes: 1

Views: 1259

Answers (2)

Michael Zronek
Michael Zronek

Reputation: 26

Thanks for your answer Tuxdude. I also have tried your way in advance by copying the example from the website. But this does only work from within an instance in the GCE environment.

I have found the solution myself which was a static method from GoogleCredential class:

GoogleCredential.fromStream(new FileInputStreamReader("path/to/json"))

Upvotes: 1

Tuxdude
Tuxdude

Reputation: 49473

There are few issues here:

  • The private key info json file that you downloaded when you created a new service account from the IAM page is not in the format that is expected by Client Secrets.

  • You're trying to follow the [OAuth steps that are meant for Desktop and mobile apps][2]. This will not work with Google Cloud APIs.

The recommended and simpler way for authorizing with Google Cloud APIs is to use Application Default Credentials which is described here and here.

In short what you need to do is (based on the outline here):

  1. Set the path to the JSON file you have in the environment variable GOOGLE_APPLICATION_CREDENTIALS.

  2. Create the GoogleCredential object as shown below.

GoogleCredential credential = GoogleCredential.getApplicationDefault();

After the above step, you should be able to talk to any of the Google Cloud APIs. In case of GCE, you will create an instance of Compute

Compute compute = new Compute.Builder (transport, jsonFactory, credential).build();

I am just copying and pasting the example from compute.instances.insert API here.

/*
 * BEFORE RUNNING:
 * ---------------
 * 1. If not already done, enable the Compute Engine API
 *    and check the quota for your project at
 *    https://console.developers.google.com/apis/api/compute
 * 2. This sample uses Application Default Credentials for authentication.
 *    If not already done, install the gcloud CLI from
 *    https://cloud.google.com/sdk and run
 *    `gcloud beta auth application-default login`.
 *    For more information, see
 *    https://developers.google.com/identity/protocols/application-default-credentials
 * 3. Install the Java client library on Maven or Gradle. Check installation
 *    instructions at https://github.com/google/google-api-java-client.
 *    On other build systems, you can add the jar files to your project from
 *    https://developers.google.com/resources/api-libraries/download/compute/v1/java
 */
import com.google.api.client.googleapis.auth.oauth2.GoogleCredential;
import com.google.api.client.googleapis.javanet.GoogleNetHttpTransport;
import com.google.api.client.http.HttpTransport;
import com.google.api.client.json.JsonFactory;
import com.google.api.client.json.jackson2.JacksonFactory;
import com.google.api.services.compute.Compute;
import com.google.api.services.compute.model.Instance;
import com.google.api.services.compute.model.Operation;
import java.io.IOException;
import java.security.GeneralSecurityException;
import java.util.Arrays;

public class ComputeExample {
  public static void main(String args[]) throws IOException, GeneralSecurityException {
    // Project ID for this request.
    String project = ""; // TODO: Update placeholder value.

    // The name of the zone for this request.
    String zone = ""; // TODO: Update placeholder value.

    // TODO: Assign values to desired fields of `requestBody`:
    Instance requestBody = new Instance();

    Compute computeService = createComputeService();
    Compute.Instances.Insert request =
        computeService.instances().insert(project, zone, requestBody);

    Operation response = request.execute();

    // TODO: Change code below to process the `response` object:
    System.out.println(response);
  }

  public static Compute createComputeService() throws IOException, GeneralSecurityException {
    HttpTransport httpTransport = GoogleNetHttpTransport.newTrustedTransport();
    JsonFactory jsonFactory = JacksonFactory.getDefaultInstance();

    GoogleCredential credential = GoogleCredential.getApplicationDefault();
    if (credential.createScopedRequired()) {
      credential =
          credential.createScoped(Arrays.asList("https://www.googleapis.com/auth/cloud-platform"));
    }

    return new Compute.Builder(httpTransport, jsonFactory, credential)
        .setApplicationName("Google-ComputeSample/0.1")
        .build();
  }
}

Upvotes: 0

Related Questions