├── .gitignore ├── .goreleaser.yaml ├── .github ├── dependabot.yaml └── workflows │ ├── release.yaml │ ├── using-gcloud.yaml │ └── test-action.yaml ├── go.mod ├── setup.txt ├── action.yaml ├── README.md ├── main.go ├── LICENSE └── go.sum /.gitignore: -------------------------------------------------------------------------------- 1 | 2 | dist/ 3 | 4 | gke-auth 5 | -------------------------------------------------------------------------------- /.goreleaser.yaml: -------------------------------------------------------------------------------- 1 | version: 2 2 | builds: 3 | - goos: 4 | - linux 5 | - windows 6 | - darwin 7 | goarch: 8 | - amd64 9 | - arm64 10 | archives: 11 | - name_template: gke-auth_{{ .Version }}_{{ if eq .Os "linux"}}Linux{{ else }}{{ .Os }}{{ end }}_{{- if eq .Arch "amd64" }}x86_64{{ else }}{{ .Arch }}{{ end }} 12 | checksum: 13 | name_template: 'checksums.txt' 14 | -------------------------------------------------------------------------------- /.github/dependabot.yaml: -------------------------------------------------------------------------------- 1 | # Copyright 2024 Chainguard, Inc. 2 | # SPDX-License-Identifier: Apache-2.0 3 | 4 | version: 2 5 | updates: 6 | - package-ecosystem: "gomod" 7 | directories: 8 | - "/" 9 | schedule: 10 | interval: "daily" 11 | open-pull-requests-limit: 5 12 | groups: 13 | all: 14 | patterns: 15 | - "*" 16 | update-types: 17 | - "minor" 18 | - "patch" 19 | 20 | - package-ecosystem: "github-actions" 21 | directories: 22 | - "/" 23 | schedule: 24 | interval: "daily" 25 | open-pull-requests-limit: 5 26 | groups: 27 | all: 28 | update-types: 29 | - "minor" 30 | - "patch" 31 | -------------------------------------------------------------------------------- /.github/workflows/release.yaml: -------------------------------------------------------------------------------- 1 | name: goreleaser 2 | 3 | on: 4 | push: 5 | tags: 6 | - '*' 7 | 8 | permissions: 9 | contents: write 10 | 11 | jobs: 12 | goreleaser: 13 | if: startsWith(github.ref, 'refs/tags/') 14 | runs-on: ubuntu-latest 15 | steps: 16 | - uses: actions/checkout@692973e3d937129bcbf40652eb9f2f61becf3332 # v4.1.7 17 | with: 18 | fetch-depth: 0 19 | - run: git fetch --force --tags 20 | 21 | - uses: actions/setup-go@0a12ed9d6a96ab950c8f026ed9f722fe0da7ef32 # v5.0.2 22 | with: 23 | go-version: 'stable' 24 | - uses: goreleaser/goreleaser-action@286f3b13b1b49da4ac219696163fb8c1c93e1200 # v6.0.0 25 | with: 26 | version: latest 27 | args: release --clean 28 | env: 29 | GITHUB_TOKEN: ${{ github.token }} 30 | -------------------------------------------------------------------------------- /.github/workflows/using-gcloud.yaml: -------------------------------------------------------------------------------- 1 | name: gcloud 2 | 3 | on: 4 | push: 5 | branches: ['main'] 6 | workflow_dispatch: 7 | 8 | permissions: 9 | id-token: write 10 | contents: read 11 | 12 | jobs: 13 | gcloud: 14 | runs-on: ubuntu-latest 15 | steps: 16 | - uses: actions/checkout@692973e3d937129bcbf40652eb9f2f61becf3332 # v4.1.7 17 | - uses: azure/setup-kubectl@3e0aec4d80787158d308d7b364cb1b702e7feb7f # v4.0.0 18 | 19 | - uses: google-github-actions/auth@09cecabe1f169596b81c2ef22b40faff87acc460 # v0.9.0 20 | with: 21 | workload_identity_provider: 'projects/30098225237/locations/global/workloadIdentityPools/gha-pool/providers/gha-provider' 22 | service_account: 'gha-sa@imjasonh-autopilot.iam.gserviceaccount.com' 23 | 24 | - uses: google-github-actions/setup-gcloud@98ddc00a17442e89a24bbf282954a3b65ce6d200 # v2.1.0 25 | with: 26 | project_id: imjasonh-autopilot 27 | install_components: gke-gcloud-auth-plugin 28 | - run: | 29 | gcloud container clusters get-credentials autopilot \ 30 | --region us-east1 31 | 32 | - run: kubectl get pods 33 | 34 | - run: gcloud auth configure-docker us-east1-docker.pkg.dev 35 | - run: crane catalog us-east1-docker.pkg.dev 36 | -------------------------------------------------------------------------------- /.github/workflows/test-action.yaml: -------------------------------------------------------------------------------- 1 | name: Test Action 2 | 3 | on: 4 | push: 5 | branches: ['main'] 6 | workflow_dispatch: 7 | 8 | permissions: 9 | id-token: write 10 | contents: read 11 | 12 | jobs: 13 | test-action: 14 | runs-on: ubuntu-latest 15 | strategy: 16 | matrix: 17 | version: ['v0.1.0', 'latest-release', 'tip'] 18 | fail-fast: false 19 | steps: 20 | - uses: actions/checkout@692973e3d937129bcbf40652eb9f2f61becf3332 # v4.1.7 21 | - uses: actions/setup-go@0a12ed9d6a96ab950c8f026ed9f722fe0da7ef32 # v5.0.2 22 | with: 23 | go-version-file: './go.mod' 24 | - uses: azure/setup-kubectl@3e0aec4d80787158d308d7b364cb1b702e7feb7f # v4.0.0 25 | 26 | - uses: 'google-github-actions/auth@v2' 27 | with: 28 | workload_identity_provider: 'projects/30098225237/locations/global/workloadIdentityPools/gha-pool/providers/gha-provider' 29 | service_account: 'gha-sa@imjasonh-autopilot.iam.gserviceaccount.com' 30 | 31 | - uses: imjasonh/gke-auth@main 32 | with: 33 | version: ${{ matrix.version }} 34 | project: imjasonh-autopilot 35 | location: us-east1 36 | cluster: autopilot 37 | registry_location: us-east1 38 | - run: kubectl get pods 39 | 40 | - uses: imjasonh/setup-crane@main 41 | - run: crane catalog us-east1-docker.pkg.dev 42 | 43 | -------------------------------------------------------------------------------- /go.mod: -------------------------------------------------------------------------------- 1 | module github.com/imjasonh/gke-auth 2 | 3 | go 1.22.0 4 | 5 | toolchain go1.22.3 6 | 7 | require ( 8 | github.com/docker/cli v28.0.1+incompatible 9 | golang.org/x/oauth2 v0.21.0 10 | k8s.io/apimachinery v0.30.2 11 | k8s.io/client-go v0.30.2 12 | ) 13 | 14 | require ( 15 | cloud.google.com/go/compute/metadata v0.3.0 // indirect 16 | github.com/davecgh/go-spew v1.1.1 // indirect 17 | github.com/docker/docker-credential-helpers v0.9.3 // indirect 18 | github.com/go-logr/logr v1.4.1 // indirect 19 | github.com/gogo/protobuf v1.3.2 // indirect 20 | github.com/google/gofuzz v1.2.0 // indirect 21 | github.com/imdario/mergo v0.3.6 // indirect 22 | github.com/json-iterator/go v1.1.12 // indirect 23 | github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd // indirect 24 | github.com/modern-go/reflect2 v1.0.2 // indirect 25 | github.com/pkg/errors v0.9.1 // indirect 26 | github.com/sirupsen/logrus v1.9.3 // indirect 27 | github.com/spf13/pflag v1.0.5 // indirect 28 | golang.org/x/net v0.25.0 // indirect 29 | golang.org/x/sys v0.20.0 // indirect 30 | golang.org/x/term v0.20.0 // indirect 31 | golang.org/x/text v0.15.0 // indirect 32 | golang.org/x/time v0.5.0 // indirect 33 | google.golang.org/protobuf v1.34.1 // indirect 34 | gopkg.in/inf.v0 v0.9.1 // indirect 35 | gopkg.in/yaml.v2 v2.4.0 // indirect 36 | gotest.tools/v3 v3.5.2 // indirect 37 | k8s.io/klog/v2 v2.120.1 // indirect 38 | k8s.io/utils v0.0.0-20230726121419-3b25d923346b // indirect 39 | sigs.k8s.io/json v0.0.0-20221116044647-bc3834ca7abd // indirect 40 | sigs.k8s.io/structured-merge-diff/v4 v4.4.1 // indirect 41 | sigs.k8s.io/yaml v1.3.0 // indirect 42 | ) 43 | -------------------------------------------------------------------------------- /setup.txt: -------------------------------------------------------------------------------- 1 | Notes based on https://github.com/google-github-actions/auth#setting-up-workload-identity-federation 2 | 3 | 4 | PROJECT_ID=imjasonh-autopilot 5 | 6 | gcloud config set project ${PROJECT_ID} 7 | 8 | gcloud services enable container.googleapis.com 9 | gcloud container clusters create-auto autopilot --region=us-east1 10 | 11 | gcloud iam service-accounts create gha-sa 12 | 13 | gcloud projects add-iam-policy-binding \ 14 | imjasonh-autopilot \ 15 | --member=serviceAccount:gha-sa@imjasonh-autopilot.iam.gserviceaccount.com \ 16 | --role=roles/container.developer 17 | 18 | gcloud services enable iamcredentials.googleapis.com 19 | gcloud iam workload-identity-pools create "gha-pool" \ 20 | --location="global" \ 21 | --display-name="GHA pool" 22 | fullid=$(gcloud iam workload-identity-pools describe "gha-pool" \ 23 | --location="global" \ 24 | --format="value(name)") 25 | export WORKLOAD_IDENTITY_POOL_ID=${fullid} 26 | gcloud iam workload-identity-pools providers create-oidc "gha-provider" \ 27 | --location="global" \ 28 | --workload-identity-pool="gha-pool" \ 29 | --display-name="GHA provider" \ 30 | --attribute-mapping="google.subject=assertion.sub,attribute.actor=assertion.actor,attribute.repository=assertion.repository" \ 31 | --issuer-uri="https://token.actions.githubusercontent.com" 32 | 33 | export REPO="imjasonh/gke-auth" 34 | gcloud iam service-accounts add-iam-policy-binding "gha-sa@${PROJECT_ID}.iam.gserviceaccount.com" \ 35 | --role="roles/iam.workloadIdentityUser" \ 36 | --member="principalSet://iam.googleapis.com/${WORKLOAD_IDENTITY_POOL_ID}/attribute.repository/${REPO}" 37 | 38 | 39 | echo "WORKLOAD IDENTITY PROVIDER:" 40 | gcloud iam workload-identity-pools providers describe "gha-provider" \ 41 | --project="${PROJECT_ID}" \ 42 | --location="global" \ 43 | --workload-identity-pool="gha-pool" \ 44 | --format="value(name)" 45 | -------------------------------------------------------------------------------- /action.yaml: -------------------------------------------------------------------------------- 1 | name: 'Setup GKE Auth' 2 | description: 'Authorize to a GKE cluster' 3 | branding: 4 | icon: cloud-lightning 5 | color: blue 6 | inputs: 7 | version: 8 | description: 'Version of gke-auth to install (tip, latest-release, v0.1, etc.)' 9 | required: true 10 | default: 'latest-release' 11 | project: 12 | description: "GCP project" 13 | required: true 14 | location: 15 | description: "Region or zone of the cluster" 16 | required: true 17 | cluster: 18 | description: "Name of the cluster" 19 | required: true 20 | registry_location: 21 | description: "Region or multi-region of the Artifact Registry instance" 22 | required: false 23 | default: "" 24 | runs: 25 | using: "composite" 26 | steps: 27 | - shell: bash 28 | run: | 29 | set -ex 30 | 31 | # Install gke-auth: 32 | # - if version is "tip", `go install` from tip of main. 33 | # - if version is "latest-release", look up latest release. 34 | # - otherwise, install the specified version. 35 | case ${{ inputs.version }} in 36 | tip) 37 | echo "Installing gke-auth using go install" 38 | go install github.com/imjasonh/gke-auth@main 39 | ;; 40 | latest-release) 41 | tag=$(curl -s -u "username:${{ github.token }}" https://api.github.com/repos/imjasonh/gke-auth/releases/latest | jq -r '.tag_name') 42 | ;; 43 | *) 44 | tag="${{ inputs.version }}" 45 | esac 46 | 47 | if [[ ! -z ${tag} ]]; then 48 | echo "Installing gke-auth @ ${tag}" 49 | curl -fsL https://github.com/imjasonh/gke-auth/releases/download/${tag}/gke-auth_${tag:1}_Linux_x86_64.tar.gz | sudo tar xzf - -C /usr/local/bin gke-auth 50 | fi 51 | 52 | if [[ "${{ inputs.registry_location }}" != "" ]]; then 53 | gke-auth --location=${{ inputs.registry_location }} --configure-docker 54 | fi 55 | 56 | gke-auth --project=${{ inputs.project }} \ 57 | --location=${{ inputs.location }} \ 58 | --cluster=${{ inputs.cluster }} 59 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Auth to GKE and Artifact Registry without `gcloud` 2 | 3 | ### Installation 4 | 5 | ``` 6 | go install github.com/imjasonh/gke-auth@latest 7 | ``` 8 | 9 | ### Use 10 | 11 | Once you've installed the Go binary, run it: 12 | 13 | ``` 14 | gke-auth --project=[MY_PROJECT] \ 15 | --location=[REGION_OR_ZONE] \ 16 | --cluster=[CLUSTER_NAME] 17 | ``` 18 | 19 | Now you have auth and kubeconfigs set up to use the cluster. 20 | 21 | Or, using GitHub Actions: 22 | 23 | ```yaml 24 | - uses: imjasonh/gke-auth@v0.1.0 25 | with: 26 | project: [MY_PROJECT] 27 | location: [REGION_OR_ZONE] 28 | cluster: [CLUSTER_NAME] 29 | ``` 30 | 31 | :bulb: Protip: You probably want to [set up Workload Identity](https://github.com/google-github-actions/auth#usage) between your GitHub Actions workflow and your GCP project. 32 | 33 | Test it with: 34 | 35 | ``` 36 | kubectl get pods 37 | ``` 38 | 39 | ### Artifact Registry 40 | 41 | To use `gke-auth` as a Docker credential helper for Artifact Registry, run: 42 | 43 | ``` 44 | gke-auth --configure-docker --location=[REGION] 45 | ``` 46 | 47 | This will set up a Docker credential helper for interacting with `[REGION]-docker.pkg.dev`. 48 | 49 | This is similar to [`docker-credential-gcr`](https://github.com/GoogleCloudPlatform/docker-credential-gcr) except much simpler. 50 | 51 | This can also be configured with the GitHub Action: 52 | 53 | ```yaml 54 | uses: imjasonh/gke-auth@XYZ 55 | with: 56 | location: us-central1-a 57 | registry_location: us-central1 58 | ``` 59 | 60 | ### Why? 61 | 62 | `gcloud` is great. 63 | It's like a Swiss army knife for the cloud, if a knife could do anything to a cloud. 64 | 65 | It does so much. 66 | _It does soooo much!_ 67 | 68 | Too much. 69 | 70 | This leads it to be really huge. 71 | Hundreds of megabytes of sweet delicious Python. 72 | Python that has to be interpreted before it can even start running anything. 73 | 74 | If you're downloading and installing and running `gcloud` just to execute `gcloud container clusters get-credentials` so you can switch to using `kubectl` -- _especially_ in a CI environment -- you're wasting a lot of time. Same with `gcloud auth configure-docker` for Artifact Registry. 75 | 76 | Installing `gcloud` can take _minutes_, compared to just a few seconds with `gke-auth`, even if you have to build it from source. 77 | 78 | ### `gke-gcloud-auth-plugin` 79 | 80 | `gcloud` itself includes a K8s auth plugin very similar to `gke-auth`, called [`gke-gcloud-auth-plugin`](https://github.com/kubernetes/cloud-provider-gcp/tree/master/cmd/gke-gcloud-auth-plugin). 81 | 82 | For more information about this plugin, see this [GCP blog post](https://cloud.google.com/blog/products/containers-kubernetes/kubectl-auth-changes-in-gke). 83 | 84 | Like `gke-auth`, this plugin can be configured to be used by `kubectl` and `client-go` to get auth credentials. 85 | 86 | Unlike `gke-auth`, the plugin is installed using `gcloud components add gke-gcloud-auth-plugin`, and configured to be used with `gcloud container get-credentials`, so while it's still better than having `kubectl` invoke `gcloud` every time it needs new credentials, it still seems to mostly require `gcloud` to install and use it, at least as recommended in documentation. 87 | 88 | `gke-auth` should be more or less equivalent to `gke-gcloud-auth-plugin` in core functionality, but `gke-auth` doesn't need or recommend `gcloud` at all to install or configure it. 89 | -------------------------------------------------------------------------------- /main.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "context" 5 | "encoding/base64" 6 | "encoding/json" 7 | "flag" 8 | "fmt" 9 | "io" 10 | "log" 11 | "net/http" 12 | "os" 13 | "os/exec" 14 | "path/filepath" 15 | "strings" 16 | 17 | "github.com/docker/cli/cli/config" 18 | "golang.org/x/oauth2/google" 19 | metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" 20 | clientauthv1 "k8s.io/client-go/pkg/apis/clientauthentication/v1" 21 | "k8s.io/client-go/tools/clientcmd" 22 | "k8s.io/client-go/tools/clientcmd/api" 23 | ) 24 | 25 | var ( 26 | project = flag.String("project", "", "Name of the project") 27 | location = flag.String("location", "", "Location of the cluster") 28 | clusterName = flag.String("cluster", "", "Name of the cluster") 29 | 30 | get = flag.Bool("get", false, "If true, print auth information") 31 | clear = flag.Bool("clear", false, "If true, clear auth for this cluster") 32 | configureDocker = flag.Bool("configure-docker", false, "If true, configure docker to use this token") 33 | ) 34 | 35 | func main() { 36 | flag.Parse() 37 | ctx := context.Background() 38 | 39 | if *get && *clear { 40 | log.Fatal("cannot pass both --get and --clear") 41 | } 42 | if (*get || *clear) && *configureDocker { 43 | log.Fatal("cannot pass --get or --clear with --configure-docker") 44 | } 45 | 46 | if *configureDocker { 47 | if *location == "" { 48 | log.Fatal("must pass --location when using --configure-docker") 49 | } 50 | cfg, err := config.Load(config.Dir()) 51 | if err != nil { 52 | log.Fatalf("Loading docker config: %v", err) 53 | } 54 | if cfg.CredentialHelpers == nil { 55 | cfg.CredentialHelpers = map[string]string{} 56 | } 57 | host := fmt.Sprintf("%s-docker.pkg.dev", *location) 58 | cfg.CredentialHelpers[host] = "gke-auth" 59 | path, err := exec.LookPath(os.Args[0]) 60 | if err != nil { 61 | log.Fatalf("Looking up path: %v", err) 62 | } 63 | sl := filepath.Dir(path) + "/docker-credential-gke-auth" 64 | if err := os.Remove(sl); err != nil && !os.IsNotExist(err) { 65 | log.Fatalf("Removing existing symlink: %v", err) 66 | } 67 | if err := os.Symlink(path, filepath.Dir(path)+"/docker-credential-gke-auth"); err != nil { 68 | log.Fatalf("Symlinking: %v", err) 69 | } 70 | if err := cfg.Save(); err != nil { 71 | log.Fatalf("Saving docker config: %v", err) 72 | } 73 | log.Printf("Docker configured to use gke-auth for %q in %q", host, *location) 74 | return 75 | } 76 | 77 | // get a token 78 | scopes := []string{ 79 | // Base scope for GCP auth 80 | "https://www.googleapis.com/auth/cloud-platform", 81 | // Needed in order to use service account emails instead of unique IDs in K8S RBAC. 82 | "https://www.googleapis.com/auth/userinfo.email", 83 | } 84 | ts, err := google.DefaultTokenSource(ctx, scopes...) 85 | if err != nil { 86 | log.Fatalf("google.DefaultTokenSource: %v", err) 87 | } 88 | tok, err := ts.Token() 89 | if err != nil { 90 | log.Fatalf("ts.Token: %v", err) 91 | } 92 | 93 | if strings.HasSuffix(os.Args[0], "docker-credential-gke-auth") { 94 | urlb, err := io.ReadAll(io.LimitReader(os.Stdin, 1000)) 95 | if err != nil { 96 | log.Fatalf("Reading stdin: %v", err) 97 | } 98 | 99 | if err := json.NewEncoder(os.Stdout).Encode(&struct { 100 | ServerURL string `json:"ServerURL"` 101 | Username string `json:"Username"` 102 | Secret string `json:"Secret"` 103 | }{ 104 | ServerURL: string(urlb), 105 | Username: "oauth2accesstoken", 106 | Secret: tok.AccessToken, 107 | }); err != nil { 108 | log.Fatalf("Encoding JSON: %v", err) 109 | } 110 | return 111 | } 112 | 113 | if !*get && (*project == "" || *location == "" || *clusterName == "") { 114 | log.Fatal("must pass --project and --location and --cluster") 115 | } 116 | 117 | if *get { 118 | // just print the token 119 | if err := json.NewEncoder(os.Stdout).Encode(&clientauthv1.ExecCredential{ 120 | TypeMeta: metav1.TypeMeta{ 121 | APIVersion: "client.authentication.k8s.io/v1", 122 | Kind: "ExecCredential", 123 | }, 124 | Status: &clientauthv1.ExecCredentialStatus{ 125 | ExpirationTimestamp: &metav1.Time{Time: tok.Expiry}, 126 | Token: tok.AccessToken, 127 | }, 128 | }); err != nil { 129 | log.Fatalf("Encoding JSON: %v", err) 130 | } 131 | return 132 | } 133 | 134 | url := fmt.Sprintf("https://container.googleapis.com/v1/projects/%s/locations/%s/clusters/%s", *project, *location, *clusterName) 135 | req, err := http.NewRequest(http.MethodGet, url, nil) 136 | if err != nil { 137 | log.Fatalf("http.NewRequest: %v", err) 138 | } 139 | tok.SetAuthHeader(req) 140 | resp, err := http.DefaultClient.Do(req) 141 | if err != nil { 142 | log.Fatalf("http.Do: %v", err) 143 | } 144 | defer resp.Body.Close() 145 | if resp.StatusCode != http.StatusOK { 146 | all, _ := io.ReadAll(resp.Body) 147 | log.Fatalf("http.Do: %d %s %s", resp.StatusCode, resp.Status, string(all)) 148 | } 149 | var cluster struct { 150 | Endpoint string 151 | MasterAuth struct { 152 | ClusterCaCertificate string 153 | } 154 | } 155 | if err := json.NewDecoder(resp.Body).Decode(&cluster); err != nil { 156 | log.Fatalf("json.Decode: %v", err) 157 | } 158 | 159 | cfg, err := clientcmd.NewDefaultClientConfigLoadingRules().Load() 160 | if err != nil { 161 | log.Fatalf("Loading kubeconfig %v", err) 162 | } 163 | 164 | // get kubeconfig location 165 | key := fmt.Sprintf("gke_%s_%s_%s", *project, *location, *clusterName) 166 | kcfgPath := clientcmd.RecommendedHomeFile 167 | if auth := cfg.AuthInfos[key]; auth != nil && auth.LocationOfOrigin != "" { 168 | kcfgPath = auth.LocationOfOrigin 169 | } 170 | 171 | // add user 172 | if *clear { 173 | cfg.AuthInfos[key] = &api.AuthInfo{} 174 | cfg.Clusters[key] = &api.Cluster{} 175 | cfg.Contexts[key] = &api.Context{} 176 | cfg.CurrentContext = "" 177 | log.Println("Auth config cleared") 178 | } else { 179 | cfg.AuthInfos[key] = &api.AuthInfo{ 180 | Exec: &api.ExecConfig{ 181 | APIVersion: "client.authentication.k8s.io/v1", 182 | Command: os.Args[0], 183 | Args: []string{"--get"}, 184 | InteractiveMode: api.NeverExecInteractiveMode, 185 | InstallHint: "go install github.com/imjasonh/gke-auto@latest", 186 | }, 187 | } 188 | 189 | // add cluster 190 | dec, err := base64.StdEncoding.DecodeString(cluster.MasterAuth.ClusterCaCertificate) 191 | if err != nil { 192 | log.Fatalf("Decoding CA cert: %v", err) 193 | } 194 | cfg.Clusters[key] = &api.Cluster{ 195 | Server: "https://" + cluster.Endpoint, 196 | CertificateAuthorityData: dec, 197 | } 198 | 199 | // update current context 200 | cfg.Contexts[key] = &api.Context{ 201 | AuthInfo: key, 202 | Cluster: key, 203 | } 204 | cfg.CurrentContext = key 205 | } 206 | 207 | // write the file back 208 | if err := clientcmd.WriteToFile(*cfg, kcfgPath); err != nil { 209 | log.Fatalf("Writing kubeconfig %q: %v", kcfgPath, err) 210 | } 211 | } 212 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | 2 | Apache License 3 | Version 2.0, January 2004 4 | http://www.apache.org/licenses/ 5 | 6 | TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION 7 | 8 | 1. Definitions. 9 | 10 | "License" shall mean the terms and conditions for use, reproduction, 11 | and distribution as defined by Sections 1 through 9 of this document. 12 | 13 | "Licensor" shall mean the copyright owner or entity authorized by 14 | the copyright owner that is granting the License. 15 | 16 | "Legal Entity" shall mean the union of the acting entity and all 17 | other entities that control, are controlled by, or are under common 18 | control with that entity. For the purposes of this definition, 19 | "control" means (i) the power, direct or indirect, to cause the 20 | direction or management of such entity, whether by contract or 21 | otherwise, or (ii) ownership of fifty percent (50%) or more of the 22 | outstanding shares, or (iii) beneficial ownership of such entity. 23 | 24 | "You" (or "Your") shall mean an individual or Legal Entity 25 | exercising permissions granted by this License. 26 | 27 | "Source" form shall mean the preferred form for making modifications, 28 | including but not limited to software source code, documentation 29 | source, and configuration files. 30 | 31 | "Object" form shall mean any form resulting from mechanical 32 | transformation or translation of a Source form, including but 33 | not limited to compiled object code, generated documentation, 34 | and conversions to other media types. 35 | 36 | "Work" shall mean the work of authorship, whether in Source or 37 | Object form, made available under the License, as indicated by a 38 | copyright notice that is included in or attached to the work 39 | (an example is provided in the Appendix below). 40 | 41 | "Derivative Works" shall mean any work, whether in Source or Object 42 | form, that is based on (or derived from) the Work and for which the 43 | editorial revisions, annotations, elaborations, or other modifications 44 | represent, as a whole, an original work of authorship. For the purposes 45 | of this License, Derivative Works shall not include works that remain 46 | separable from, or merely link (or bind by name) to the interfaces of, 47 | the Work and Derivative Works thereof. 48 | 49 | "Contribution" shall mean any work of authorship, including 50 | the original version of the Work and any modifications or additions 51 | to that Work or Derivative Works thereof, that is intentionally 52 | submitted to Licensor for inclusion in the Work by the copyright owner 53 | or by an individual or Legal Entity authorized to submit on behalf of 54 | the copyright owner. For the purposes of this definition, "submitted" 55 | means any form of electronic, verbal, or written communication sent 56 | to the Licensor or its representatives, including but not limited to 57 | communication on electronic mailing lists, source code control systems, 58 | and issue tracking systems that are managed by, or on behalf of, the 59 | Licensor for the purpose of discussing and improving the Work, but 60 | excluding communication that is conspicuously marked or otherwise 61 | designated in writing by the copyright owner as "Not a Contribution." 62 | 63 | "Contributor" shall mean Licensor and any individual or Legal Entity 64 | on behalf of whom a Contribution has been received by Licensor and 65 | subsequently incorporated within the Work. 66 | 67 | 2. Grant of Copyright License. Subject to the terms and conditions of 68 | this License, each Contributor hereby grants to You a perpetual, 69 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable 70 | copyright license to reproduce, prepare Derivative Works of, 71 | publicly display, publicly perform, sublicense, and distribute the 72 | Work and such Derivative Works in Source or Object form. 73 | 74 | 3. Grant of Patent License. Subject to the terms and conditions of 75 | this License, each Contributor hereby grants to You a perpetual, 76 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable 77 | (except as stated in this section) patent license to make, have made, 78 | use, offer to sell, sell, import, and otherwise transfer the Work, 79 | where such license applies only to those patent claims licensable 80 | by such Contributor that are necessarily infringed by their 81 | Contribution(s) alone or by combination of their Contribution(s) 82 | with the Work to which such Contribution(s) was submitted. If You 83 | institute patent litigation against any entity (including a 84 | cross-claim or counterclaim in a lawsuit) alleging that the Work 85 | or a Contribution incorporated within the Work constitutes direct 86 | or contributory patent infringement, then any patent licenses 87 | granted to You under this License for that Work shall terminate 88 | as of the date such litigation is filed. 89 | 90 | 4. Redistribution. You may reproduce and distribute copies of the 91 | Work or Derivative Works thereof in any medium, with or without 92 | modifications, and in Source or Object form, provided that You 93 | meet the following conditions: 94 | 95 | (a) You must give any other recipients of the Work or 96 | Derivative Works a copy of this License; and 97 | 98 | (b) You must cause any modified files to carry prominent notices 99 | stating that You changed the files; and 100 | 101 | (c) You must retain, in the Source form of any Derivative Works 102 | that You distribute, all copyright, patent, trademark, and 103 | attribution notices from the Source form of the Work, 104 | excluding those notices that do not pertain to any part of 105 | the Derivative Works; and 106 | 107 | (d) If the Work includes a "NOTICE" text file as part of its 108 | distribution, then any Derivative Works that You distribute must 109 | include a readable copy of the attribution notices contained 110 | within such NOTICE file, excluding those notices that do not 111 | pertain to any part of the Derivative Works, in at least one 112 | of the following places: within a NOTICE text file distributed 113 | as part of the Derivative Works; within the Source form or 114 | documentation, if provided along with the Derivative Works; or, 115 | within a display generated by the Derivative Works, if and 116 | wherever such third-party notices normally appear. The contents 117 | of the NOTICE file are for informational purposes only and 118 | do not modify the License. You may add Your own attribution 119 | notices within Derivative Works that You distribute, alongside 120 | or as an addendum to the NOTICE text from the Work, provided 121 | that such additional attribution notices cannot be construed 122 | as modifying the License. 123 | 124 | You may add Your own copyright statement to Your modifications and 125 | may provide additional or different license terms and conditions 126 | for use, reproduction, or distribution of Your modifications, or 127 | for any such Derivative Works as a whole, provided Your use, 128 | reproduction, and distribution of the Work otherwise complies with 129 | the conditions stated in this License. 130 | 131 | 5. Submission of Contributions. Unless You explicitly state otherwise, 132 | any Contribution intentionally submitted for inclusion in the Work 133 | by You to the Licensor shall be under the terms and conditions of 134 | this License, without any additional terms or conditions. 135 | Notwithstanding the above, nothing herein shall supersede or modify 136 | the terms of any separate license agreement you may have executed 137 | with Licensor regarding such Contributions. 138 | 139 | 6. Trademarks. This License does not grant permission to use the trade 140 | names, trademarks, service marks, or product names of the Licensor, 141 | except as required for reasonable and customary use in describing the 142 | origin of the Work and reproducing the content of the NOTICE file. 143 | 144 | 7. Disclaimer of Warranty. Unless required by applicable law or 145 | agreed to in writing, Licensor provides the Work (and each 146 | Contributor provides its Contributions) on an "AS IS" BASIS, 147 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or 148 | implied, including, without limitation, any warranties or conditions 149 | of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A 150 | PARTICULAR PURPOSE. You are solely responsible for determining the 151 | appropriateness of using or redistributing the Work and assume any 152 | risks associated with Your exercise of permissions under this License. 153 | 154 | 8. Limitation of Liability. In no event and under no legal theory, 155 | whether in tort (including negligence), contract, or otherwise, 156 | unless required by applicable law (such as deliberate and grossly 157 | negligent acts) or agreed to in writing, shall any Contributor be 158 | liable to You for damages, including any direct, indirect, special, 159 | incidental, or consequential damages of any character arising as a 160 | result of this License or out of the use or inability to use the 161 | Work (including but not limited to damages for loss of goodwill, 162 | work stoppage, computer failure or malfunction, or any and all 163 | other commercial damages or losses), even if such Contributor 164 | has been advised of the possibility of such damages. 165 | 166 | 9. Accepting Warranty or Additional Liability. While redistributing 167 | the Work or Derivative Works thereof, You may choose to offer, 168 | and charge a fee for, acceptance of support, warranty, indemnity, 169 | or other liability obligations and/or rights consistent with this 170 | License. However, in accepting such obligations, You may act only 171 | on Your own behalf and on Your sole responsibility, not on behalf 172 | of any other Contributor, and only if You agree to indemnify, 173 | defend, and hold each Contributor harmless for any liability 174 | incurred by, or claims asserted against, such Contributor by reason 175 | of your accepting any such warranty or additional liability. 176 | 177 | END OF TERMS AND CONDITIONS 178 | 179 | APPENDIX: How to apply the Apache License to your work. 180 | 181 | To apply the Apache License to your work, attach the following 182 | boilerplate notice, with the fields enclosed by brackets "[]" 183 | replaced with your own identifying information. (Don't include 184 | the brackets!) The text should be enclosed in the appropriate 185 | comment syntax for the file format. We also recommend that a 186 | file or class name and description of purpose be included on the 187 | same "printed page" as the copyright notice for easier 188 | identification within third-party archives. 189 | 190 | Copyright [yyyy] [name of copyright owner] 191 | 192 | Licensed under the Apache License, Version 2.0 (the "License"); 193 | you may not use this file except in compliance with the License. 194 | You may obtain a copy of the License at 195 | 196 | http://www.apache.org/licenses/LICENSE-2.0 197 | 198 | Unless required by applicable law or agreed to in writing, software 199 | distributed under the License is distributed on an "AS IS" BASIS, 200 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 201 | See the License for the specific language governing permissions and 202 | limitations under the License. 203 | -------------------------------------------------------------------------------- /go.sum: -------------------------------------------------------------------------------- 1 | cloud.google.com/go/compute/metadata v0.3.0 h1:Tz+eQXMEqDIKRsmY3cHTL6FVaynIjX2QxYC4trgAKZc= 2 | cloud.google.com/go/compute/metadata v0.3.0/go.mod h1:zFmK7XCadkQkj6TtorcaGlCW1hT1fIilQDwofLpJ20k= 3 | github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= 4 | github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= 5 | github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= 6 | github.com/docker/cli v28.0.1+incompatible h1:g0h5NQNda3/CxIsaZfH4Tyf6vpxFth7PYl3hgCPOKzs= 7 | github.com/docker/cli v28.0.1+incompatible/go.mod h1:JLrzqnKDaYBop7H2jaqPtU4hHvMKP+vjCwu2uszcLI8= 8 | github.com/docker/docker-credential-helpers v0.9.3 h1:gAm/VtF9wgqJMoxzT3Gj5p4AqIjCBS4wrsOh9yRqcz8= 9 | github.com/docker/docker-credential-helpers v0.9.3/go.mod h1:x+4Gbw9aGmChi3qTLZj8Dfn0TD20M/fuWy0E5+WDeCo= 10 | github.com/emicklei/go-restful/v3 v3.11.0 h1:rAQeMHw1c7zTmncogyy8VvRZwtkmkZ4FxERmMY4rD+g= 11 | github.com/emicklei/go-restful/v3 v3.11.0/go.mod h1:6n3XBCmQQb25CM2LCACGz8ukIrRry+4bhvbpWn3mrbc= 12 | github.com/go-logr/logr v1.4.1 h1:pKouT5E8xu9zeFC39JXRDukb6JFQPXM5p5I91188VAQ= 13 | github.com/go-logr/logr v1.4.1/go.mod h1:9T104GzyrTigFIr8wt5mBrctHMim0Nb2HLGrmQ40KvY= 14 | github.com/go-openapi/jsonpointer v0.19.6 h1:eCs3fxoIi3Wh6vtgmLTOjdhSpiqphQ+DaPn38N2ZdrE= 15 | github.com/go-openapi/jsonpointer v0.19.6/go.mod h1:osyAmYz/mB/C3I+WsTTSgw1ONzaLJoLCyoi6/zppojs= 16 | github.com/go-openapi/jsonreference v0.20.2 h1:3sVjiK66+uXK/6oQ8xgcRKcFgQ5KXa2KvnJRumpMGbE= 17 | github.com/go-openapi/jsonreference v0.20.2/go.mod h1:Bl1zwGIM8/wsvqjsOQLJ/SH+En5Ap4rVB5KVcIDZG2k= 18 | github.com/go-openapi/swag v0.22.3 h1:yMBqmnQ0gyZvEb/+KzuWZOXgllrXT4SADYbvDaXHv/g= 19 | github.com/go-openapi/swag v0.22.3/go.mod h1:UzaqsxGiab7freDnrUUra0MwWfN/q7tE4j+VcZ0yl14= 20 | github.com/gogo/protobuf v1.3.2 h1:Ov1cvc58UF3b5XjBnZv7+opcTcQFZebYjWzi34vdm4Q= 21 | github.com/gogo/protobuf v1.3.2/go.mod h1:P1XiOD3dCwIKUDQYPy72D8LYyHL2YPYrpS2s69NZV8Q= 22 | github.com/golang/protobuf v1.5.4 h1:i7eJL8qZTpSEXOPTxNKhASYpMn+8e5Q6AdndVa1dWek= 23 | github.com/golang/protobuf v1.5.4/go.mod h1:lnTiLA8Wa4RWRcIUkrtSVa5nRhsEGBg48fD6rSs7xps= 24 | github.com/google/gnostic-models v0.6.8 h1:yo/ABAfM5IMRsS1VnXjTBvUb61tFIHozhlYvRgGre9I= 25 | github.com/google/gnostic-models v0.6.8/go.mod h1:5n7qKqH0f5wFt+aWF8CW6pZLLNOfYuF5OpfBSENuI8U= 26 | github.com/google/go-cmp v0.5.9/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY= 27 | github.com/google/go-cmp v0.6.0 h1:ofyhxvXcZhMsU5ulbFiLKl/XBFqE1GSq7atu8tAmTRI= 28 | github.com/google/go-cmp v0.6.0/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY= 29 | github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg= 30 | github.com/google/gofuzz v1.2.0 h1:xRy4A+RhZaiKjJ1bPfwQ8sedCA+YS2YcCHW6ec7JMi0= 31 | github.com/google/gofuzz v1.2.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg= 32 | github.com/google/uuid v1.3.0 h1:t6JiXgmwXMjEs8VusXIJk2BXHsn+wx8BZdTaoZ5fu7I= 33 | github.com/google/uuid v1.3.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= 34 | github.com/imdario/mergo v0.3.6 h1:xTNEAn+kxVO7dTZGu0CegyqKZmoWFI0rF8UxjlB2d28= 35 | github.com/imdario/mergo v0.3.6/go.mod h1:2EnlNZ0deacrJVfApfmtdGgDfMuh/nq6Ok1EcJh5FfA= 36 | github.com/josharian/intern v1.0.0 h1:vlS4z54oSdjm0bgjRigI+G1HpF+tI+9rE5LLzOg8HmY= 37 | github.com/josharian/intern v1.0.0/go.mod h1:5DoeVV0s6jJacbCEi61lwdGj/aVlrQvzHFFd8Hwg//Y= 38 | github.com/json-iterator/go v1.1.12 h1:PV8peI4a0ysnczrg+LtxykD8LfKY9ML6u2jnxaEnrnM= 39 | github.com/json-iterator/go v1.1.12/go.mod h1:e30LSqwooZae/UwlEbR2852Gd8hjQvJoHmT4TnhNGBo= 40 | github.com/kisielk/errcheck v1.5.0/go.mod h1:pFxgyoBC7bSaBwPgfKdkLd5X25qrDl4LWUI2bnpBCr8= 41 | github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+oQHNcck= 42 | github.com/mailru/easyjson v0.7.7 h1:UGYAvKxe3sBsEDzO8ZeWOSlIQfWFlxbzLZe7hwFURr0= 43 | github.com/mailru/easyjson v0.7.7/go.mod h1:xzfreul335JAWq5oZzymOObrkdz5UnU4kGfJJLY9Nlc= 44 | github.com/modern-go/concurrent v0.0.0-20180228061459-e0a39a4cb421/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q= 45 | github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd h1:TRLaZ9cD/w8PVh93nsPXa1VrQ6jlwL5oN8l14QlcNfg= 46 | github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q= 47 | github.com/modern-go/reflect2 v1.0.2 h1:xBagoLtFs94CBntxluKeaWgTMpvLxC4ur3nMaC9Gz0M= 48 | github.com/modern-go/reflect2 v1.0.2/go.mod h1:yWuevngMOJpCy52FWWMvUC8ws7m/LJsjYzDa0/r8luk= 49 | github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822 h1:C3w9PqII01/Oq1c1nUAm88MOHcQC9l5mIlSMApZMrHA= 50 | github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822/go.mod h1:+n7T8mK8HuQTcFwEeznm/DIxMOiR9yIdICNftLE1DvQ= 51 | github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4= 52 | github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= 53 | github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= 54 | github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= 55 | github.com/sirupsen/logrus v1.9.3 h1:dueUQJ1C2q9oE3F7wvmSGAaVtTmUizReu6fjN8uqzbQ= 56 | github.com/sirupsen/logrus v1.9.3/go.mod h1:naHLuLoDiP4jHNo9R0sCBMtWGeIprob74mVsIT4qYEQ= 57 | github.com/spf13/pflag v1.0.5 h1:iy+VFUOCP1a+8yFto/drg2CJ5u0yRoB7fZw3DKv/JXA= 58 | github.com/spf13/pflag v1.0.5/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An2Bg= 59 | github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= 60 | github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI= 61 | github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= 62 | github.com/stretchr/testify v1.8.4 h1:CcVxjf3Q8PM0mHUKJCdn+eZZtm5yQwehR5yeSVQQcUk= 63 | github.com/stretchr/testify v1.8.4/go.mod h1:sz/lmYIOXD/1dqDmKjjqLyZ2RngseejIcXlSw2iwfAo= 64 | github.com/yuin/goldmark v1.1.27/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= 65 | github.com/yuin/goldmark v1.2.1/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= 66 | golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= 67 | golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= 68 | golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= 69 | golang.org/x/mod v0.2.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= 70 | golang.org/x/mod v0.3.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= 71 | golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= 72 | golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= 73 | golang.org/x/net v0.0.0-20200226121028-0de0cce0169b/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= 74 | golang.org/x/net v0.0.0-20201021035429-f5854403a974/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU= 75 | golang.org/x/net v0.25.0 h1:d/OCCoBEUq33pjydKrGQhw7IlUPI2Oylr+8qLx49kac= 76 | golang.org/x/net v0.25.0/go.mod h1:JkAGAh7GEvH74S6FOH42FLoXpXbE/aqXSrIQjXgsiwM= 77 | golang.org/x/oauth2 v0.21.0 h1:tsimM75w1tF/uws5rbeHzIWxEqElMehnc+iW793zsZs= 78 | golang.org/x/oauth2 v0.21.0/go.mod h1:XYTD2NtWslqkgxebSiOHnXEap4TF09sJSc7H1sXbhtI= 79 | golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= 80 | golang.org/x/sync v0.0.0-20190911185100-cd5d95a43a6e/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= 81 | golang.org/x/sync v0.0.0-20201020160332-67f06af15bc9/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= 82 | golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= 83 | golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= 84 | golang.org/x/sys v0.0.0-20200930185726-fdedc70b468f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= 85 | golang.org/x/sys v0.0.0-20220715151400-c0bba94af5f8/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= 86 | golang.org/x/sys v0.20.0 h1:Od9JTbYCk261bKm4M/mw7AklTlFYIa0bIp9BgSm1S8Y= 87 | golang.org/x/sys v0.20.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= 88 | golang.org/x/term v0.20.0 h1:VnkxpohqXaOBYJtBmEppKUG6mXpi+4O6purfc2+sMhw= 89 | golang.org/x/term v0.20.0/go.mod h1:8UkIAJTvZgivsXaD6/pH6U9ecQzZ45awqEOzuCvwpFY= 90 | golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= 91 | golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= 92 | golang.org/x/text v0.15.0 h1:h1V/4gjBv8v9cjcR6+AR5+/cIYK5N/WAgiv4xlsEtAk= 93 | golang.org/x/text v0.15.0/go.mod h1:18ZOQIKpY8NJVqYksKHtTdi31H5itFRjB5/qKTNYzSU= 94 | golang.org/x/time v0.5.0 h1:o7cqy6amK/52YcAKIPlM3a+Fpj35zvRj2TP+e1xFSfk= 95 | golang.org/x/time v0.5.0/go.mod h1:3BpzKBy/shNhVucY/MWOyx10tF3SFh9QdLuxbVysPQM= 96 | golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= 97 | golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= 98 | golang.org/x/tools v0.0.0-20200619180055-7c47624df98f/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE= 99 | golang.org/x/tools v0.0.0-20210106214847-113979e3529a/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= 100 | golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= 101 | golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= 102 | golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= 103 | golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= 104 | google.golang.org/protobuf v1.34.1 h1:9ddQBjfCyZPOHPUiPxpYESBLc+T8P3E+Vo4IbKZgFWg= 105 | google.golang.org/protobuf v1.34.1/go.mod h1:c6P6GXX6sHbq/GpV6MGZEdwhWPcYBgnhAHhKbcUYpos= 106 | gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405 h1:yhCVgyC4o1eVCa2tZl7eS0r+SDo693bJlVdllGtEeKM= 107 | gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= 108 | gopkg.in/inf.v0 v0.9.1 h1:73M5CoZyi3ZLMOyDlQh031Cx6N9NDJ2Vvfl76EDAgDc= 109 | gopkg.in/inf.v0 v0.9.1/go.mod h1:cWUDdTG/fYaXco+Dcufb5Vnc6Gp2YChqWtbxRZE0mXw= 110 | gopkg.in/yaml.v2 v2.2.8/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= 111 | gopkg.in/yaml.v2 v2.4.0 h1:D8xgwECY7CYvx+Y2n4sBz93Jn9JRvxdiyyo8CTfuKaY= 112 | gopkg.in/yaml.v2 v2.4.0/go.mod h1:RDklbk79AGWmwhnvt/jBztapEOGDOx6ZbXqjP6csGnQ= 113 | gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= 114 | gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA= 115 | gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= 116 | gotest.tools/v3 v3.5.2 h1:7koQfIKdy+I8UTetycgUqXWSDwpgv193Ka+qRsmBY8Q= 117 | gotest.tools/v3 v3.5.2/go.mod h1:LtdLGcnqToBH83WByAAi/wiwSFCArdFIUV/xxN4pcjA= 118 | k8s.io/api v0.30.2 h1:+ZhRj+28QT4UOH+BKznu4CBgPWgkXO7XAvMcMl0qKvI= 119 | k8s.io/api v0.30.2/go.mod h1:ULg5g9JvOev2dG0u2hig4Z7tQ2hHIuS+m8MNZ+X6EmI= 120 | k8s.io/apimachinery v0.30.2 h1:fEMcnBj6qkzzPGSVsAZtQThU62SmQ4ZymlXRC5yFSCg= 121 | k8s.io/apimachinery v0.30.2/go.mod h1:iexa2somDaxdnj7bha06bhb43Zpa6eWH8N8dbqVjTUc= 122 | k8s.io/client-go v0.30.2 h1:sBIVJdojUNPDU/jObC+18tXWcTJVcwyqS9diGdWHk50= 123 | k8s.io/client-go v0.30.2/go.mod h1:JglKSWULm9xlJLx4KCkfLLQ7XwtlbflV6uFFSHTMgVs= 124 | k8s.io/klog/v2 v2.120.1 h1:QXU6cPEOIslTGvZaXvFWiP9VKyeet3sawzTOvdXb4Vw= 125 | k8s.io/klog/v2 v2.120.1/go.mod h1:3Jpz1GvMt720eyJH1ckRHK1EDfpxISzJ7I9OYgaDtPE= 126 | k8s.io/kube-openapi v0.0.0-20240228011516-70dd3763d340 h1:BZqlfIlq5YbRMFko6/PM7FjZpUb45WallggurYhKGag= 127 | k8s.io/kube-openapi v0.0.0-20240228011516-70dd3763d340/go.mod h1:yD4MZYeKMBwQKVht279WycxKyM84kkAx2DPrTXaeb98= 128 | k8s.io/utils v0.0.0-20230726121419-3b25d923346b h1:sgn3ZU783SCgtaSJjpcVVlRqd6GSnlTLKgpAAttJvpI= 129 | k8s.io/utils v0.0.0-20230726121419-3b25d923346b/go.mod h1:OLgZIPagt7ERELqWJFomSt595RzquPNLL48iOWgYOg0= 130 | sigs.k8s.io/json v0.0.0-20221116044647-bc3834ca7abd h1:EDPBXCAspyGV4jQlpZSudPeMmr1bNJefnuqLsRAsHZo= 131 | sigs.k8s.io/json v0.0.0-20221116044647-bc3834ca7abd/go.mod h1:B8JuhiUyNFVKdsE8h686QcCxMaH6HrOAZj4vswFpcB0= 132 | sigs.k8s.io/structured-merge-diff/v4 v4.4.1 h1:150L+0vs/8DA78h1u02ooW1/fFq/Lwr+sGiqlzvrtq4= 133 | sigs.k8s.io/structured-merge-diff/v4 v4.4.1/go.mod h1:N8hJocpFajUSSeSJ9bOZ77VzejKZaXsTtZo4/u7Io08= 134 | sigs.k8s.io/yaml v1.3.0 h1:a2VclLzOGrwOHDiV8EfBGhvjHvP46CtW5j6POvhYGGo= 135 | sigs.k8s.io/yaml v1.3.0/go.mod h1:GeOyir5tyXNByN85N/dRIT9es5UQNerPYEKK56eTBm8= 136 | --------------------------------------------------------------------------------