<p>I need to authenticate to a Kubernetes cluster provisioned in <a href="https://cloud.google.com/kubernetes-engine/" rel="noreferrer">GKE</a> using the <a href="https://github.com/kubernetes-client" rel="noreferrer">Kubernetes Python client</a> and the Google Cloud python client. I would prefer not to shell out to <code>gcloud</code> for several reasons:</p>

<ul>
<li>relying on the system shell <code>gcloud</code> in a Python script when I have a native Google Cloud library is inelegant</li>
<li>it requires the system to have <code>gcloud</code></li>
<li>I would have to switch users to the relevant ServiceAccount and switch back</li>
<li>It incurs the cost of starting/joining another process</li>
</ul>

<p>As such, the workflow of <code>gcloud container clusters get-credentials</code> (which delegates to <code>gcloud config config-helper</code>) will not suffice to get me the API key I need. How do I get the equivalent output with the Google Cloud Python API?</p>

<p>Here is what I have so far:</p>

<pre><code>import kubernetes.client
import googleapiclient.discovery
import base64

# get the cluster object from GKE
gke = googleapiclient.discovery.build('container', 'v1', credentials=config['credentials'])
name = f'projects/{config["project_id"]}/locations/{config["location"]}/{parent}/clusters/{config["name"]}'
gke_clusters = gke.projects().locations().clusters()
gke_cluster = gke_clusters.get(name=name).execute()

# set up Kubernetes Config
kube_config = kubernetes.client.Configuration()
kube_config.host = 'https://{0}/'.format(gke_cluster['endpoint'])
kube_config.verify_ssl = True
#kube_config.api_key['authenticate'] = "don't know what goes here"

# regretably, the Kubernetes client requires `ssl_ca_cert` to be a path, not the literal cert, so I will write it here.
kube_config.ssl_ca_cert = 'ssl_ca_cert'
with open(kube_config.ssl_ca_cert, 'wb') as f:
    f.write(base64.decodestring(gke_cluster['masterAuth']['clusterCaCertificate'].encode()))

# use Kubernetes client to do something
kube_client = kubernetes.client.ApiClient(configuration=kube_config)
kube_v1 = kubernetes.client.CoreV1Api(kube_client)
kube_v1.list_pod_for_all_namespaces(watch=False)
</code></pre>

<p>Below is a solution that pulls the access token out of the googleapiclient, rather than copy-pasting things manually.</p>

<pre class="lang-py prettyprint-override"><code>import googleapiclient.discovery
from tempfile import NamedTemporaryFile
import kubernetes
import base64

def token(*scopes):
    credentials = googleapiclient._auth.default_credentials()
    scopes = [f'https://www.googleapis.com/auth/{s}' for s in scopes]
    scoped = googleapiclient._auth.with_scopes(credentials, scopes)
    googleapiclient._auth.refresh_credentials(scoped)
    return scoped.token

def kubernetes_api(cluster):
    config = kubernetes.client.Configuration()
    config.host = f'https://{cluster["endpoint"]}'

    config.api_key_prefix['authorization'] = 'Bearer'
    config.api_key['authorization'] = token('cloud-platform')

    with NamedTemporaryFile(delete=False) as cert:
        cert.write(base64.decodebytes(cluster['masterAuth']['clusterCaCertificate'].encode()))
        config.ssl_ca_cert = cert.name

    client = kubernetes.client.ApiClient(configuration=config)
    api = kubernetes.client.CoreV1Api(client)

    return api

def run(cluster):
    """You'll need to give whichever account `googleapiclient` is using the 
    'Kubernetes Engine Developer' role so that it can access the Kubernetes API.

    `cluster` should be the dict you get back from `projects.zones.clusters.get`
    and the like"""

    api = kubernetes_api(cluster)
    print(api.list_pod_for_all_namespaces())
</code></pre>

<p>Figuring this out took longer than I care to admit. @Ivan's post helped a lot.</p>
