在Google Cloud Function中对GKE集群的Kubernetes API进行身份验证

dri*_*zzd 7 kubernetes google-kubernetes-engine google-cloud-functions

在Google Cloud Function上下文中对GKE集群的Kubernetes API进行身份验证的最佳方法是什么?在深入研究google-auth-libraryand 的源代码之后@kubernetes/client-node,我通过使用一些未公开的API提出了以下解决方案。它可以工作,但是我想知道这是否是正确的方法,以及那里是否有随时可用的东西。

https://cloud.google.com/kubernetes-engine/docs/reference/rest/v1/projects.zones.clusters#MasterAuth还返回clientCertificate和clientKey ,这尤其奇怪。将那些用于opts.certopts.key代替访问令牌会导致以下错误:

Error from server (Forbidden): namespaces "footest" is forbidden: User "client" cannot delete namespaces in the namespace "footest": Unknown user "client"
Run Code Online (Sandbox Code Playgroud)
Error from server (Forbidden): namespaces "footest" is forbidden: User "client" cannot delete namespaces in the namespace "footest": Unknown user "client"
Run Code Online (Sandbox Code Playgroud)

Sha*_*ean 4

上述错误似乎是由于用户无效或没有正确的权限造成的。

您可以使用该@google-cloud/container库从 GKE 获取有关集群的详细信息,并使用返回的信息在客户端中设置@kubernetes/client-node.

为了能够使用该@google-cloud/container库获取集群信息,您应该有一个JsonKey由环境变量指向的有效 GCP 服务帐户文件:GOOGLE_APPLICATION_CREDENTIALS

以下是从 GKE 获取集群凭据并随后使用它@kubernetes/client-node与 K8s API 进行交互的代码片段。

此处提供的示例遵循这两条评论中提供的解释。(12

const googleContainer = require('@google-cloud/container');
const k8s = require('@kubernetes/client-node');

// Create the Cluster Manager Client
const client = new googleContainer.v1.ClusterManagerClient();

/**
 * The following function is equivalent to the 'get-credentials' call using
 * gcloud. The client assumes that the 'GOOGLE_APPLICATION_CREDENTIALS'
 * environment variable is set to the json key file associated to your GCP
 * service account (https://cloud.google.com/docs/authentication/production#create_service_account).
 *
 * The return values of this method are the credentials that are used to update
 * the k8s config file (~/.kube/config) to add a new context when
 * 'get-credentials' is invoked by the 'gcloud' CLI
 */
async function getCredentials(cluster, zone) {
  const projectId = await client.getProjectId();
  const accessToken = await client.auth.getAccessToken();
  const request = {
    projectId: projectId,
    zone: zone,
    clusterId: cluster
  };

  const [response] = await client.getCluster(request);
  // the following are the parameters added when a new k8s context is created
  return {
    // the endpoint set as 'cluster.server'
    endpoint: response.endpoint,
    // the certificate set as 'cluster.certificate-authority-data'
    certificateAuthority: response.masterAuth.clusterCaCertificate,
    // the accessToken set as 'user.auth-provider.config.access-token'
    accessToken: accessToken
  }
}

async function listServices(cluster, zone) {
  const k8sCredentials = await getCredentials(cluster, zone);
  const k8sClientConfig = new k8s.KubeConfig();
  k8sClientConfig.loadFromOptions({
    clusters: [{
      name: `my-gke-cluster_${cluster}`,            // any name can be used here
      caData: k8sCredentials.certificateAuthority,  // <-- this is from getCredentials call
      server: `https://${k8sCredentials.endpoint}`, // <-- this is from getCredentials call
    }],
    users: [{
      name: `my-gke-cluster_${cluster}`,
      authProvider: 'gcp',                          // the is not a required field
      token: k8sCredentials.accessToken             // <-- this is from getCredentials call
    }],
    contexts: [{
      name: `my-gke-cluster_${cluster}`,
      user: `my-gke-cluster_${cluster}`,
      cluster: `my-gke-cluster_${cluster}`
    }],
    currentContext: `my-gke-cluster_${cluster}`,
  });
  const k8sApi = k8sClientConfig.makeApiClient(k8s.CoreV1Api);
  k8sApi.listNamespacedService('default').then((res) => {
    printServices(res.body.items);
  });
}

function printServices(services) {
  services.forEach(svc => {
    const name = svc.metadata.name;
    const type = svc.spec.type;
    const clusterIp = svc.spec.clusterIP;
    const externalIP = svc.spec.externalIPs || "<none>";
    let ports = "";
    svc.spec.ports.forEach((p) => ports += `${p.port}/${p.protocol},`)
    ports = ports || "<none>"
    console.log(name + "\t" + type + "\t" + clusterIp + "\t" + externalIP + "\t" + ports);
  });
}

// list k8s services in the given cluster and zone
listServices('<CLUSTER>', '<ZONE>');
Run Code Online (Sandbox Code Playgroud)