/* Copyright 2020 The Kubernetes Authors All rights reserved. Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. */ package gcpauth import ( "bytes" "context" "io/ioutil" "os" "os/exec" "path" "strconv" "github.com/pkg/errors" "golang.org/x/oauth2/google" "k8s.io/minikube/pkg/minikube/assets" "k8s.io/minikube/pkg/minikube/config" "k8s.io/minikube/pkg/minikube/exit" "k8s.io/minikube/pkg/minikube/mustload" "k8s.io/minikube/pkg/minikube/out" "k8s.io/minikube/pkg/minikube/reason" "k8s.io/minikube/pkg/minikube/style" ) const ( credentialsPath = "/var/lib/minikube/google_application_credentials.json" projectPath = "/var/lib/minikube/google_cloud_project" ) // EnableOrDisable enables or disables the metadata addon depending on the val parameter func EnableOrDisable(cfg *config.ClusterConfig, name string, val string) error { enable, err := strconv.ParseBool(val) if err != nil { return errors.Wrapf(err, "parsing bool: %s", name) } if enable { return enableAddon(cfg) } return disableAddon(cfg) } func enableAddon(cfg *config.ClusterConfig) error { // Grab command runner from running cluster cc := mustload.Running(cfg.Name) r := cc.CP.Runner // Grab credentials from where GCP would normally look ctx := context.Background() creds, err := google.FindDefaultCredentials(ctx) if err != nil { exit.Message(reason.InternalCredsNotFound, "Could not find any GCP credentials. Either run `gcloud auth application-default login` or set the GOOGLE_APPLICATION_CREDENTIALS environment variable to the path of your credentials file.") } if creds.JSON == nil { // Cloud Shell sends credential files to an unusual location, let's check that location // For example, CLOUDSDK_CONFIG=/tmp/tmp.cflmvysoQE if e := os.Getenv("CLOUDSDK_CONFIG"); e != "" { credFile := path.Join(e, "application_default_credentials.json") b, err := ioutil.ReadFile(credFile) if err != nil { exit.Message(reason.InternalCredsNotFound, "Could not find any GCP credentials. Either run `gcloud auth application-default login` or set the GOOGLE_APPLICATION_CREDENTIALS environment variable to the path of your credentials file.") } creds.JSON = b } else { // We don't currently support authentication through the metadata server exit.Message(reason.InternalCredsNotFound, "Could not find any GCP credentials. Either run `gcloud auth application-default login` or set the GOOGLE_APPLICATION_CREDENTIALS environment variable to the path of your credentials file.") } } f := assets.NewMemoryAssetTarget(creds.JSON, credentialsPath, "0444") err = r.Copy(f) if err != nil { return err } // First check if the project env var is explicitly set projectEnv := os.Getenv("GOOGLE_CLOUD_PROJECT") if projectEnv != "" { f := assets.NewMemoryAssetTarget([]byte(projectEnv), projectPath, "0444") return r.Copy(f) } // We're currently assuming gcloud is installed and in the user's path project, err := exec.Command("gcloud", "config", "get-value", "project").Output() if err == nil && len(project) > 0 { f := assets.NewMemoryAssetTarget(bytes.TrimSpace(project), projectPath, "0444") return r.Copy(f) } out.WarningT("Could not determine a Google Cloud project, which might be ok.") out.Step(style.Tip, `To set your Google Cloud project, run: gcloud config set project or set the GOOGLE_CLOUD_PROJECT environment variable.`) // Copy an empty file in to avoid errors about missing files emptyFile := assets.NewMemoryAssetTarget([]byte{}, projectPath, "0444") return r.Copy(emptyFile) } func disableAddon(cfg *config.ClusterConfig) error { // Grab command runner from running cluster cc := mustload.Running(cfg.Name) r := cc.CP.Runner // Clean up the files generated when enabling the addon creds := assets.NewMemoryAssetTarget([]byte{}, credentialsPath, "0444") err := r.Remove(creds) if err != nil { return err } project := assets.NewMemoryAssetTarget([]byte{}, projectPath, "0444") err = r.Remove(project) if err != nil { return err } return nil }