Repository: kubernetes/kops (go)

Issue:
AWS: 1.26.x Broke kops export kubecfg when the existing cluster has DNS
/kind bug

**1. What `kops` version are you running? The command `kops version`, will display
 this information.**
1.26.2

**2. What Kubernetes version are you running? `kubectl version` will print the
 version if a cluster is running or provide the Kubernetes version specified as
 a `kops` flag.**
1.21.14

**3. What cloud provider are you using?**
AWS

**4. What commands did you run?  What is the simplest way to reproduce this issue?**
kops export kubecfg --admin=1h0m0s

**5. What happened after the commands executed?**
The exported kubeconfig file contains a reference to the ELB dns instead of the public API dns (which is an alias for the elb) but, the cluster certificate doesn't include the ELB name in the domains causing other commands such as `kops validate cluster` to fail because of it:
```
Error: Validation failed: unexpected error during validation: error listing nodes: Get "https://api-cluster-*********.us-east-1.elb.amazonaws.com/api/v1/nodes": x509: certificate is valid for kubernetes, kubernetes.default, kubernetes.default.svc, kubernetes.default.svc.cluster.local, api.cluster.domain, api.internal.cluster.domain, not api-cluster-********.us-east-1.elb.amazonaws.com
```

**6. What did you expect to happen?**
the exported kubeconfig when running `kops export kubecfg ...` to contain the valid DNS name of the cluster.

**7. Please provide your cluster manifest. Execute
  `kops get --name my.example.com -o yaml` to display your cluster manifest.
  You may want to remove your cluster name and other sensitive information.**

