internal/kubelet/kubeconfig.go (111 lines of code) (raw):

package kubelet import ( "bytes" _ "embed" "path" "text/template" "github.com/pkg/errors" "k8s.io/client-go/kubernetes" "k8s.io/client-go/tools/clientcmd" "github.com/aws/eks-hybrid/internal/api" "github.com/aws/eks-hybrid/internal/iamauthenticator" "github.com/aws/eks-hybrid/internal/util" ) const ( kubeconfigRoot = "/var/lib/kubelet" kubeconfigFile = "kubeconfig" kubeconfigBootstrapFile = "bootstrap-kubeconfig" kubeconfigPerm = 0o644 ) var ( //go:embed kubeconfig.template.yaml kubeconfigTemplateData string //go:embed hybrid-kubeconfig.template.yaml hybridKubeconfigTemplateData string kubeconfigPath = path.Join(kubeconfigRoot, kubeconfigFile) kubeconfigBootstrapPath = path.Join(kubeconfigRoot, kubeconfigBootstrapFile) ) func (k *kubelet) writeKubeconfig() error { kubeconfig, err := generateKubeconfig(k.nodeConfig) if err != nil { return err } if k.nodeConfig.IsOutpostNode() { // kubelet bootstrap kubeconfig uses aws-iam-authenticator with cluster id to authenticate to cluster // - if "aws eks describe-cluster" is bypassed, for local outpost, the value of CLUSTER_NAME parameter will be cluster id. // - otherwise, the cluster id will use the id returned by "aws eks describe-cluster". k.flags["bootstrap-kubeconfig"] = kubeconfigBootstrapPath return util.WriteFileWithDir(kubeconfigBootstrapPath, kubeconfig, kubeconfigPerm) } else { k.flags["kubeconfig"] = kubeconfigPath return util.WriteFileWithDir(kubeconfigPath, kubeconfig, kubeconfigPerm) } } type kubeconfigTemplateVars struct { Cluster string Region string APIServerEndpoint string CaCertPath string SessionName string AssumeRole string AwsConfigPath string AwsIamAuthenticatorPath string } func newKubeconfigTemplateVars(cfg *api.NodeConfig) *kubeconfigTemplateVars { return &kubeconfigTemplateVars{ Cluster: cfg.Spec.Cluster.Name, Region: cfg.Status.Instance.Region, APIServerEndpoint: cfg.Spec.Cluster.APIServerEndpoint, CaCertPath: caCertificatePath, } } func (kct *kubeconfigTemplateVars) withOutpostVars(cfg *api.NodeConfig) { kct.Cluster = cfg.Spec.Cluster.ID } func (kct *kubeconfigTemplateVars) withHybridTemplateVars(cfg *api.NodeConfig) { if cfg.IsIAMRolesAnywhere() { kct.withIamRolesAnywhereHybridVars(cfg) } else if cfg.IsSSM() { kct.withSsmHybridVars(cfg) } kct.AwsIamAuthenticatorPath = iamauthenticator.IAMAuthenticatorBinPath } func (kct *kubeconfigTemplateVars) withIamRolesAnywhereHybridVars(cfg *api.NodeConfig) { kct.Region = cfg.Spec.Cluster.Region kct.AwsConfigPath = cfg.Spec.Hybrid.IAMRolesAnywhere.AwsConfigPath } func (kct *kubeconfigTemplateVars) withSsmHybridVars(cfg *api.NodeConfig) { kct.Region = cfg.Spec.Cluster.Region } func generateKubeconfig(cfg *api.NodeConfig) ([]byte, error) { config := newKubeconfigTemplateVars(cfg) if cfg.IsOutpostNode() { config.withOutpostVars(cfg) } if cfg.IsHybridNode() { config.withHybridTemplateVars(cfg) } var buf bytes.Buffer var kubeconfigTemplate *template.Template // SSM based hybrid nodes can still use the normal eks get-token api for authentication if cfg.IsHybridNode() { kubeconfigTemplate = template.Must(template.New(kubeconfigFile).Parse(hybridKubeconfigTemplateData)) } else { kubeconfigTemplate = template.Must(template.New(kubeconfigFile).Parse(kubeconfigTemplateData)) } if err := kubeconfigTemplate.Execute(&buf, config); err != nil { return nil, err } return buf.Bytes(), nil } // GetKubeClientFromKubeConfig gets kubernetes client from kubeconfig on the disk func GetKubeClientFromKubeConfig() (kubernetes.Interface, error) { // Use the current context in the kubeconfig file config, err := clientcmd.BuildConfigFromFlags("", KubeconfigPath()) if err != nil { return nil, errors.Wrap(err, "failed to build config from kubeconfig") } return kubernetes.NewForConfig(config) } // KubeconfigPath returns the path to the kubeconfig file used by the kubelet. func KubeconfigPath() string { return kubeconfigPath } // Kubeconfig is the default kubeconfig generated for the kubelet. type Kubeconfig struct{} // Path returns the path to the kubeconfig file used by the kubelet. func (d Kubeconfig) Path() string { return KubeconfigPath() } // BuildClient builds a new Kubernetes client from the kubeconfig. func (d Kubeconfig) BuildClient() (kubernetes.Interface, error) { return GetKubeClientFromKubeConfig() }