Last active
August 1, 2024 13:47
-
-
Save dragonsinth/aea365732b60da3adc928dc18fff56ed to your computer and use it in GitHub Desktop.
Connect to Google Kubernetes with GCP credentials and pure Golang
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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 | |
} |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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 | |
) |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
@Tang8330 feel free to hack on one, I'm stiil using the old package. According to the new docs:
I wanted a pure Go solution, whereas it looks like the new stuff requires an installed binary.