```yaml
ClusterName as positional argument is deprecated and will be removed in a future version

apiVersion: kops.k8s.io/v1alpha2
kind: Cluster
metadata:
  creationTimestamp: null
  name: cluster.domain
spec:
  additionalPolicies:
    master: |
      [
        {
          "Effect": "Allow",
          "Action": [
            "kms:Encrypt",
            "kms:Decrypt",
            "kms:ReEncrypt*",
            "kms:GenerateDataKey*",
            "kms:DescribeKey",
            "kms:CreateGrant",
            "kms:ListGrants",
            "kms:RevokeGrant"
          ],
          "Resource": [
            "arn:aws:kms:us-east-1:*:key/*"
          ]
        },
        {
          "Effect": "Allow",
          "Action": ["autoscaling:Describe*"],
          "Resource": "*"
        },
        {
          "Effect": "Allow",
          "Action": ["ec2:CreateTags"],
          "Resource": "arn:aws:ec2:*:*:volume/*"
        },
        {
          "Action": [
              "s3:GetBucketLocation"
          ],
          "Effect": "Allow",
          "Resource": [
              "arn:aws:s3:::logs-3rd-party-***-us-east-1",
              "arn:aws:s3:us-east-1:***:accesspoint/logs-3rd-party-k8saudit-us-east-1"
          ]
        },
        {
          "Action": [
              "s3:GetObject",
              "s3:PutObject",
              "s3:PutObjectAcl",
              "s3:AbortMultipartUpload",
              "s3:ListMultipartUploadParts"
          ],
          "Effect": "Allow",
          "Resource": [
              "arn:aws:s3:::logs-3rd-party-***-us-east-1/*",
              "arn:aws:s3:us-east-1:***:accesspoint/logs-3rd-party-k8saudit-us-east-1/*"
          ]
        },
        {
          "Effect": "Allow",
          "Action": [
              "ecr:GetAuthorizationToken",
              "ecr:BatchCheckLayerAvailability",
              "ecr:GetDownloadUrlForLayer",
              "ecr:GetRepositoryPolicy",
              "ecr:DescribeRepositories",
              "ecr:ListImages",
              "ecr:BatchGetImage"
          ],
          "Resource": [
              "*"
          ]
        },
        {
          "Effect": "Allow",
          "Action": [
              "firehose:PutRecordBatch"
          ],
          "Resource": [
              "*"
          ]
        }
      ]
    node: |
      [
        {
          "Action": ["sts:AssumeRole"],
          "Effect": "Allow",
          "Resource": "*"
        },
        {
          "Effect": "Allow",
          "Action": [
            "kms:Encrypt",
            "kms:Decrypt",
            "kms:ReEncrypt*",
            "kms:GenerateDataKey*",
            "kms:DescribeKey",
            "kms:CreateGrant",
            "kms:ListGrants",
            "kms:RevokeGrant"
          ],
          "Resource": [
            "arn:aws:kms:us-east-1:*:key/*"
          ]
        },
        {
          "Effect": "Allow",
          "Action": ["autoscaling:Describe*"],
          "Resource": "*"
        },
        {
          "Effect": "Allow",
          "Action": ["ec2:CreateTags"],
          "Resource": "arn:aws:ec2:*:*:volume/*"
        },
        {
          "Effect": "Allow",
          "Action": [
              "ecr:GetAuthorizationToken",
              "ecr:BatchCheckLayerAvailability",
              "ecr:GetDownloadUrlForLayer",
              "ecr:GetRepositoryPolicy",
              "ecr:DescribeRepositories",
              "ecr:ListImages",
              "ecr:BatchGetImage"
          ],
          "Resource": [
              "*"
          ]
        }
      ]
  addons:
  - manifest: s3://kops-cluster.domain/cluster.domain/addons/storageclass-gp2-wait-for-first-consumer.yaml
  api:
    loadBalancer:
      class: Classic
      type: Public
  authorization:
    rbac: {}
  channel: stable
  cloudLabels:
    Chargeback: base
    ClientId: shared
    Component: ***
    Department: "***"
    Environment: Development
    ManagedServiceLevel: Immutable Enhanced
    Product: ***
    cmapplication: ***
    cmenv: Development
    cmlayer: Infra
  cloudProvider: aws
  clusterAutoscaler:
    enabled: true
    memoryRequest: 1536Mi
  configBase: s3://kops-cluster.domain/cluster.domain
  etcdClusters:
  - etcdMembers:
    - encryptedVolume: true
      instanceGroup: master-us-east-1a
      name: a
    - encryptedVolume: true
      instanceGroup: master-us-east-1b
      name: b
    - encryptedVolume: true
      instanceGroup: master-us-east-1c
      name: c
    manager:
      env:
      - name: ETCD_LISTEN_METRICS_URLS
        value: http://0.0.0.0:2379
      - name: ETCD_METRICS
        value: extensive
    memoryRequest: 875Mi
    name: main
  - etcdMembers:
    - encryptedVolume: true
      instanceGroup: master-us-east-1a
      name: a
    - encryptedVolume: true
      instanceGroup: master-us-east-1b
      name: b
    - encryptedVolume: true
      instanceGroup: master-us-east-1c
      name: c
    memoryRequest: 300Mi
    name: events
  fileAssets:
  - content: |
      apiVersion: apiserver.k8s.io/v1alpha1
      kind: AdmissionConfiguration
      plugins:
      - name: EventRateLimit
        path: event-rate-limit.yaml
    name: admissionControl
    path: /srv/kubernetes/kube-apiserver/admission-control.yaml
    roles:
    - Master
  - content: |
      apiVersion: eventratelimit.admission.k8s.io/v1alpha1
      kind: Configuration
      limits:
      - type: Namespace
        qps: 100
        burst: 1000
        cacheSize: 2000
      - type: User
        qps: 100
        burst: 1000
    name: eventRateLimit
    path: /srv/kubernetes/kube-apiserver/event-rate-limit.yaml
    roles:
    - Master
  - content: |
      apiVersion: audit.k8s.io/v1 # This is required.
      kind: Policy
      # Don't generate audit events for all requests in RequestReceived stage.
      omitStages:
        - "RequestReceived"
      rules:
        # Log pod changes at RequestResponse level
        - level: RequestResponse
          resources:
          - group: ""
            # Resource "pods" doesn't match requests to any subresource of pods,
            # which is consistent with the RBAC policy.
            resources: ["pods"]
        # Log "pods/log", "pods/status" at Metadata level
        - level: Metadata
          resources:
          - group: ""
            resources: ["pods/log", "pods/status"]

        # Don't log requests to a configmap called "controller-leader"
        - level: None
          resources:
          - group: ""
            resources: ["configmaps"]
            resourceNames: ["controller-leader"]

        # Don't log watch requests by the "system:kube-proxy" on endpoints or services
        - level: None
          users: ["system:kube-proxy"]
          verbs: ["watch"]
          resources:
          - group: "" # core API group
            resources: ["endpoints", "services"]

        # Don't log authenticated requests to certain non-resource URL paths.
        - level: None
          userGroups: ["system:authenticated"]
          nonResourceURLs:
          - "/api*" # Wildcard matching.
          - "/version"

        # Log the request body of configmap changes in kube-system.
        - level: Request
          resources:
          - group: "" # core API group
            resources: ["configmaps"]
          # This rule only applies to resources in the "kube-system" namespace.
          # The empty string "" can be used to select non-namespaced resources.
          namespaces: ["kube-system"]

        # Log configmap and secret changes in all other namespaces at the Metadata level.
        - level: Metadata
          resources:
          - group: "" # core API group
            resources: ["secrets", "configmaps"]

        # Log all other resources in core and extensions at the Request level.
        - level: Request
          resources:
          - group: "" # core API group
          - group: "extensions" # Version of group should NOT be included.

        # A catch-all rule to log all other requests at the Metadata level.
        - level: Metadata
          # Long-running requests like watches that fall under this rule will not
          # generate an audit event in RequestReceived.
          omitStages:
            - "RequestReceived"
    name: kubeApiServerAdvancedAuditing
    path: /srv/kubernetes/kube-apiserver/audit-policy.yaml
    roles:
    - Master
  hooks:
  - manifest: |
      [Unit]
      Description=Manage Tenable Nessus Agent

      [Service]
      Type=oneshot
      RemainAfterExit=true

      ExecStartPre=curl https://***/public/nessus/agent/NessusAgent-10.0.1-ubuntu1110_amd64.deb --output /tmp/NessusAgent.deb
      ExecStartPre=dpkg -i /tmp/NessusAgent.deb
      ExecStartPre=rm /tmp/NessusAgent.deb
      ExecStart=systemctl start nessusagent.service
      ExecStartPost=/opt/nessus_agent/sbin/nessuscli agent link --cloud --key="***" --name="***$(hostname)" --groups="***,***,***,DEV,Scan1"

      TimeoutStopSec=15s
      ExecStop=/opt/nessus_agent/sbin/nessuscli agent unlink --force

      [Install]
      WantedBy=multi-user.target
    name: nessusagent-installer.service
    roles:
    - Node
    - Master
    useRawManifest: true
  - manifest: |
      [Unit]
      Description=Ensure rsyslog files are readable by fluent-bit
      Before=logrotate.service rsyslog.service

      [Service]
      Type=oneshot
      RemainAfterExit=yes

      ExecStartPre=mkdir -p /var/log/aide /var/log/clamav
      ExecStartPre=touch /var/log/aide/aide-scan.log /var/log/clamav/clamav-scan.log
      ExecStartPre=perl -pi -e 's,FileCreateMode .*,FileCreateMode 0644,' /etc/rsyslog.conf
      ExecStartPre=perl -pi -e 's,{,{\n\tcreate 0644 syslog adm,' /etc/logrotate.d/rsyslog
      ExecStart=find /var/log/ -type f -user syslog -exec chmod 0644 {} ';'

      [Install]
      WantedBy=multi-user.target
    name: rsyslog-fluentbit-permissions.service
    roles:
    - Node
    - Master
    useRawManifest: true
  iam:
    legacy: false
  kubeAPIServer:
    admissionControlConfigFile: /srv/kubernetes/kube-apiserver/admission-control.yaml
    auditLogMaxAge: 30
    auditLogMaxBackups: 10
    auditLogMaxSize: 100
    auditLogPath: /var/log/kube-apiserver-audit.log
    auditPolicyFile: /srv/kubernetes/kube-apiserver/audit-policy.yaml
    authorizationMode: Node,RBAC
    enableAdmissionPlugins:
    - AlwaysPullImages
    - DefaultStorageClass
    - DefaultTolerationSeconds
    - EventRateLimit
    - LimitRanger
    - NamespaceLifecycle
    - NodeRestriction
    - PersistentVolumeLabel
    - PodNodeSelector
    - PodTolerationRestriction
    - ResourceQuota
    - ServiceAccount
    featureGates:
      AdvancedAuditing: "true"
    memoryRequest: 2093796556800m
    oidcClientID: ***
    oidcGroupsClaim: groups
    oidcIssuerURL: https://***/oauth2/****
    oidcUsernameClaim: k8s_user
  kubeControllerManager:
    terminatedPodGCThreshold: 10
  kubeDNS:
    externalCoreFile: |-
      (global) {
        cache
        errors
        log . {
          class error
        }
        prometheus :9153
      }

      ec2.internal. {
        import global

        health :8084
        forward . 169.254.169.253
      }

      . {
        import global

        health {
          lameduck 5s
        }

        kubernetes cluster.local in-addr.arpa ip6.arpa {
          pods insecure
          fallthrough in-addr.arpa ip6.arpa
          ttl 30
        }

        loadbalance
        loop
        ready
        reload

        forward . 1.1.1.1 8.8.8.8 8.8.4.4 9.9.9.9
      }
    nodeLocalDNS:
      enabled: true
      forwardToKubeDNS: true
    provider: CoreDNS
  kubeProxy:
    metricsBindAddress: 0.0.0.0
  kubelet:
    anonymousAuth: false
    authenticationTokenWebhook: true
    authorizationMode: Webhook
    readOnlyPort: 0
    registryBurst: 100
    registryPullQPS: 20
    tlsCipherSuites:
    - TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256
    - TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256
    - TLS_ECDHE_ECDSA_WITH_CHACHA20_POLY1305
    - TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384
    - TLS_ECDHE_RSA_WITH_CHACHA20_POLY1305
    - TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384
    - TLS_RSA_WITH_AES_256_GCM_SHA384
  kubernetesApiAccess:
  - 0.0.0.0/0
  kubernetesVersion: 1.21.14
  masterInternalName: api.internal.cluster.domain
  masterPublicName: api.cluster.domain
  metricsServer:
    enabled: true
    insecure: true
  networkCIDR: 10.147.32.0/20
  networkID: vpc-***
  networking:
    flannel:
      backend: vxlan
  nodeTerminationHandler:
    enabled: true
  nonMasqueradeCIDR: 100.64.0.0/10
  sshAccess:
  - 0.0.0.0/0
  subnets:
  - cidr: 10.147.36.0/24
    id: subnet-***
    name: utility-us-east-1a
    type: Utility
    zone: us-east-1a
  - cidr: 10.147.37.0/24
    id: subnet-***
    name: utility-us-east-1b
    type: Utility
    zone: us-east-1b
  - cidr: 10.147.38.0/24
    id: subnet-***
    name: utility-us-east-1c
    type: Utility
    zone: us-east-1c
  - cidr: 10.147.32.0/24
    egress: nat-***
    id: subnet-***
    name: us-east-1a
    type: Private
    zone: us-east-1a
  - cidr: 10.147.33.0/24
    egress: nat-***
    id: subnet-***
    name: us-east-1b
    type: Private
    zone: us-east-1b
  - cidr: 10.147.34.0/24
    egress: nat-***
    id: subnet-***
    name: us-east-1c
    type: Private
    zone: us-east-1c
  topology:
    bastion:
      bastionPublicName: bastion.cluster.domain
    dns:
      type: Public
    masters: private
    nodes: private

---

apiVersion: kops.k8s.io/v1alpha2
kind: InstanceGroup
metadata:
  creationTimestamp: "2023-04-28T14:26:42Z"
  labels:
    kops.k8s.io/cluster: cluster.domain
  name: master-us-east-1a
spec:
  cloudLabels:
    LayerDetail: kubernetes-master
  image: ubuntu/ubuntu/images/hvm-ssd/ubuntu-focal-20.04-amd64-server-20230302
  machineType: m6a.large
  maxSize: 1
  minSize: 1
  role: Master
  rootVolumeOptimization: true
  subnets:
  - us-east-1a
  sysctlParameters:
  - net.ipv6.conf.all.disable_ipv6=1
  - net.ipv6.conf.default.disable_ipv6=1

---

apiVersion: kops.k8s.io/v1alpha2
kind: InstanceGroup
metadata:
  creationTimestamp: "2023-04-28T14:26:42Z"
  labels:
    kops.k8s.io/cluster: cluster.domain
  name: master-us-east-1b
spec:
  cloudLabels:
    LayerDetail: kubernetes-master
  image: ubuntu/ubuntu/images/hvm-ssd/ubuntu-focal-20.04-amd64-server-20230302
  machineType: m6a.large
  maxSize: 1
  minSize: 1
  role: Master
  rootVolumeOptimization: true
  subnets:
  - us-east-1b
  sysctlParameters:
  - net.ipv6.conf.all.disable_ipv6=1
  - net.ipv6.conf.default.disable_ipv6=1

---

apiVersion: kops.k8s.io/v1alpha2
kind: InstanceGroup
metadata:
  creationTimestamp: "2023-04-28T14:26:42Z"
  labels:
    kops.k8s.io/cluster: cluster.domain
  name: master-us-east-1c
spec:
  cloudLabels:
    LayerDetail: kubernetes-master
  image: ubuntu/ubuntu/images/hvm-ssd/ubuntu-focal-20.04-amd64-server-20230302
  machineType: m6a.large
  maxSize: 1
  minSize: 1
  role: Master
  rootVolumeOptimization: true
  subnets:
  - us-east-1c
  sysctlParameters:
  - net.ipv6.conf.all.disable_ipv6=1
  - net.ipv6.conf.default.disable_ipv6=1

---

apiVersion: kops.k8s.io/v1alpha2
kind: InstanceGroup
metadata:
  creationTimestamp: "2023-04-28T14:26:42Z"
  labels:
    kops.k8s.io/cluster: cluster.domain
  name: nodes-us-east-1a
spec:
  cloudLabels:
    LayerDetail: kubernetes-node
    k8s.io/cluster-autoscaler/cluster.domain: "1"
    k8s.io/cluster-autoscaler/enabled: "1"
  image: ubuntu/ubuntu/images/hvm-ssd/ubuntu-focal-20.04-amd64-server-20230302
  maxSize: 4
  minSize: 2
  mixedInstancesPolicy:
    instances:
    - m6a.2xlarge
    - m6i.2xlarge
    - m5.2xlarge
    - m5a.2xlarge
    - m5d.2xlarge
    - m5zn.2xlarge
    - m6id.2xlarge
    - r5.2xlarge
    - r5a.2xlarge
    - r5ad.2xlarge
    - r5b.2xlarge
    - r5d.2xlarge
    - r5dn.2xlarge
    - r5n.2xlarge
    - r6a.2xlarge
    - r6i.2xlarge
    - r6id.2xlarge
    - t3.2xlarge
    - t3a.2xlarge
    onDemandAboveBase: 0
    onDemandBase: 1
    spotAllocationStrategy: capacity-optimized
  nodeLabels:
    autoscalegroup: nodes
    kops.k8s.io/instancegroup: nodes-us-east-1a
  role: Node
  rollingUpdate:
    maxSurge: 50%
  rootVolumeOptimization: true
  rootVolumeSize: 100
  subnets:
  - us-east-1a
  sysctlParameters:
  - net.core.dev_weight=3072
  - net.core.netdev_budget=12288
  - net.core.somaxconn=65536
  - net.ipv6.conf.all.disable_ipv6=1
  - net.ipv6.conf.default.disable_ipv6=1
  - net.netfilter.nf_conntrack_expect_max=2048

---

apiVersion: kops.k8s.io/v1alpha2
kind: InstanceGroup
metadata:
  creationTimestamp: "2023-04-28T14:26:43Z"
  labels:
    kops.k8s.io/cluster: cluster.domain
  name: nodes-us-east-1b
spec:
  cloudLabels:
    LayerDetail: kubernetes-node
    k8s.io/cluster-autoscaler/cluster.domain: "1"
    k8s.io/cluster-autoscaler/enabled: "1"
  image: ubuntu/ubuntu/images/hvm-ssd/ubuntu-focal-20.04-amd64-server-20230302
  maxSize: 4
  minSize: 2
  mixedInstancesPolicy:
    instances:
    - m6a.2xlarge
    - m6i.2xlarge
    - m5.2xlarge
    - m5a.2xlarge
    - m5d.2xlarge
    - m5zn.2xlarge
    - m6id.2xlarge
    - r5.2xlarge
    - r5a.2xlarge
    - r5ad.2xlarge
    - r5b.2xlarge
    - r5d.2xlarge
    - r5dn.2xlarge
    - r5n.2xlarge
    - r6a.2xlarge
    - r6i.2xlarge
    - r6id.2xlarge
    - t3.2xlarge
    - t3a.2xlarge
    onDemandAboveBase: 0
    onDemandBase: 1
    spotAllocationStrategy: capacity-optimized
  nodeLabels:
    autoscalegroup: nodes
    kops.k8s.io/instancegroup: nodes-us-east-1b
  role: Node
  rollingUpdate:
    maxSurge: 50%
  rootVolumeOptimization: true
  rootVolumeSize: 100
  subnets:
  - us-east-1b
  sysctlParameters:
  - net.core.dev_weight=3072
  - net.core.netdev_budget=12288
  - net.core.somaxconn=65536
  - net.ipv6.conf.all.disable_ipv6=1
  - net.ipv6.conf.default.disable_ipv6=1
  - net.netfilter.nf_conntrack_expect_max=2048

---

apiVersion: kops.k8s.io/v1alpha2
kind: InstanceGroup
metadata:
  creationTimestamp: "2023-04-28T14:26:43Z"
  labels:
    kops.k8s.io/cluster: cluster.domain
  name: nodes-us-east-1c
spec:
  cloudLabels:
    LayerDetail: kubernetes-node
    k8s.io/cluster-autoscaler/cluster.domain: "1"
    k8s.io/cluster-autoscaler/enabled: "1"
  image: ubuntu/ubuntu/images/hvm-ssd/ubuntu-focal-20.04-amd64-server-20230302
  maxSize: 4
  minSize: 2
  mixedInstancesPolicy:
    instances:
    - m6a.2xlarge
    - m6i.2xlarge
    - m5.2xlarge
    - m5a.2xlarge
    - m5d.2xlarge
    - m5zn.2xlarge
    - m6id.2xlarge
    - r5.2xlarge
    - r5a.2xlarge
    - r5ad.2xlarge
    - r5b.2xlarge
    - r5d.2xlarge
    - r5dn.2xlarge
    - r5n.2xlarge
    - r6a.2xlarge
    - r6i.2xlarge
    - r6id.2xlarge
    - t3.2xlarge
    - t3a.2xlarge
    onDemandAboveBase: 0
    onDemandBase: 1
    spotAllocationStrategy: capacity-optimized
  nodeLabels:
    autoscalegroup: nodes
    kops.k8s.io/instancegroup: nodes-us-east-1c
  role: Node
  rollingUpdate:
    maxSurge: 50%
  rootVolumeOptimization: true
  rootVolumeSize: 100
  subnets:
  - us-east-1c
  sysctlParameters:
  - net.core.dev_weight=3072
  - net.core.netdev_budget=12288
  - net.core.somaxconn=65536
  - net.ipv6.conf.all.disable_ipv6=1
  - net.ipv6.conf.default.disable_ipv6=1
  - net.netfilter.nf_conntrack_expect_max=2048
```

