<p>I need to create a Kubernetes clientset using a token extracted from JSON service account key file.</p>
<p>I explicitly provide this token inside the config, however it still looks for Google Application-Default credentials, and crashes because it cannot find them.</p>
<p>Below is my code:</p>
<pre><code>package main

import (
    &quot;context&quot;
    &quot;encoding/base64&quot;
    &quot;fmt&quot;
    &quot;io/ioutil&quot;

    &quot;golang.org/x/oauth2&quot;
    &quot;golang.org/x/oauth2/google&quot;
    gke &quot;google.golang.org/api/container/v1&quot;
    &quot;google.golang.org/api/option&quot;
    &quot;k8s.io/client-go/kubernetes&quot;
    _ &quot;k8s.io/client-go/plugin/pkg/client/auth/gcp&quot;
    &quot;k8s.io/client-go/tools/clientcmd&quot;
    &quot;k8s.io/client-go/tools/clientcmd/api&quot;
)

const (
    projectID   = &quot;my_project_id&quot;
    clusterName = &quot;my_cluster_name&quot;
    scope       = &quot;https://www.googleapis.com/auth/cloud-platform&quot;
)

func main() {
    ctx := context.Background()

    // Read JSON key and extract the token
    data, err := ioutil.ReadFile(&quot;sa_key.json&quot;)
    if err != nil {
        panic(err)
    }
    creds, err := google.CredentialsFromJSON(ctx, data, scope)
    if err != nil {
        panic(err)
    }
    token, err := creds.TokenSource.Token()
    if err != nil {
        panic(err)
    }
    fmt.Println(&quot;token&quot;, token.AccessToken)

    // Create GKE client
    tokenSource := oauth2.StaticTokenSource(token)
    gkeClient, err := gke.NewService(ctx, option.WithTokenSource(tokenSource))
    if err != nil {
        panic(err)
    }

    // Create a dynamic kube config
    inMemKubeConfig, err := createInMemKubeConfig(ctx, gkeClient, token, projectID)
    if err != nil {
        panic(err)
    }

    // Use it to create a rest.Config
    config, err := clientcmd.NewNonInteractiveClientConfig(*inMemKubeConfig, clusterName, &amp;clientcmd.ConfigOverrides{CurrentContext: clusterName}, nil).ClientConfig()
    if err != nil {
        panic(err)
    }

    // Create the clientset
    clientset, err := kubernetes.NewForConfig(config)
    if err != nil {
        panic(err) // this where the code crashes because it can't find the Google ADCs
    }

    fmt.Printf(&quot;clientset %+v\n&quot;, clientset)
}

func createInMemKubeConfig(ctx context.Context, client *gke.Service, token *oauth2.Token, projectID string) (*api.Config, error) {
    k8sConf := api.Config{
        APIVersion: &quot;v1&quot;,
        Kind:       &quot;Config&quot;,
        Clusters:   map[string]*api.Cluster{},
        AuthInfos:  map[string]*api.AuthInfo{},
        Contexts:   map[string]*api.Context{},
    }

    // List all clusters in project with id projectID across all zones (&quot;-&quot;)
    resp, err := client.Projects.Zones.Clusters.List(projectID, &quot;-&quot;).Context(ctx).Do()
    if err != nil {
        return nil, err
    }

    for _, f := range resp.Clusters {
        name := fmt.Sprintf(&quot;gke_%s_%s_%s&quot;, projectID, f.Zone, f.Name) // My custom naming convention
        cert, err := base64.StdEncoding.DecodeString(f.MasterAuth.ClusterCaCertificate)
        if err != nil {
            return nil, err
        }

        k8sConf.Clusters[name] = &amp;api.Cluster{
            CertificateAuthorityData: cert,
            Server:                   &quot;https://&quot; + f.Endpoint,
        }

        k8sConf.Contexts[name] = &amp;api.Context{
            Cluster:  name,
            AuthInfo: name,
        }

        k8sConf.AuthInfos[name] = &amp;api.AuthInfo{
            Token: token.AccessToken,
            AuthProvider: &amp;api.AuthProviderConfig{
                Name: &quot;gcp&quot;,
                Config: map[string]string{
                    &quot;scopes&quot;: scope,
                },
            },
        }
    }
    return &amp;k8sConf, nil
}
</code></pre>
<p>and here is the error message:</p>
<pre><code>panic: cannot construct google default token source: google: could not find default credentials. See https://developers.google.com/accounts/docs/application-default-credentials for more information.
</code></pre>

