diff --git a/cmd/kops-controller/pkg/server/server.go b/cmd/kops-controller/pkg/server/server.go index 2feb3c97ac..f9a9911ca1 100644 --- a/cmd/kops-controller/pkg/server/server.go +++ b/cmd/kops-controller/pkg/server/server.go @@ -203,7 +203,7 @@ func (s *Server) issueCert(name string, pubKey string, id *fi.VerifyResult, vali issueReq.Subject = pkix.Name{ CommonName: id.NodeName, } - issueReq.AlternateNames = []string{id.NodeName} + issueReq.AlternateNames = id.CertificateNames issueReq.Type = "server" case "kube-proxy": issueReq.Subject = pkix.Name{ diff --git a/nodeup/pkg/model/kubelet.go b/nodeup/pkg/model/kubelet.go index 38b273cb18..2e7054236c 100644 --- a/nodeup/pkg/model/kubelet.go +++ b/nodeup/pkg/model/kubelet.go @@ -18,6 +18,8 @@ package model import ( "fmt" + "net" + "os" "path" "path/filepath" @@ -25,6 +27,7 @@ import ( "github.com/aws/aws-sdk-go/aws/ec2metadata" "github.com/aws/aws-sdk-go/aws/session" + "github.com/aws/aws-sdk-go/service/ec2" v1 "k8s.io/api/core/v1" "k8s.io/klog/v2" @@ -560,7 +563,7 @@ func (b *KubeletBuilder) buildKubeletServingCertificate(c *fi.ModelBuilderContex name := "kubelet-server" dir := b.PathSrvKubernetes() - nodeName, err := b.NodeName() + names, err := b.kubeletNames() if err != nil { return err } @@ -594,9 +597,9 @@ func (b *KubeletBuilder) buildKubeletServingCertificate(c *fi.ModelBuilderContex KeypairID: b.NodeupConfig.KeypairIDs[fi.CertificateIDCA], Type: "server", Subject: nodetasks.PKIXName{ - CommonName: nodeName, + CommonName: names[0], }, - AlternateNames: []string{nodeName}, + AlternateNames: names, } c.AddTask(issueCert) return issueCert.AddFileTasks(c, dir, name, "", nil) @@ -605,3 +608,27 @@ func (b *KubeletBuilder) buildKubeletServingCertificate(c *fi.ModelBuilderContex return nil } + +func (b *KubeletBuilder) kubeletNames() ([]string, error) { + if kops.CloudProviderID(b.Cluster.Spec.CloudProvider) != kops.CloudProviderAWS { + name, err := os.Hostname() + if err != nil { + return nil, err + } + + addrs, _ := net.LookupHost(name) + + return append(addrs, name), nil + } + + cloud := b.Cloud.(awsup.AWSCloud) + + result, err := cloud.EC2().DescribeInstances(&ec2.DescribeInstancesInput{ + InstanceIds: []*string{&b.InstanceID}, + }) + if err != nil { + return nil, fmt.Errorf("error describing instances: %v", err) + } + + return awsup.GetInstanceCertificateNames(result) +} diff --git a/upup/pkg/fi/authenticate.go b/upup/pkg/fi/authenticate.go index 3e02adee8f..92ef79be97 100644 --- a/upup/pkg/fi/authenticate.go +++ b/upup/pkg/fi/authenticate.go @@ -28,6 +28,9 @@ type VerifyResult struct { // InstanceGroupName is the name of the kops InstanceGroup this node is a member of. InstanceGroupName string + + // CertificateNames is the names the node is authorized to use for certificates. + CertificateNames []string } // Verifier verifies authentication credentials for requests. diff --git a/upup/pkg/fi/cloudup/awsup/aws_cloud.go b/upup/pkg/fi/cloudup/awsup/aws_cloud.go index 27d33df5b4..0a70257e12 100644 --- a/upup/pkg/fi/cloudup/awsup/aws_cloud.go +++ b/upup/pkg/fi/cloudup/awsup/aws_cloud.go @@ -2069,3 +2069,40 @@ func GetRolesInInstanceProfile(c AWSCloud, profileName string) ([]string, error) } return roleNames, nil } + +// GetInstanceCertificateNames returns the instance hostname and addresses that should go into certificates. +// The first value is the node name and any additional values are IP addresses. +func GetInstanceCertificateNames(instances *ec2.DescribeInstancesOutput) (addrs []string, err error) { + + if len(instances.Reservations) != 1 { + return nil, fmt.Errorf("too many reservations returned for the single instance-id") + } + + if len(instances.Reservations[0].Instances) != 1 { + return nil, fmt.Errorf("too many instances returned for the single instance-id") + } + + instance := instances.Reservations[0].Instances[0] + + name := *instance.PrivateDnsName + + addrs = append(addrs, name) + + // We only use data for the first interface, and only the first IP + for _, iface := range instance.NetworkInterfaces { + if iface.Attachment == nil { + continue + } + if *iface.Attachment.DeviceIndex != 0 { + continue + } + addrs = append(addrs, *iface.PrivateIpAddress) + if iface.Ipv6Addresses != nil && len(iface.Ipv6Addresses) > 0 { + addrs = append(addrs, *iface.Ipv6Addresses[0].Ipv6Address) + } + if iface.Association.PublicIp != nil { + addrs = append(addrs, *iface.Association.PublicIp) + } + } + return addrs, nil +} diff --git a/upup/pkg/fi/cloudup/awsup/aws_verifier.go b/upup/pkg/fi/cloudup/awsup/aws_verifier.go index 40899b5472..9d5196922f 100644 --- a/upup/pkg/fi/cloudup/awsup/aws_verifier.go +++ b/upup/pkg/fi/cloudup/awsup/aws_verifier.go @@ -232,8 +232,14 @@ func (a awsVerifier) VerifyToken(token string, body []byte) (*fi.VerifyResult, e instance := instances.Reservations[0].Instances[0] + addrs, err := GetInstanceCertificateNames(instances) + if err != nil { + return nil, err + } + result := &fi.VerifyResult{ - NodeName: aws.StringValue(instance.PrivateDnsName), + NodeName: addrs[0], + CertificateNames: addrs, } for _, tag := range instance.Tags {