**8. Please run the commands with most verbose logging by adding the `-v 10` flag.
  Paste the logs into this report, or in a gist and provide the gist link here.**

**9. Anything else do we need to know?**


Pull request:
Use API internal name as TLS server name in kubeconfig
Adds `tls-server-name: api.internal.<CLUSTER_NAME>` to the `kubeconfig` entry.

Closes #15354

Patch:
diff --git a/pkg/kubeconfig/create_kubecfg.go b/pkg/kubeconfig/create_kubecfg.go
index 1b151ac74e..09ebed5972 100644
--- a/pkg/kubeconfig/create_kubecfg.go
+++ b/pkg/kubeconfig/create_kubecfg.go
@@ -85,6 +85,7 @@ func BuildKubecfg(ctx context.Context, cluster *kops.Cluster, keyStore fi.Keysto
 
 	b.Context = clusterName
 	b.Server = server
+	b.TLSServerName = cluster.APIInternalName()
 
 	// add the CA Cert to the kubeconfig only if we didn't specify a certificate for the LB
 	//  or if we're using admin credentials and the secondary port
diff --git a/pkg/kubeconfig/kubecfg_builder.go b/pkg/kubeconfig/kubecfg_builder.go
index 0220791681..e12421828c 100644
--- a/pkg/kubeconfig/kubecfg_builder.go
+++ b/pkg/kubeconfig/kubecfg_builder.go
@@ -19,7 +19,6 @@ package kubeconfig
 import (
 	"fmt"
 
-	"k8s.io/client-go/rest"
 	"k8s.io/client-go/tools/clientcmd"
 	clientcmdapi "k8s.io/client-go/tools/clientcmd/api"
 	"k8s.io/klog/v2"
@@ -28,7 +27,8 @@ import (
 // KubeconfigBuilder builds a kubecfg file
 // This logic previously lives in the bash scripts (create-kubeconfig in cluster/common.sh)
 type KubeconfigBuilder struct {
-	Server string
+	Server        string
+	TLSServerName string
 
 	Context   string
 	Namespace string
@@ -77,20 +77,6 @@ func (b *KubeconfigBuilder) DeleteKubeConfig(configAccess clientcmd.ConfigAccess
 	return nil
 }
 
-// Create new Rest Client
-func (c *KubeconfigBuilder) BuildRestConfig() (*rest.Config, error) {
-	restConfig := &rest.Config{
-		Host: c.Server,
-	}
-	restConfig.CAData = c.CACerts
-	restConfig.CertData = c.ClientCert
-	restConfig.KeyData = c.ClientKey
-	restConfig.Username = c.KubeUser
-	restConfig.Password = c.KubePassword
-
-	return restConfig, nil
-}
-
 // Write out a new kubeconfig
 func (b *KubeconfigBuilder) WriteKubecfg(configAccess clientcmd.ConfigAccess) error {
 	config, err := configAccess.GetStartingConfig()
@@ -108,6 +94,7 @@ func (b *KubeconfigBuilder) WriteKubecfg(configAccess clientcmd.ConfigAccess) er
 			cluster = clientcmdapi.NewCluster()
 		}
 		cluster.Server = b.Server
+		cluster.TLSServerName = b.TLSServerName
 		cluster.CertificateAuthorityData = b.CACerts
 
 		if config.Clusters == nil {


Test patch:
diff --git a/pkg/kubeconfig/create_kubecfg_test.go b/pkg/kubeconfig/create_kubecfg_test.go
index e8338f74bb..0b068491c7 100644
--- a/pkg/kubeconfig/create_kubecfg_test.go
+++ b/pkg/kubeconfig/create_kubecfg_test.go
@@ -191,10 +191,11 @@ func TestBuildKubecfg(t *testing.T) {
 				user:    "",
 			},
 			want: &KubeconfigBuilder{
-				Context: "testcluster",
-				Server:  "https://testcluster.test.com",
-				CACerts: []byte(nextCertificate + certData),
-				User:    "testcluster",
+				Context:       "testcluster",
+				Server:        "https://testcluster.test.com",
+				TLSServerName: "api.internal.testcluster",
+				CACerts:       []byte(nextCertificate + certData),
+				User:          "testcluster",
 			},
 			wantClientCert: true,
 		},
@@ -206,10 +207,11 @@ func TestBuildKubecfg(t *testing.T) {
 				admin:   DefaultKubecfgAdminLifetime,
 			},
 			want: &KubeconfigBuilder{
-				Context: "testcluster",
-				Server:  "https://elbHostName:8443",
-				CACerts: []byte(nextCertificate + certData),
-				User:    "testcluster",
+				Context:       "testcluster",
+				Server:        "https://elbHostName:8443",
+				TLSServerName: "api.internal.testcluster",
+				CACerts:       []byte(nextCertificate + certData),
+				User:          "testcluster",
 			},
 			wantClientCert: true,
 		},
@@ -221,10 +223,11 @@ func TestBuildKubecfg(t *testing.T) {
 				admin:   DefaultKubecfgAdminLifetime,
 			},
 			want: &KubeconfigBuilder{
-				Context: "testcluster",
-				Server:  "https://elbHostName",
-				CACerts: nil,
-				User:    "testcluster",
+				Context:       "testcluster",
+				Server:        "https://elbHostName",
+				TLSServerName: "api.internal.testcluster",
+				CACerts:       nil,
+				User:          "testcluster",
 			},
 			wantClientCert: true,
 		},
@@ -236,10 +239,11 @@ func TestBuildKubecfg(t *testing.T) {
 				admin:   0,
 			},
 			want: &KubeconfigBuilder{
-				Context: "testcluster",
-				Server:  "https://testcluster.test.com",
-				CACerts: []byte(nextCertificate + certData),
-				User:    "testcluster",
+				Context:       "testcluster",
+				Server:        "https://testcluster.test.com",
+				TLSServerName: "api.internal.testcluster",
+				CACerts:       []byte(nextCertificate + certData),
+				User:          "testcluster",
 			},
 			wantClientCert: false,
 		},
@@ -252,10 +256,11 @@ func TestBuildKubecfg(t *testing.T) {
 				user:    "myuser",
 			},
 			want: &KubeconfigBuilder{
-				Context: "testcluster",
-				Server:  "https://testcluster.test.com",
-				CACerts: []byte(nextCertificate + certData),
-				User:    "myuser",
+				Context:       "testcluster",
+				Server:        "https://testcluster.test.com",
+				TLSServerName: "api.internal.testcluster",
+				CACerts:       []byte(nextCertificate + certData),
+				User:          "myuser",
 			},
 			wantClientCert: false,
 		},
