Authentication to Kubernetes API of GKE cluster within Google Cloud Function

8/14/2018

What is the best way to authenticate to the Kubernetes API of a GKE cluster in the context of a Google Cloud Function? After digging into the source code of google-auth-library and @kubernetes/client-node, I came up with the solution below by using some undocumented APIs. It works, but I wonder if this is the right way to do it, and if there is something ready-to-use out there.

It is particularly strange that https://cloud.google.com/kubernetes-engine/docs/reference/rest/v1/projects.zones.clusters#MasterAuth also returns clientCertificate and clientKey. Using those for opts.cert and opts.key instead of the access token lead to the following error:

Error from server (Forbidden): namespaces "footest" is forbidden: User "client" cannot delete namespaces in the namespace "footest": Unknown user "client"
const { auth } = require('google-auth-library');
const k8s = require('@kubernetes/client-node');

const CLUSTER_ID = 'cluster';
const ZONE = 'us-central1';

async function deleteNamespace(namespace) {
  const cluster = await getCluster(ZONE, CLUSTER_ID);
  const token = await auth.getAccessToken();
  const k8sApi = new k8s.Core_v1Api('https://' + cluster.endpoint);
  k8sApi.setDefaultAuthentication({
    applyToRequest: (opts) => {
      opts.ca = Buffer.from(cluster.masterAuth.clusterCaCertificate, 'base64');
      if (!opts.headers) {
        opts.headers = [];
      }
      opts.headers.Authorization = 'Bearer ' + token;
    },
  });

  await k8sApi.deleteNamespace(namespace, {});
}

async function getCluster(zone, clusterId) {
  const googleApi = await getGoogleApi();
  const projectId = googleApi.projectId;
  const res = await googleApi.client.request({
    url: `https://container.googleapis.com/v1/projects/${projectId}/zones/${zone}/clusters/${clusterId}`,
  });
  return res.data;
}

async function getGoogleApi() {
  const res = await auth.getApplicationDefault();
  const client = res.credential;

  // The createScopedRequired method returns true when running on GAE or a local developer
  // machine. In that case, the desired scopes must be passed in manually. When the code is
  // running in GCE or a Managed VM, the scopes are pulled from the GCE metadata server.
  // See https://cloud.google.com/compute/docs/authentication for more information.
  if (client.createScopedRequired && client.createScopedRequired()) {
    // Scopes can be specified either as an array or as a single, space-delimited string.
    const scopes = ['https://www.googleapis.com/auth/cloud-platform'];
    client = client.createScoped(scopes);
  }

  return {
    client: client,
    projectId: res.projectId,
  };
}
-- drizzd
google-cloud-functions
google-kubernetes-engine
kubernetes

0 Answers