diff --git a/pkg/eks/auth.go b/pkg/eks/auth.go index b54fc505a6..9754153566 100644 --- a/pkg/eks/auth.go +++ b/pkg/eks/auth.go @@ -8,6 +8,7 @@ import ( "github.com/pkg/errors" "github.com/weaveworks/eksctl/pkg/eks/api" + "github.com/weaveworks/eksctl/pkg/utils/kubeconfig" "github.com/aws/aws-sdk-go/aws" "github.com/aws/aws-sdk-go/service/ec2" @@ -163,29 +164,10 @@ type ClientConfig struct { // based on "k8s.io/kubernetes/cmd/kubeadm/app/util/kubeconfig" // these are small, so we can copy these, and no need to deal with k/k as dependency func (c *ClusterProvider) NewClientConfig() (*ClientConfig, error) { - clusterName := fmt.Sprintf("%s.%s.eksctl.io", c.Spec.ClusterName, c.Spec.Region) - contextName := fmt.Sprintf("%s@%s", c.getUsername(), clusterName) - + client, clusterName, contextName := kubeconfig.New(c.Spec, c.getUsername(), "") clientConfig := &ClientConfig{ - Cluster: c.Spec, - Client: &clientcmdapi.Config{ - Clusters: map[string]*clientcmdapi.Cluster{ - clusterName: { - Server: c.Spec.Endpoint, - CertificateAuthorityData: c.Spec.CertificateAuthorityData, - }, - }, - Contexts: map[string]*clientcmdapi.Context{ - contextName: { - Cluster: clusterName, - AuthInfo: contextName, - }, - }, - AuthInfos: map[string]*clientcmdapi.AuthInfo{ - contextName: &clientcmdapi.AuthInfo{}, - }, - CurrentContext: contextName, - }, + Cluster: c.Spec, + Client: client, ClusterName: clusterName, ContextName: contextName, roleARN: c.Status.iamRoleARN, @@ -195,22 +177,20 @@ func (c *ClusterProvider) NewClientConfig() (*ClientConfig, error) { return clientConfig, nil } +// WithExecAuthenticator creates a copy of ClientConfig with authenticator exec plugin +// it ensures that AWS_PROFILE environment variable gets added to config also func (c *ClientConfig) WithExecAuthenticator() *ClientConfig { clientConfigCopy := *c - x := clientConfigCopy.Client.AuthInfos[c.ContextName] - x.Exec = &clientcmdapi.ExecConfig{ - APIVersion: "client.authentication.k8s.io/v1alpha1", - Command: utils.DetectAuthenticator(), - Args: []string{"token", "-i", c.Cluster.ClusterName}, - /* - Args: []string{"token", "-i", c.Cluster.ClusterName, "-r", c.roleARN}, - */ - } + kubeconfig.AppendAuthenticator(clientConfigCopy.Client, c.Cluster, utils.DetectAuthenticator()) if len(c.Cluster.Profile) > 0 { - profileVar := &clientcmdapi.ExecEnvVar{Name: "AWS_PROFILE", Value: c.Cluster.Profile} - x.Exec.Env = []clientcmdapi.ExecEnvVar{*profileVar} + clientConfigCopy.Client.AuthInfos[c.ContextName].Exec.Env = []clientcmdapi.ExecEnvVar{ + clientcmdapi.ExecEnvVar{ + Name: "AWS_PROFILE", + Value: c.Cluster.Profile, + }, + } } return &clientConfigCopy diff --git a/pkg/nodebootstrap/assets.go b/pkg/nodebootstrap/assets.go index a04f478e83..439c79d008 100644 --- a/pkg/nodebootstrap/assets.go +++ b/pkg/nodebootstrap/assets.go @@ -1,10 +1,7 @@ // Code generated by go-bindata. // sources: // assets/10-eksclt.al2.conf -// assets/authenticator.sh -// assets/get_credentials.sh -// assets/get_metadata.sh -// assets/kubeconfig.yaml +// assets/bootstrap.al2.sh // DO NOT EDIT! package nodebootstrap @@ -92,82 +89,22 @@ func _10EkscltAl2Conf() (*asset, error) { return a, nil } -var _authenticatorSh = []byte("\x1f\x8b\x08\x00\x00\x00\x00\x00\x00\xff\x6c\xcf\xcf\x4a\xf5\x30\x14\x04\xf0\x7d\x9e\x62\xbe\xdb\x0f\x54\xb0\xed\x33\x5c\xa4\x2b\xff\x2c\xac\xe2\xb2\x3d\xb7\x3d\x6d\x43\xd3\x9c\x90\x9c\xdc\x22\xe2\xbb\x8b\xe8\x42\xc1\xed\x0c\x03\xf3\x2b\xfe\xd5\x27\xeb\xeb\xb4\xa0\xe4\x6c\x4c\x81\xd6\x6e\xc1\x31\xf6\x48\x21\x70\xc4\x24\x11\x94\x75\x61\xaf\x76\x20\x95\x78\x8d\x24\xd8\x19\x03\x79\x44\xa6\x11\xc7\x97\xb6\x6b\x6e\xdb\xee\xe6\xee\xb9\x7d\x6a\x1e\xbb\x87\xe3\x7d\x83\x29\xca\x86\x7e\x63\xa5\x91\x94\x2a\xf6\xe7\xde\x14\xb0\x3e\xe9\xe7\x44\x26\x2c\x74\xb6\x7e\x86\x0a\x72\x18\x49\x19\xfd\x9a\x4f\x3c\x88\x9f\xec\x5c\xbd\xd2\xe6\x7a\x5c\x52\xfa\x4e\xd5\xe1\xab\xe9\x31\x0a\x27\x7f\xa1\x48\x39\x04\x89\x8a\xe0\xf2\x6c\x3d\x26\xcb\x6e\x4c\x57\xc6\x54\xa8\x59\x87\x9a\xd7\x34\xa8\xab\x7f\x1e\x30\x86\xf6\x54\x5a\xda\xca\x5f\x1e\xa8\xac\xec\x51\x5a\x1c\xfe\xbf\xfd\x65\x79\x3f\x7c\x04\x00\x00\xff\xff\xf7\xe0\x0f\x10\x24\x01\x00\x00") +var _bootstrapAl2Sh = []byte("\x1f\x8b\x08\x00\x00\x00\x00\x00\x00\xff\x4c\xcb\x31\x0e\xc2\x30\x0c\x46\xe1\x3d\xa7\x30\x85\x01\x86\x34\x27\x80\x09\x06\x16\xe0\x06\xc8\x49\x7f\x29\x55\x9d\x44\xaa\x5d\x24\x6e\xcf\x82\xaa\xae\xdf\xd3\xdb\xef\x42\x1c\x6b\xd0\x4c\x1e\x8b\x73\x48\xb9\x51\xf7\x78\x5e\x6f\xef\xfb\xeb\x7c\x38\xe6\xa6\x56\xb9\x80\xfc\x78\xea\xe8\x42\x01\x96\x02\x26\x4d\x26\x61\x5a\x22\x04\xd6\x4b\x4b\x2c\x3d\xea\xc7\x39\xfd\xaa\xa1\x24\x13\x1a\x18\xa5\x55\x3f\x43\x1a\x0f\x1b\x47\xe5\x28\xa0\xff\xbb\x09\x6a\x3c\xdb\xea\xbf\x00\x00\x00\xff\xff\xef\x6e\xff\x33\x97\x00\x00\x00") -func authenticatorShBytes() ([]byte, error) { +func bootstrapAl2ShBytes() ([]byte, error) { return bindataRead( - _authenticatorSh, - "authenticator.sh", + _bootstrapAl2Sh, + "bootstrap.al2.sh", ) } -func authenticatorSh() (*asset, error) { - bytes, err := authenticatorShBytes() +func bootstrapAl2Sh() (*asset, error) { + bytes, err := bootstrapAl2ShBytes() if err != nil { return nil, err } - info := bindataFileInfo{name: "authenticator.sh", size: 292, mode: os.FileMode(493), modTime: time.Unix(1, 0)} - a := &asset{bytes: bytes, info: info} - return a, nil -} - -var _get_credentialsSh = []byte("\x1f\x8b\x08\x00\x00\x00\x00\x00\x00\xff\x7c\x92\xcd\x6e\xdb\x30\x10\x84\xef\xfb\x14\x53\xc6\x40\x92\x83\xa4\x4b\xd1\x5b\x0a\xb8\xa9\x12\x18\x71\x6d\xc0\x8e\xd1\x4b\x01\x85\xa2\xd6\x35\x63\x99\x54\xc9\x55\x7e\xe0\xf8\xdd\x0b\xa5\x92\x91\xe6\x90\xe3\xee\x60\x86\xc3\x8f\x3c\xf9\x94\x95\xd6\x65\xa5\x8e\x1b\xa2\x13\xcc\x4b\xd1\xd6\xc1\xd4\x6d\x14\x0e\x30\x81\x2b\x76\x62\x75\x1d\xa1\x5d\x85\xb6\xa9\xb4\x30\xee\xb6\x6d\xc9\xc6\xbb\xb5\xfd\x9d\x3e\xeb\x5d\x7d\x87\x47\x2b\x1b\xe8\xc6\x46\x0e\x0f\x1c\xb0\x5a\x4c\x89\x22\x0b\x12\x0f\x0e\x81\x9f\xac\x0c\x63\x63\x1b\x5e\x6b\x5b\x0f\xb3\xf3\xad\x8b\x2c\x44\xd1\xb7\xc1\x30\x32\x16\x93\xf1\x36\x1a\xa9\xb3\x1d\x8b\xae\xb4\xe8\x94\xdd\x03\x11\x3f\x35\x3e\x08\xc6\x3f\x97\xc5\xf7\xfc\x6a\xbc\x9a\xde\x16\x8b\xfc\x7a\x32\x9f\x0d\xca\xcd\xea\x5b\x7e\x39\x9f\x5d\x4d\xae\x2f\xd4\xdb\x98\x77\x6d\x15\x51\xc5\xd1\x04\x5b\x72\xd1\x5f\xf4\xec\x1c\x7b\x02\xf4\x63\x04\x6f\x23\x06\x39\x19\x38\xfc\x22\x00\x48\x12\xdf\x4a\xd3\x0a\xee\xa3\x77\xc7\x9d\xd3\x3b\x86\x1a\xed\xbb\x5e\xf9\xcd\xb2\xb8\x9c\xae\x96\xb7\xf9\xa2\x98\x8d\x7f\xe4\x07\x45\x07\xa2\x3e\x65\xe2\xd6\xfe\x42\x8d\xce\xde\x1f\x7e\xae\x88\xd8\x55\x8d\xb7\x4e\x3a\x9d\xcd\xc6\x77\x81\x6f\x6c\x07\x85\x17\xdc\xff\x41\x12\x90\xf6\xeb\x74\xb0\xbc\xda\x3f\xb4\x9c\x1e\x3d\x86\x83\xd8\xb5\x35\x5a\x78\xdc\xca\xc6\x07\x2b\xcf\x69\x47\xf8\x14\x2f\x28\x75\xe4\x2f\x9f\x91\x54\xf8\xfa\xdf\x2b\x18\x9d\x9a\x20\x44\xaf\x18\xa5\xc6\x3f\x94\x88\x2c\x47\x3e\x9d\x14\x1c\x0b\x47\x24\x49\xff\x07\xd4\x68\x3f\x54\x3c\x28\xa2\xbf\x01\x00\x00\xff\xff\xe2\xe9\xad\xa5\x69\x02\x00\x00") - -func get_credentialsShBytes() ([]byte, error) { - return bindataRead( - _get_credentialsSh, - "get_credentials.sh", - ) -} - -func get_credentialsSh() (*asset, error) { - bytes, err := get_credentialsShBytes() - if err != nil { - return nil, err - } - - info := bindataFileInfo{name: "get_credentials.sh", size: 617, mode: os.FileMode(420), modTime: time.Unix(1, 0)} - a := &asset{bytes: bytes, info: info} - return a, nil -} - -var _get_metadataSh = []byte("\x1f\x8b\x08\x00\x00\x00\x00\x00\x00\xff\x94\x54\x5d\x6e\xe3\x36\x17\x7d\xd7\x2a\xee\xc7\x18\x70\x0c\x44\xd2\xe7\x34\x69\xa6\x01\x34\x45\x50\xbb\x85\x91\x69\x3c\x98\x64\xda\x87\x76\xe0\xd0\xd2\xb5\xc4\x31\x4d\x6a\x78\xaf\xec\x18\x8e\x81\xee\xa1\x1b\xe8\x5a\xba\x94\xae\xa4\xa0\xfc\x13\xd5\x49\xdb\xe9\x93\x20\xf2\x9e\x73\xee\xdf\xe1\xd1\xff\xe2\xb1\x32\xf1\x58\x52\x11\x04\x47\x30\x1c\xb3\x54\x06\x66\xc8\x32\x93\x2c\x41\x8e\x6d\xc5\xc0\x05\x82\x32\xc4\xd2\xa4\x78\x02\xa5\x74\x84\x80\x53\x4a\x59\x03\xcb\x1c\xe6\x52\x57\x08\x6c\x41\x9a\x0c\x16\x4e\x31\x82\x47\xdd\xef\x58\x22\x34\xf3\xfb\xfa\xf2\x7e\x5a\x8d\x51\x23\x47\xda\xa6\x52\xd7\xe7\xc1\x11\x4c\xac\x03\xcb\x05\x3a\xa0\xd4\xa9\x92\xa9\x8e\xf5\xa2\xb4\x24\xc6\x59\x06\x95\x51\xec\x05\x2a\xc2\x20\x20\x64\x08\x2d\xa0\x73\xf8\xa0\x78\xf7\x5b\xaa\x12\x27\x52\xe9\xdd\xbf\xb1\x95\x21\x64\x5f\xd4\x02\x21\xb5\x95\xce\x3c\xbc\xa6\x9d\x58\xad\xed\x42\x99\xfc\x04\xc6\x15\xfb\x7b\x62\xa5\x35\x18\xc4\x0c\x3e\x7e\xf2\x4a\x39\x32\x38\xcc\x95\x35\x75\x32\xbb\xea\x61\xd0\xbb\x0c\x8e\x40\x2e\x08\xc2\xd0\x56\x5c\xfa\xee\xe0\x03\x43\x18\x6e\xa3\x2b\x0a\x17\x48\x1c\x9e\x02\xa6\xa7\x90\xa1\x2f\x69\x8c\x21\xcb\xdc\x43\x26\x4a\x33\x3a\x82\x1b\x39\xc3\xc4\x21\xd9\xca\xa5\x18\xf2\xb2\xc4\x93\x1f\x7c\x17\x29\xd9\x2b\xfd\x35\x44\x65\xfb\x80\xf0\xff\xdd\x0b\xfc\xe2\xe2\xec\xfc\x14\xb1\x7b\x96\xbd\xca\x2e\x20\x0c\x3f\x55\xe8\x96\x20\xee\x64\x4e\x3f\x7d\x7d\x8d\xcb\x24\x69\x6f\x26\x14\xa5\xba\x22\x46\x17\x4d\x5f\x51\xa4\x6c\x3c\xef\x4a\x5d\x16\xb2\x1b\x6f\xcf\x43\x23\x67\xd8\xfe\x10\xd5\xec\xc2\xb7\xeb\x6e\xd8\x1b\x5e\x82\x9c\x5b\x95\x41\x21\xe7\xca\xe4\xbe\x21\x99\x05\xa9\x35\x70\xa1\x08\xfe\xf8\xe5\xd7\xdf\x7f\x2b\x98\x4b\xba\x8c\xe3\x5c\x71\x51\x8d\xa3\xd4\xce\xe2\x05\xca\x39\x2e\xac\x9b\x52\xbc\x11\x8f\x15\x51\x85\x14\x77\xcf\x2f\x82\x60\x57\xd9\xc0\x4c\x6c\x22\x5a\xc7\x69\xe5\x34\x84\x21\x29\x8d\x86\xc1\xd3\x5d\xc6\x71\xf7\xcb\xaf\xa2\xd3\xf3\xb3\x68\xfb\x8d\xb5\x64\x24\x8e\xb3\xa5\x91\x33\x95\xc6\x3b\x8e\x50\x65\x68\x58\xf1\x32\xce\x6c\x5a\xcd\xd0\x70\x47\x34\x14\x7a\x9e\x1f\xd3\xc2\x82\x68\xad\x9a\xba\x6b\x01\x8f\x7e\xc2\xa1\x83\x68\x7f\x9e\x75\xc4\x06\x5a\xa6\x38\x78\xfb\x39\xd0\xd2\xa9\xb9\x64\x1c\x94\x5e\xf5\xea\xc7\xdb\x51\xaf\xff\xed\xd5\xfb\x37\x77\xa3\x77\xfd\xef\x06\xc3\x9b\xcf\xa1\xd8\xac\x8b\xc7\xe3\x43\x69\x1d\xc3\x73\x1a\x3f\x8c\xbd\x13\x27\x4a\x23\x28\x02\x65\x18\x4d\x86\x59\xc3\x35\xde\xbc\x4f\xd6\x21\x58\xa0\xd6\xfe\xdb\x74\x0f\x9d\x00\x59\x50\xdc\xf6\x0c\x40\x6a\x56\x6a\xef\x03\x37\x93\x1c\x6c\x52\x7d\xa1\x8c\xd6\xea\xf9\xe1\x5a\x00\xbc\x86\x18\x39\xdd\xcd\xb8\x69\xf3\x60\x4b\x76\x33\xec\xf5\x47\x83\xb7\xc9\xb6\xfe\xba\xb1\x6b\x71\x00\x7c\xf6\x18\x04\x41\x8e\x3c\xf2\x56\x39\xee\xc0\x2a\x80\xda\x67\xcf\x6d\xf4\x73\x00\x00\x4f\xfe\xfb\x48\xd6\xec\xcf\x76\x06\x13\xff\xee\x30\x71\x18\xf4\xe4\xb1\xc6\xd8\x7a\x6b\x11\xac\x37\x89\x6d\x1d\x33\xf2\x8e\xd9\x26\x08\xdb\x71\xb6\xa3\xda\x79\x1f\xe0\x11\x08\x35\xa6\x7c\x1c\x5d\xe3\x12\x92\x04\xc4\x7f\xb0\xa1\xe8\xc0\x23\x6c\x9c\xd8\xf6\xa2\x69\x81\xe9\x74\x2f\x6b\x17\x06\xb3\xbd\x2e\xcb\x3c\x11\xbe\x83\xce\x20\x63\xcd\xb9\x0d\x8c\x5b\xab\xee\x5a\xec\x93\x0b\xa5\xcb\xeb\x67\x5a\xb4\x56\x2c\xf3\xb5\xf8\xe7\x7c\x5b\x2c\xf3\x83\x34\x7c\xd3\xfd\x4a\xef\x86\xe3\x97\xb6\xd9\x8b\xe6\xba\xfb\xfb\x7a\xcd\x0f\x1b\xe6\x41\xde\xca\xf0\x52\xf0\x0b\x85\xfa\xfb\x26\x7e\x2d\x3a\x02\x12\x10\xf5\xa5\x08\x1a\x4b\xdb\xbf\xbe\x1d\x7d\xf3\xe6\xfd\xed\x5d\xff\xdd\xe8\xe6\xea\xfb\x7e\x72\x08\x04\x78\xfd\xf7\x1b\xfb\x67\x00\x00\x00\xff\xff\x59\x14\x0f\xe6\x01\x07\x00\x00") - -func get_metadataShBytes() ([]byte, error) { - return bindataRead( - _get_metadataSh, - "get_metadata.sh", - ) -} - -func get_metadataSh() (*asset, error) { - bytes, err := get_metadataShBytes() - if err != nil { - return nil, err - } - - info := bindataFileInfo{name: "get_metadata.sh", size: 1793, mode: os.FileMode(420), modTime: time.Unix(1, 0)} - a := &asset{bytes: bytes, info: info} - return a, nil -} - -var _kubeconfigYaml = []byte("\x1f\x8b\x08\x00\x00\x00\x00\x00\x00\xff\x6c\x91\x41\x8f\xd3\x30\x10\x85\xef\xfe\x15\x4f\xdb\x2b\x4d\xd5\x1b\xca\x0d\xad\x38\x20\x21\x90\x10\x70\xa5\x83\xf3\xda\x8c\xea\xd8\x91\x67\xd2\xdd\xfd\xf7\xc8\x21\x0b\x3d\xec\x6d\x34\x33\xef\xbd\xf1\xe7\x1d\x3e\x65\x75\x95\x84\xd3\x75\xf9\xcd\x58\xf2\x59\x2f\xdd\x8b\x4c\xe9\x04\xe7\x34\x27\x71\x86\x1d\x4e\x17\xfa\xaf\x58\x39\x30\xb7\x65\xeb\x6c\x3c\xe1\xa9\xaa\xd3\x50\x16\xc7\xe3\x07\x44\x56\x7f\x07\xc9\x03\x8c\x6e\x90\x59\x8d\xf5\xc6\x8a\x1f\xdf\x3e\x87\x1d\xbe\x7c\xfd\xfe\xb1\x87\x8f\x34\x22\x96\x69\x62\x76\xc3\x93\xa6\x84\x5c\x1c\x32\xcf\x94\x0a\x39\x3b\x2b\x7c\x54\xc3\x59\x13\x0d\x97\x66\xb5\xcc\x83\x38\x87\x20\xb3\xfe\x64\x35\x2d\xb9\xc7\xed\x18\xae\x9a\x87\x1e\x8f\xeb\xc5\x21\xa6\xc5\x9c\xd5\xfa\xb0\xc7\x56\xf7\x01\xc0\x7a\x96\x9e\x35\x8a\x73\x2f\x8b\x8f\xa5\xaa\xbf\xf4\x78\x38\xd0\xe3\x81\x57\x8b\x9e\x0e\x51\xba\x58\xfd\x21\x00\x59\x26\xf6\x68\x24\x6a\xa6\xd3\x42\x2c\xd9\xf9\xec\xab\xef\xff\x61\xa2\x07\x60\x9b\x6d\x39\x5b\xe8\xbd\xb8\xf5\x17\x7b\x6d\x26\x3a\x10\xe2\x52\x2b\xb3\xef\x5f\xc5\xff\xfc\xda\xe2\x9b\x31\xab\xc3\xea\xc5\x67\xc6\xbf\x15\x70\x0f\x23\x26\x65\xf6\xae\x3d\xaf\xfd\x4f\x14\xd7\x92\xbb\xeb\x7b\xeb\xb4\x1c\x6e\x47\x49\xf3\x28\xc7\x4d\xd7\xd8\x4b\x03\x77\x0f\xe0\x4e\x59\x6a\x67\xe3\x9f\x00\x00\x00\xff\xff\xf3\x8f\xab\xb4\x16\x02\x00\x00") - -func kubeconfigYamlBytes() ([]byte, error) { - return bindataRead( - _kubeconfigYaml, - "kubeconfig.yaml", - ) -} - -func kubeconfigYaml() (*asset, error) { - bytes, err := kubeconfigYamlBytes() - if err != nil { - return nil, err - } - - info := bindataFileInfo{name: "kubeconfig.yaml", size: 534, mode: os.FileMode(420), modTime: time.Unix(1, 0)} + info := bindataFileInfo{name: "bootstrap.al2.sh", size: 151, mode: os.FileMode(420), modTime: time.Unix(1, 0)} a := &asset{bytes: bytes, info: info} return a, nil } @@ -225,10 +162,7 @@ func AssetNames() []string { // _bindata is a table, holding each asset generator, mapped to its name. var _bindata = map[string]func() (*asset, error){ "10-eksclt.al2.conf": _10EkscltAl2Conf, - "authenticator.sh": authenticatorSh, - "get_credentials.sh": get_credentialsSh, - "get_metadata.sh": get_metadataSh, - "kubeconfig.yaml": kubeconfigYaml, + "bootstrap.al2.sh": bootstrapAl2Sh, } // AssetDir returns the file names below a certain @@ -272,10 +206,7 @@ type bintree struct { } var _bintree = &bintree{nil, map[string]*bintree{ "10-eksclt.al2.conf": &bintree{_10EkscltAl2Conf, map[string]*bintree{}}, - "authenticator.sh": &bintree{authenticatorSh, map[string]*bintree{}}, - "get_credentials.sh": &bintree{get_credentialsSh, map[string]*bintree{}}, - "get_metadata.sh": &bintree{get_metadataSh, map[string]*bintree{}}, - "kubeconfig.yaml": &bintree{kubeconfigYaml, map[string]*bintree{}}, + "bootstrap.al2.sh": &bintree{bootstrapAl2Sh, map[string]*bintree{}}, }} // RestoreAsset restores an asset under the given directory diff --git a/pkg/nodebootstrap/assets/authenticator.sh b/pkg/nodebootstrap/assets/authenticator.sh deleted file mode 100755 index db193a523d..0000000000 --- a/pkg/nodebootstrap/assets/authenticator.sh +++ /dev/null @@ -1,8 +0,0 @@ -#!/bin/sh -eu - -# Simple wrapper for authenticator, so we can read AWS_EKS_CLUSTER_NAME from `metadata.env` -# instead of having to update `kubeconfig.yaml` (as `kubectl config` doesn't support plugin fields) - -. /etc/eksctl/metadata.env - -aws-iam-authenticator token -i "${AWS_EKS_CLUSTER_NAME}" \ No newline at end of file diff --git a/pkg/nodebootstrap/assets/bootstrap.al2.sh b/pkg/nodebootstrap/assets/bootstrap.al2.sh new file mode 100644 index 0000000000..1f1479566f --- /dev/null +++ b/pkg/nodebootstrap/assets/bootstrap.al2.sh @@ -0,0 +1,7 @@ +#!/bin/sh -eu + +echo "NODE_IP=$(hostname -i)" > /etc/eksctl/kubelet.local.env + +systemctl daemon-reload +systemctl enable kubelet +systemctl start kubelet diff --git a/pkg/nodebootstrap/assets/get_credentials.sh b/pkg/nodebootstrap/assets/get_credentials.sh deleted file mode 100644 index 8d601f331a..0000000000 --- a/pkg/nodebootstrap/assets/get_credentials.sh +++ /dev/null @@ -1,27 +0,0 @@ -#!/bin/bash - -# Obtain cluster credentials and update `kubeconfig.yaml` with apiserver URL - -set -o errexit -set -o pipefail -set -o nounset - -source /etc/eksctl/metadata.env - -export AWS_DEFAULT_REGION -export KUBECONFIG="/etc/eksctl/kubeconfig.yaml" - -describe_cluster() { - aws eks describe-cluster \ - --output json \ - --name "${AWS_EKS_CLUSTER_NAME}" -} - -clusterInfo="$(describe_cluster)" - -endpoint="$(echo "${clusterInfo}" | jq -r .cluster.endpoint)" - -echo "${clusterInfo}" | jq -r '.cluster.certificateAuthority.data' | base64 -d > /etc/eksctl/ca.crt - -kubectl config set-cluster kubernetes --server "${endpoint}" - diff --git a/pkg/nodebootstrap/assets/get_metadata.sh b/pkg/nodebootstrap/assets/get_metadata.sh deleted file mode 100644 index 893e27e1d1..0000000000 --- a/pkg/nodebootstrap/assets/get_metadata.sh +++ /dev/null @@ -1,50 +0,0 @@ -#!/bin/bash - -# Obtain metadata about the instance, parse eksctl tag value to and write out `metadata.env` and `kubelet.local.env` -# for other scripts and the systemd unit to use - -set -o errexit -set -o pipefail -set -o nounset - -# we could use the following, but we still need jq to get region and instance ID: -# aws --output text --region us-west-2 ec2 describe-tags --filters Name=resource-type,Values=instance Name=resource-id,Values=i-017e37452ee14d8d7 --query "Tags[?Key=='eksctl.cluster.k8s.io/v1alpha1/cluster-name'].Value" - -# TODO: avoid having to do all this – https://github.com/weaveworks/eksctl/issues/157 - -instanceInfo="$(curl --silent http://169.254.169.254/latest/dynamic/instance-identity/document)" - -instanceID="$(echo "${instanceInfo}" | jq -r .instanceId)" -instapceIP="$(echo "${instanceInfo}" | jq -r .privateIp)" - -AWS_DEFAULT_REGION="$(echo "${instanceInfo}" | jq -r .region)" - -export AWS_DEFAULT_REGION - -# metadata file is intended for other bash scripts as well as systemd units, so it's in simple format -echo "AWS_DEFAULT_REGION=${AWS_DEFAULT_REGION}" > /etc/eksctl/metadata.env - -echo "NODE_IP=${instapceIP}" > /etc/eksctl/kubelet.local.env - -get_tags() { - aws ec2 describe-tags \ - --output json \ - --filters "Name=resource-type,Values=instance" "Name=resource-id,Values=${instanceID}" -} - -get_cluster_name() { - jq -r '.Tags[] | select(.Key == "eksctl.cluster.k8s.io/v1alpha1/cluster-name") | .Value' -} - -check_cluster_owned() { - tag="kubernetes.io/cluster/${1}" - jq --arg tag "${tag}" -r '.Tags[] | select(.Key == $tag) | .Value' -} - -tags="$(get_tags)" - -cluster_name="$(echo "${tags}" | get_cluster_name)" - -test "$(echo "${tags}" | check_cluster_owned "${cluster_name}")" = "owned" - -echo "AWS_EKS_CLUSTER_NAME=${cluster_name}" >> /etc/eksctl/metadata.env \ No newline at end of file diff --git a/pkg/nodebootstrap/assets/kubeconfig.yaml b/pkg/nodebootstrap/assets/kubeconfig.yaml deleted file mode 100644 index 29d03721a7..0000000000 --- a/pkg/nodebootstrap/assets/kubeconfig.yaml +++ /dev/null @@ -1,21 +0,0 @@ -# Initial `kubeconfig.yaml` template -# `get_credentials.sh` writes out CA cert, and sets apiserver URL -# NOTE: these comments will not appear after this files gets updated -apiVersion: v1 -kind: Config -clusters: -- cluster: - certificate-authority: "/etc/eksctl/ca.crt" - name: kubernetes -contexts: -- name: kubelet - context: - cluster: kubernetes - user: kubelet -current-context: kubelet -users: -- name: kubelet - user: - exec: - apiVersion: client.authentication.k8s.io/v1alpha1 - command: /etc/eksctl/authenticator.sh \ No newline at end of file diff --git a/pkg/nodebootstrap/userdata.go b/pkg/nodebootstrap/userdata.go index 9110409214..b328db0d03 100644 --- a/pkg/nodebootstrap/userdata.go +++ b/pkg/nodebootstrap/userdata.go @@ -6,6 +6,7 @@ import ( "strings" "github.com/pkg/errors" + "k8s.io/client-go/tools/clientcmd" "github.com/kubicorn/kubicorn/pkg/logger" @@ -13,6 +14,7 @@ import ( "github.com/weaveworks/eksctl/pkg/cloudconfig" "github.com/weaveworks/eksctl/pkg/eks/api" + "github.com/weaveworks/eksctl/pkg/utils/kubeconfig" ) //go:generate go-bindata -pkg $GOPACKAGE -prefix assets -modtime 1 -o assets.go assets @@ -22,6 +24,13 @@ const ( kubeletDropInUnitDir = "/etc/systemd/system/kubelet.service.d/" ) +type configFile struct { + content string + isAsset bool +} + +type configFiles = map[string]map[string]configFile + func getAsset(name string) (string, os.FileInfo, error) { data, err := Asset(name) if err != nil { @@ -34,18 +43,23 @@ func getAsset(name string) (string, os.FileInfo, error) { return string(data), info, nil } -func addFilesAndScripts(config *cloudconfig.CloudConfig, files map[string][]string, scripts []string) error { +func addFilesAndScripts(config *cloudconfig.CloudConfig, files configFiles, scripts []string) error { for dir, fileNames := range files { - for _, fileName := range fileNames { - data, info, err := getAsset(fileName) - if err != nil { - return err + for fileName, file := range fileNames { + f := cloudconfig.File{ + Path: dir + fileName, + } + if file.isAsset { + data, info, err := getAsset(fileName) + if err != nil { + return err + } + f.Content = data + f.Permissions = fmt.Sprintf("%04o", uint(info.Mode())) + } else { + f.Content = file.content } - config.AddFile(cloudconfig.File{ - Path: dir + fileName, - Content: data, - Permissions: fmt.Sprintf("%04o", uint(info.Mode())), - }) + config.AddFile(f) } } for _, scriptName := range scripts { @@ -58,7 +72,7 @@ func addFilesAndScripts(config *cloudconfig.CloudConfig, files map[string][]stri return nil } -func setKubeletParams(config *cloudconfig.CloudConfig, spec *api.ClusterConfig) { +func makeAmazonLinux2Config(config *cloudconfig.CloudConfig, spec *api.ClusterConfig) (configFiles, error) { if spec.MaxPodsPerNode == 0 { spec.MaxPodsPerNode = maxPodsPerNodeType[spec.NodeType] } @@ -69,40 +83,51 @@ func setKubeletParams(config *cloudconfig.CloudConfig, spec *api.ClusterConfig) "CLUSTER_DNS=10.100.0.10", } - config.AddFile(cloudconfig.File{ - Path: configDir + "kubelet.env", - Content: strings.Join(kubeletParams, "\n"), - }) -} + metadata := []string{ + fmt.Sprintf("AWS_DEFAULT_REGION=%s", spec.Region), + fmt.Sprintf("AWS_EKS_CLUSTER_NAME=%s", spec.ClusterName), + fmt.Sprintf("AWS_EKS_ENDPOINT=%s", spec.Endpoint), + } -func NewUserDataForAmazonLinux2(spec *api.ClusterConfig) (*gfn.StringIntrinsic, error) { - config := cloudconfig.New() + clientConfig, _, _ := kubeconfig.New(spec, "kubelet", configDir+"ca.crt") + kubeconfig.AppendAuthenticator(clientConfig, spec, kubeconfig.AWSIAMAuthenticator) - scripts := []string{ - "get_metadata.sh", - "get_credentials.sh", + clientConfigData, err := clientcmd.Write(*clientConfig) + if err != nil { + return nil, errors.Wrap(err, "serialising kubeconfig for nodegroup") } - files := map[string][]string{ - configDir: { - "authenticator.sh", - "kubeconfig.yaml", - }, + + files := configFiles{ kubeletDropInUnitDir: { - "10-eksclt.al2.conf", + "10-eksclt.al2.conf": {isAsset: true}, + }, + configDir: { + "metadata.env": {content: strings.Join(metadata, "\n")}, + "kubelet.env": {content: strings.Join(kubeletParams, "\n")}, + // TODO: https://github.com/weaveworks/eksctl/issues/161 + "ca.crt": {content: string(spec.CertificateAuthorityData)}, + "kubeconfig.yaml": {content: string(clientConfigData)}, }, } - setKubeletParams(config, spec) + return files, nil +} - config.AddPackages("jq") - config.AddCommand("pip", "install", "--upgrade", "awscli") +func NewUserDataForAmazonLinux2(spec *api.ClusterConfig) (*gfn.StringIntrinsic, error) { + config := cloudconfig.New() - if err := addFilesAndScripts(config, files, scripts); err != nil { + scripts := []string{ + "bootstrap.al2.sh", + } + + files, err := makeAmazonLinux2Config(config, spec) + if err != nil { return nil, err } - config.AddCommand("systemctl", "daemon-reload") - config.AddCommand("systemctl", "restart", "kubelet") + if err := addFilesAndScripts(config, files, scripts); err != nil { + return nil, err + } body, err := config.Encode() if err != nil { diff --git a/pkg/utils/kubeconfig/kubeconfig.go b/pkg/utils/kubeconfig/kubeconfig.go index f23e24ae01..b120048deb 100644 --- a/pkg/utils/kubeconfig/kubeconfig.go +++ b/pkg/utils/kubeconfig/kubeconfig.go @@ -6,22 +6,73 @@ import ( "path" "strings" + "github.com/weaveworks/eksctl/pkg/eks/api" "github.com/weaveworks/eksctl/pkg/utils" "github.com/pkg/errors" "k8s.io/client-go/tools/clientcmd" - "k8s.io/client-go/tools/clientcmd/api" + clientcmdapi "k8s.io/client-go/tools/clientcmd/api" "github.com/kubicorn/kubicorn/pkg/logger" ) var DefaultPath = clientcmd.RecommendedHomeFile +const ( + HeptioAuthenticatorAWS = "heptio-authenticator-aws" + AWSIAMAuthenticator = "aws-iam-authenticator" +) + +// New creates Kubernetes client configuration for a given username +// if certificateAuthorityPath is no empty, it is used instead of +// embdedded certificate-authority-data +func New(spec *api.ClusterConfig, username, certificateAuthorityPath string) (*clientcmdapi.Config, string, string) { + clusterName := fmt.Sprintf("%s.%s.eksctl.io", spec.ClusterName, spec.Region) + contextName := fmt.Sprintf("%s@%s", username, clusterName) + + c := &clientcmdapi.Config{ + Clusters: map[string]*clientcmdapi.Cluster{ + clusterName: { + Server: spec.Endpoint, + }, + }, + Contexts: map[string]*clientcmdapi.Context{ + contextName: { + Cluster: clusterName, + AuthInfo: contextName, + }, + }, + AuthInfos: map[string]*clientcmdapi.AuthInfo{ + contextName: &clientcmdapi.AuthInfo{}, + }, + CurrentContext: contextName, + } + + if certificateAuthorityPath == "" { + c.Clusters[clusterName].CertificateAuthorityData = spec.CertificateAuthorityData + } else { + c.Clusters[clusterName].CertificateAuthority = certificateAuthorityPath + } + + return c, clusterName, contextName +} + +func AppendAuthenticator(c *clientcmdapi.Config, spec *api.ClusterConfig, command string) { + c.AuthInfos[c.CurrentContext].Exec = &clientcmdapi.ExecConfig{ + APIVersion: "client.authentication.k8s.io/v1alpha1", + Command: command, + Args: []string{"token", "-i", spec.ClusterName}, + /* + Args: []string{"token", "-i", c.Cluster.ClusterName, "-r", c.roleARN}, + */ + } +} + // Write will write Kubernetes client configuration to a file. // If path isn't specified then the path will be determined by client-go. // If file pointed to by path doesn't exist it will be created. // If the file already exists then the configuration will be merged with the existing file. -func Write(path string, newConfig *api.Config, setContext bool) (string, error) { +func Write(path string, newConfig *clientcmdapi.Config, setContext bool) (string, error) { configAccess := getConfigAccess(path) config, err := configAccess.GetStartingConfig() @@ -52,8 +103,7 @@ func getConfigAccess(explicitPath string) clientcmd.ConfigAccess { return interface{}(pathOptions).(clientcmd.ConfigAccess) } - -func merge(existing *api.Config, tomerge *api.Config) (*api.Config, error) { +func merge(existing *clientcmdapi.Config, tomerge *clientcmdapi.Config) (*clientcmdapi.Config, error) { for k, v := range tomerge.Clusters { existing.Clusters[k] = v }