@@ -268,10 +273,11 @@ func TestBuildKubecfg(t *testing.T) {
 				user:    "",
 			},
 			want: &KubeconfigBuilder{
-				Context: "emptyMasterPublicNameCluster",
-				Server:  "https://api.emptyMasterPublicNameCluster",
-				CACerts: []byte(nextCertificate + certData),
-				User:    "emptyMasterPublicNameCluster",
+				Context:       "emptyMasterPublicNameCluster",
+				Server:        "https://api.emptyMasterPublicNameCluster",
+				TLSServerName: "api.internal.emptyMasterPublicNameCluster",
+				CACerts:       []byte(nextCertificate + certData),
+				User:          "emptyMasterPublicNameCluster",
 			},
 			wantClientCert: false,
 		},
@@ -282,10 +288,11 @@ func TestBuildKubecfg(t *testing.T) {
 				status:  fakeStatus,
 			},
 			want: &KubeconfigBuilder{
-				Context: "testgossipcluster.k8s.local",
-				Server:  "https://elbHostName",
-				CACerts: []byte(nextCertificate + certData),
-				User:    "testgossipcluster.k8s.local",
+				Context:       "testgossipcluster.k8s.local",
+				Server:        "https://elbHostName",
+				TLSServerName: "api.internal.testgossipcluster.k8s.local",
+				CACerts:       []byte(nextCertificate + certData),
+				User:          "testgossipcluster.k8s.local",
 			},
 			wantClientCert: false,
 		},