<p>Here's what worked for me.</p>
<p>It is based on this <a href="https://gist.github.com/ahmetb/548059cdbf12fb571e4e2f1e29c48997" rel="nofollow noreferrer">gist</a>
and it's exactly what I was looking for. It uses an <code>oauth2.TokenSource</code> object which can be fed with a variety of token types so it's quite flexible.</p>
<p>It took me a long time to find this solution so I hope this helps somebody!</p>
<pre><code>package main

import (
    &quot;context&quot;
    &quot;encoding/base64&quot;
    &quot;fmt&quot;
    &quot;io/ioutil&quot;
    &quot;log&quot;
    &quot;net/http&quot;

    gke &quot;google.golang.org/api/container/v1&quot;
    &quot;google.golang.org/api/option&quot;

    &quot;golang.org/x/oauth2&quot;
    &quot;golang.org/x/oauth2/google&quot;
    metav1 &quot;k8s.io/apimachinery/pkg/apis/meta/v1&quot;
    &quot;k8s.io/client-go/kubernetes&quot;
    &quot;k8s.io/client-go/rest&quot;
    clientcmdapi &quot;k8s.io/client-go/tools/clientcmd/api&quot;
)

const (
    googleAuthPlugin = &quot;gcp&quot;
    projectID        = &quot;my_project&quot;
    clusterName      = &quot;my_cluster&quot;
    zone             = &quot;my_cluster_zone&quot;
    scope            = &quot;https://www.googleapis.com/auth/cloud-platform&quot;
)

type googleAuthProvider struct {
    tokenSource oauth2.TokenSource
}

// These funcitons are needed even if we don't utilize them
// So that googleAuthProvider is an rest.AuthProvider interface
func (g *googleAuthProvider) WrapTransport(rt http.RoundTripper) http.RoundTripper {
    return &amp;oauth2.Transport{
        Base:   rt,
        Source: g.tokenSource,
    }
}
func (g *googleAuthProvider) Login() error { return nil }


func main() {
    ctx := context.Background()

    // Extract a token from the JSON SA key
    data, err := ioutil.ReadFile(&quot;sa_key.json&quot;)
    if err != nil {
        panic(err)
    }
    creds, err := google.CredentialsFromJSON(ctx, data, scope)
    if err != nil {
        panic(err)
    }
    token, err := creds.TokenSource.Token()
    if err != nil {
        panic(err)
    }
    tokenSource := oauth2.StaticTokenSource(token)

    // Authenticate with the token
    // If it's nil use Google ADC
    if err := rest.RegisterAuthProviderPlugin(googleAuthPlugin,
        func(clusterAddress string, config map[string]string, persister rest.AuthProviderConfigPersister) (rest.AuthProvider, error) {
            var err error
            if tokenSource == nil {
                tokenSource, err = google.DefaultTokenSource(ctx, scope)
                if err != nil {
                    return nil, fmt.Errorf(&quot;failed to create google token source: %+v&quot;, err)
                }
            }
            return &amp;googleAuthProvider{tokenSource: tokenSource}, nil
        }); err != nil {
        log.Fatalf(&quot;Failed to register %s auth plugin: %v&quot;, googleAuthPlugin, err)
    }

    gkeClient, err := gke.NewService(ctx, option.WithTokenSource(tokenSource))
    if err != nil {
        panic(err)
    }

    clientset, err := getClientSet(ctx, gkeClient, projectID, org, env)
    if err != nil {
        panic(err)
    }

    // Demo to make sure it works
    pods, err := clientset.CoreV1().Pods(&quot;&quot;).List(ctx, metav1.ListOptions{})
    if err != nil {
        panic(err)
    }
    log.Printf(&quot;There are %d pods in the cluster&quot;, len(pods.Items))
    for _, pod := range pods.Items {
        fmt.Println(pod.Name)
    }
}

func getClientSet(ctx context.Context, client *gke.Service, projectID, name string) (*kubernetes.Clientset, error) {
    // Get cluster info
    cluster, err := client.Projects.Zones.Clusters.Get(projectID, zone, name).Context(ctx).Do()
    if err != nil {
        panic(err)
    }

    // Decode cluster CA certificate
    cert, err := base64.StdEncoding.DecodeString(cluster.MasterAuth.ClusterCaCertificate)
    if err != nil {
        return nil, err
    }

    // Build a config using the cluster info
    config := &amp;rest.Config{
        TLSClientConfig: rest.TLSClientConfig{
            CAData: cert,
        },
        Host:         &quot;https://&quot; + cluster.Endpoint,
        AuthProvider: &amp;clientcmdapi.AuthProviderConfig{Name: googleAuthPlugin},
    }

    return kubernetes.NewForConfig(config)
}
</code></pre>
