-
-
Save dragonsinth/aea365732b60da3adc928dc18fff56ed to your computer and use it in GitHub Desktop.
package main | |
import ( | |
"context" | |
"encoding/base64" | |
"flag" | |
"fmt" | |
"log" | |
container "google.golang.org/api/container/v1beta1" | |
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" | |
"k8s.io/client-go/kubernetes" | |
"k8s.io/client-go/tools/clientcmd" | |
"k8s.io/client-go/tools/clientcmd/api" | |
_ "k8s.io/cloud-provider-gcp/pkg/clientauthplugin/gcp" // register GCP auth provider | |
) | |
var fProjectId = flag.String("projectId", "", "specify a project id to examine") | |
func main() { | |
flag.Parse() | |
if *fProjectId == "" { | |
log.Fatal("must specific -projectId") | |
} | |
if err := run(context.Background(), *fProjectId); err != nil { | |
log.Fatal(err) | |
} | |
} | |
func run(ctx context.Context, projectId string) error { | |
kubeConfig, err := getK8sClusterConfigs(ctx, projectId) | |
if err != nil { | |
return err | |
} | |
// Just list all the namespaces found in the project to test the API. | |
for clusterName := range kubeConfig.Clusters { | |
cfg, err := clientcmd.NewNonInteractiveClientConfig(*kubeConfig, clusterName, &clientcmd.ConfigOverrides{CurrentContext: clusterName}, nil).ClientConfig() | |
if err != nil { | |
return fmt.Errorf("failed to create Kubernetes configuration cluster=%s: %w", clusterName, err) | |
} | |
k8s, err := kubernetes.NewForConfig(cfg) | |
if err != nil { | |
return fmt.Errorf("failed to create Kubernetes client cluster=%s: %w", clusterName, err) | |
} | |
ns, err := k8s.CoreV1().Namespaces().List(ctx, metav1.ListOptions{}) | |
if err != nil { | |
return fmt.Errorf("failed to list namespaces cluster=%s: %w", clusterName, err) | |
} | |
log.Printf("Namespaces found in cluster=%s", clusterName) | |
for _, item := range ns.Items { | |
log.Println(item.Name) | |
} | |
} | |
return nil | |
} | |
func getK8sClusterConfigs(ctx context.Context, projectId string) (*api.Config, error) { | |
svc, err := container.NewService(ctx) | |
if err != nil { | |
return nil, fmt.Errorf("container.NewService: %w", err) | |
} | |
// Basic config structure | |
ret := api.Config{ | |
APIVersion: "v1", | |
Kind: "Config", | |
Clusters: map[string]*api.Cluster{}, // Clusters is a map of referencable names to cluster configs | |
AuthInfos: map[string]*api.AuthInfo{}, // AuthInfos is a map of referencable names to user configs | |
Contexts: map[string]*api.Context{}, // Contexts is a map of referencable names to context configs | |
} | |
// Ask Google for a list of all kube clusters in the given project. | |
resp, err := svc.Projects.Zones.Clusters.List(projectId, "-").Context(ctx).Do() | |
if err != nil { | |
return nil, fmt.Errorf("clusters list project=%s: %w", projectId, err) | |
} | |
for _, f := range resp.Clusters { | |
name := fmt.Sprintf("gke_%s_%s_%s", projectId, f.Zone, f.Name) | |
cert, err := base64.StdEncoding.DecodeString(f.MasterAuth.ClusterCaCertificate) | |
if err != nil { | |
return nil, fmt.Errorf("invalid certificate cluster=%s cert=%s: %w", name, f.MasterAuth.ClusterCaCertificate, err) | |
} | |
// example: gke_my-project_us-central1-b_cluster-1 => https://XX.XX.XX.XX | |
ret.Clusters[name] = &api.Cluster{ | |
CertificateAuthorityData: cert, | |
Server: "https://" + f.Endpoint, | |
} | |
// Just reuse the context name as an auth name. | |
ret.Contexts[name] = &api.Context{ | |
Cluster: name, | |
AuthInfo: name, | |
} | |
// GCP specific configation; use cloud platform scope. | |
ret.AuthInfos[name] = &api.AuthInfo{ | |
AuthProvider: &api.AuthProviderConfig{ | |
Name: "gcp", | |
Config: map[string]string{ | |
"scopes": "https://www.googleapis.com/auth/cloud-platform", | |
}, | |
}, | |
} | |
} | |
return &ret, nil | |
} |
module github.com/dragonsinth/gcp-kube | |
go 1.21.6 | |
require ( | |
google.golang.org/api v0.63.0 | |
k8s.io/apimachinery v0.26.0 | |
k8s.io/client-go v0.26.0 | |
k8s.io/cloud-provider-gcp v0.0.0-20230119221216-bb1acae5826d | |
) | |
require ( | |
cloud.google.com/go v0.99.0 // indirect | |
github.com/davecgh/go-spew v1.1.1 // indirect | |
github.com/emicklei/go-restful/v3 v3.9.0 // indirect | |
github.com/go-logr/logr v1.2.3 // indirect | |
github.com/go-openapi/jsonpointer v0.19.5 // indirect | |
github.com/go-openapi/jsonreference v0.20.0 // indirect | |
github.com/go-openapi/swag v0.19.14 // indirect | |
github.com/gogo/protobuf v1.3.2 // indirect | |
github.com/golang/groupcache v0.0.0-20210331224755-41bb18bfe9da // indirect | |
github.com/golang/protobuf v1.5.2 // indirect | |
github.com/google/gnostic v0.5.7-v3refs // indirect | |
github.com/google/go-cmp v0.5.9 // indirect | |
github.com/google/gofuzz v1.1.0 // indirect | |
github.com/googleapis/gax-go/v2 v2.1.1 // indirect | |
github.com/imdario/mergo v0.3.11 // indirect | |
github.com/josharian/intern v1.0.0 // indirect | |
github.com/json-iterator/go v1.1.12 // indirect | |
github.com/mailru/easyjson v0.7.6 // indirect | |
github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd // indirect | |
github.com/modern-go/reflect2 v1.0.2 // indirect | |
github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822 // indirect | |
github.com/spf13/pflag v1.0.5 // indirect | |
go.opencensus.io v0.23.0 // indirect | |
golang.org/x/net v0.3.1-0.20221206200815-1e63c2f08a10 // indirect | |
golang.org/x/oauth2 v0.0.0-20220223155221-ee480838109b // indirect | |
golang.org/x/sys v0.3.0 // indirect | |
golang.org/x/term v0.3.0 // indirect | |
golang.org/x/text v0.5.0 // indirect | |
golang.org/x/time v0.0.0-20220210224613-90d013bbcef8 // indirect | |
google.golang.org/appengine v1.6.7 // indirect | |
google.golang.org/genproto v0.0.0-20220502173005-c8bf987b8c21 // indirect | |
google.golang.org/grpc v1.49.0 // indirect | |
google.golang.org/protobuf v1.28.1 // indirect | |
gopkg.in/inf.v0 v0.9.1 // indirect | |
gopkg.in/yaml.v2 v2.4.0 // indirect | |
gopkg.in/yaml.v3 v3.0.1 // indirect | |
k8s.io/api v0.26.0 // indirect | |
k8s.io/klog/v2 v2.80.1 // indirect | |
k8s.io/kube-openapi v0.0.0-20221012153701-172d655c2280 // indirect | |
k8s.io/utils v0.0.0-20221107191617-1a15be271d1d // indirect | |
sigs.k8s.io/json v0.0.0-20220713155537-f223a00ba0e2 // indirect | |
sigs.k8s.io/structured-merge-diff/v4 v4.2.3 // indirect | |
sigs.k8s.io/yaml v1.3.0 // indirect | |
) |
Interestingly, when I updated today I found I no longer needed the replace
in the go mod... I wonder if that means this could now be transformed into a tiny shared lib.
Yes, you are right, I didn't mention it earlier, the first step in the comment is no longer needed.
Is there a more updated version that is not using clientauthplugin
?
Per docs:
Client auth library is a copy of the gcp plugin library that existed in Client-Go until k8s 1.25. Going ahead, this library is not supported and is expected to be replaced by GKE-GCLOUD-AUTH-PLUGIN. The code here is kept as a reference, in case anyone needs to refer to it.
https://github.com/kubernetes/cloud-provider-gcp/tree/master/pkg/clientauthplugin
@Tang8330 feel free to hack on one, I'm stiil using the old package. According to the new docs:
You will need to install the
gke-gcloud-auth-plugin
binary on all systems wherekubectl
or Kubernetes custom clients are used.
I wanted a pure Go solution, whereas it looks like the new stuff requires an installed binary.
@dragonsinth I know :'(. I have it working by installing the binary, but it feels dirty.
Even it's working for 1.22.2 which is latest as of today. Glad that you added go.mod. Thanks.