@@ -298,10 +305,11 @@ func TestBuildKubecfg(t *testing.T) {
 				useKopsAuthenticationPlugin: true,
 			},
 			want: &KubeconfigBuilder{
-				Context: "testcluster",
-				Server:  "https://testcluster.test.com",
-				CACerts: []byte(nextCertificate + certData),
-				User:    "testcluster",
+				Context:       "testcluster",
+				Server:        "https://testcluster.test.com",
+				TLSServerName: "api.internal.testcluster",
+				CACerts:       []byte(nextCertificate + certData),
+				User:          "testcluster",
 				AuthenticationExec: []string{
 					"kops",
 					"helpers",
@@ -321,10 +329,11 @@ func TestBuildKubecfg(t *testing.T) {
 				internal: true,
 			},
 			want: &KubeconfigBuilder{
-				Context: "testcluster",
-				Server:  "https://api.internal.testcluster",
-				CACerts: []byte(nextCertificate + certData),
-				User:    "testcluster",
+				Context:       "testcluster",
+				Server:        "https://api.internal.testcluster",
+				TLSServerName: "api.internal.testcluster",
+				CACerts:       []byte(nextCertificate + certData),
+				User:          "testcluster",
 			},
 			wantClientCert: true,
 		},
@@ -336,10 +345,11 @@ func TestBuildKubecfg(t *testing.T) {
 				admin:   DefaultKubecfgAdminLifetime,
 			},
 			want: &KubeconfigBuilder{
-				Context: "testgossipcluster.k8s.local",
-				Server:  "https://elbHostName:8443",
-				CACerts: []byte(nextCertificate + certData),
-				User:    "testgossipcluster.k8s.local",
+				Context:       "testgossipcluster.k8s.local",
+				Server:        "https://elbHostName:8443",
+				TLSServerName: "api.internal.testgossipcluster.k8s.local",
+				CACerts:       []byte(nextCertificate + certData),
+				User:          "testgossipcluster.k8s.local",
 			},
 			wantClientCert: true,
 		},
@@ -352,10 +362,11 @@ func TestBuildKubecfg(t *testing.T) {
 				internal: true,
 			},
 			want: &KubeconfigBuilder{
-				Context: "testcluster",
-				Server:  "https://api.internal.testcluster",
-				CACerts: []byte(nextCertificate + certData),
-				User:    "testcluster",
+				Context:       "testcluster",
+				Server:        "https://api.internal.testcluster",
+				TLSServerName: "api.internal.testcluster",
+				CACerts:       []byte(nextCertificate + certData),
+				User:          "testcluster",
 			},
 			wantClientCert: true,
 		},
@@ -368,10 +379,11 @@ func TestBuildKubecfg(t *testing.T) {
 				internal: true,
 			},
 			want: &KubeconfigBuilder{
-				Context: "testcluster",
-				Server:  "https://api.internal.testcluster",
-				CACerts: []byte(nextCertificate + certData),
-				User:    "testcluster",
+				Context:       "testcluster",
+				Server:        "https://api.internal.testcluster",
+				TLSServerName: "api.internal.testcluster",
+				CACerts:       []byte(nextCertificate + certData),
+				User:          "testcluster",
 			},
 			wantClientCert: false,
 		},