// Copyright (c) 2023 Multus Authors // // 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. // This binary submit CSR for kube controll access for multus thin plugin // and generate Kubeconfig package main import ( "encoding/base64" "fmt" "os" "os/signal" "path/filepath" "syscall" "text/template" "time" "github.com/spf13/pflag" "gopkg.in/k8snetworkplumbingwg/multus-cni.v4/pkg/k8sclient" "k8s.io/client-go/tools/clientcmd" "k8s.io/klog/v2" ) var kubeConfigTemplate = `apiVersion: v1 clusters: - cluster: certificate-authority-data: {{.CADATA}} server: {{.K8S_APISERVER}} name: default-cluster contexts: - context: cluster: default-cluster namespace: default user: default-auth name: default-context current-context: default-context kind: Config preferences: {} users: - name: default-auth user: client-certificate: {{.CERTDIR}}/multus-client-current.pem client-key: {{.CERTDIR}}/multus-client-current.pem ` func main() { certDir := pflag.StringP("certdir", "", "/tmp", "specify cert directory") bootstrapConfig := pflag.StringP("bootstrap-config", "", "/tmp/kubeconfig", "specify bootstrap kubernetes config") kubeconfigPathRaw := pflag.StringP("kubeconfig", "", "/run/multus/kubeconfig", "specify output kubeconfig path") certDurationString := pflag.StringP("cert-duration", "", "10m", "specify certificate duration") helpFlag := pflag.BoolP("help", "h", false, "show help message and quit") kubeconfigPath, err := filepath.Abs(*kubeconfigPathRaw) if err != nil { klog.Fatalf("illegal path %s in kubeconfigPath %s: %v", kubeconfigPath, *kubeconfigPathRaw, err) } pflag.Parse() if *helpFlag { pflag.PrintDefaults() os.Exit(1) } // check variables if _, err := os.Stat(*bootstrapConfig); err != nil { klog.Fatalf("failed to read bootstrap config %q", *bootstrapConfig) } st, err := os.Stat(*certDir) if err != nil { klog.Fatalf("failed to find cert directory %q", *certDir) } if !st.IsDir() { klog.Fatalf("cert directory %q is not directory", *certDir) } certDuration, err := time.ParseDuration(*certDurationString) if err != nil { klog.Fatalf("failed to parse duration %q: %v", *certDurationString, err) } nodeName := os.Getenv("MULTUS_NODE_NAME") if nodeName == "" { klog.Fatalf("cannot identify node name from MULTUS_NODE_NAME env variables") } // retrieve API server from bootstrapConfig() config, err := clientcmd.BuildConfigFromFlags("", *bootstrapConfig) if err != nil { klog.Fatalf("cannot get in-cluster config: %v", err) } apiServer := fmt.Sprintf("%s%s", config.Host, config.APIPath) caData := base64.StdEncoding.EncodeToString(config.CAData) // run certManager to create certification if _, err = k8sclient.PerNodeK8sClient(nodeName, *bootstrapConfig, certDuration, *certDir); err != nil { klog.Fatalf("failed to start cert manager: %v", err) } fp, err := os.OpenFile(kubeconfigPath, os.O_RDWR|os.O_CREATE|os.O_TRUNC, 0600) if err != nil { klog.Fatalf("cannot create kubeconfig file %q: %v", kubeconfigPath, err) } // render kubeconfig templateKubeconfig, err := template.New("kubeconfig").Parse(kubeConfigTemplate) if err != nil { klog.Fatalf("template parse error: %v", err) } templateData := map[string]string{ "CADATA": caData, "CERTDIR": *certDir, "K8S_APISERVER": apiServer, } // genearate kubeconfig from template if err = templateKubeconfig.Execute(fp, templateData); err != nil { klog.Fatalf("cannot create kubeconfig: %v", err) } if err = fp.Close(); err != nil { klog.Fatalf("cannot save kubeconfig: %v", err) } klog.Infof("kubeconfig %q is saved", kubeconfigPath) // wait for signal sigterm := make(chan os.Signal, 1) signal.Notify(sigterm, syscall.SIGINT, syscall.SIGTERM, syscall.SIGKILL) <-sigterm klog.Infof("signal received. remove kubeconfig %q and quit.", kubeconfigPath) err = os.Remove(kubeconfigPath) if err != nil { klog.Errorf("failed to remove kubeconfig %q: %v", kubeconfigPath, err) } }