diff --git a/nodeup/pkg/model/context.go b/nodeup/pkg/model/context.go index deadf36c2913c..72490a4869b05 100644 --- a/nodeup/pkg/model/context.go +++ b/nodeup/pkg/model/context.go @@ -27,7 +27,6 @@ import ( "k8s.io/kops/pkg/apis/kops" "k8s.io/kops/pkg/apis/kops/util" "k8s.io/kops/pkg/apis/nodeup" - "k8s.io/kops/pkg/kubeconfig" "k8s.io/kops/pkg/systemd" "k8s.io/kops/upup/pkg/fi" "k8s.io/kops/upup/pkg/fi/nodeup/nodetasks" @@ -193,6 +192,33 @@ func (c *NodeupModelContext) KubeletKubeConfig() string { return "/var/lib/kubelet/kubeconfig" } +// BuildIssuedKubeconfig generates a kubeconfig with a locally issued client certificate. +func (c *NodeupModelContext) BuildIssuedKubeconfig(name string, subject nodetasks.PKIXName, ctx *fi.ModelBuilderContext) *fi.TaskDependentResource { + issueCert := &nodetasks.IssueCert{ + Name: name, + Signer: fi.CertificateIDCA, + Type: "client", + Subject: subject, + } + ctx.AddTask(issueCert) + certResource, keyResource, caResource := issueCert.GetResources() + + kubeConfig := &nodetasks.KubeConfig{ + Name: name, + Cert: certResource, + Key: keyResource, + CA: caResource, + } + if c.IsMaster { + // @note: use https even for local connections, so we can turn off the insecure port + kubeConfig.ServerURL = "https://127.0.0.1" + } else { + kubeConfig.ServerURL = "https://" + c.Cluster.Spec.MasterInternalName + } + ctx.AddTask(kubeConfig) + return kubeConfig.GetConfig() +} + // BuildPKIKubeconfig generates a kubeconfig func (c *NodeupModelContext) BuildPKIKubeconfig(name string) (string, error) { ca, err := c.GetCert(fi.CertificateIDCA) @@ -215,54 +241,29 @@ func (c *NodeupModelContext) BuildPKIKubeconfig(name string) (string, error) { // BuildKubeConfig is responsible for building a kubeconfig func (c *NodeupModelContext) BuildKubeConfig(username string, ca, certificate, privateKey []byte) (string, error) { - user := kubeconfig.KubectlUser{ - ClientCertificateData: certificate, - ClientKeyData: privateKey, + kubeConfig := &nodetasks.KubeConfig{ + Name: username, + Cert: fi.NewBytesResource(certificate), + Key: fi.NewBytesResource(privateKey), + CA: fi.NewBytesResource(ca), } - cluster := kubeconfig.KubectlCluster{ - CertificateAuthorityData: ca, - } - if c.IsMaster { // @note: use https even for local connections, so we can turn off the insecure port - cluster.Server = "https://127.0.0.1" + kubeConfig.ServerURL = "https://127.0.0.1" } else { - cluster.Server = "https://" + c.Cluster.Spec.MasterInternalName - } - - config := &kubeconfig.KubectlConfig{ - ApiVersion: "v1", - Kind: "Config", - Users: []*kubeconfig.KubectlUserWithName{ - { - Name: username, - User: user, - }, - }, - Clusters: []*kubeconfig.KubectlClusterWithName{ - { - Name: "local", - Cluster: cluster, - }, - }, - Contexts: []*kubeconfig.KubectlContextWithName{ - { - Name: "service-account-context", - Context: kubeconfig.KubectlContext{ - Cluster: "local", - User: username, - }, - }, - }, - CurrentContext: "service-account-context", - } - - yaml, err := kops.ToRawYaml(config) + kubeConfig.ServerURL = "https://" + c.Cluster.Spec.MasterInternalName + } + + err := kubeConfig.Run(nil) if err != nil { - return "", fmt.Errorf("error marshaling kubeconfig to yaml: %v", err) + return "", err } - return string(yaml), nil + config, err := fi.ResourceAsString(kubeConfig.GetConfig()) + if err != nil { + return "", err + } + return config, nil } // IsKubernetesGTE checks if the version is greater-than-or-equal diff --git a/nodeup/pkg/model/etcd_manager_tls.go b/nodeup/pkg/model/etcd_manager_tls.go index 686def5fd0c33..1be28370ba050 100644 --- a/nodeup/pkg/model/etcd_manager_tls.go +++ b/nodeup/pkg/model/etcd_manager_tls.go @@ -17,7 +17,6 @@ limitations under the License. package model import ( - "crypto/x509/pkix" "fmt" "k8s.io/kops/upup/pkg/fi" @@ -77,7 +76,7 @@ func (b *EtcdManagerTLSBuilder) buildKubeAPIServerKeypair(c *fi.ModelBuilderCont Name: name, Signer: "etcd-clients-ca", Type: "client", - Subject: pkix.Name{ + Subject: nodetasks.PKIXName{ CommonName: "kube-apiserver", }, } diff --git a/nodeup/pkg/model/kube_apiserver_healthcheck.go b/nodeup/pkg/model/kube_apiserver_healthcheck.go index 7647a5459b66f..57cabe306509b 100644 --- a/nodeup/pkg/model/kube_apiserver_healthcheck.go +++ b/nodeup/pkg/model/kube_apiserver_healthcheck.go @@ -17,7 +17,6 @@ limitations under the License. package model import ( - "crypto/x509/pkix" "fmt" corev1 "k8s.io/api/core/v1" @@ -86,7 +85,7 @@ func (b *KubeAPIServerBuilder) addHealthcheckSidecarTasks(c *fi.ModelBuilderCont Name: id, Signer: fi.CertificateIDCA, Type: "client", - Subject: pkix.Name{ + Subject: nodetasks.PKIXName{ CommonName: id, }, } diff --git a/nodeup/pkg/model/kube_controller_manager.go b/nodeup/pkg/model/kube_controller_manager.go index 1e77161210b8b..c37d51060bec9 100644 --- a/nodeup/pkg/model/kube_controller_manager.go +++ b/nodeup/pkg/model/kube_controller_manager.go @@ -25,6 +25,7 @@ import ( "k8s.io/kops/pkg/flagbuilder" "k8s.io/kops/pkg/k8scodecs" "k8s.io/kops/pkg/kubemanifest" + "k8s.io/kops/pkg/rbac" "k8s.io/kops/upup/pkg/fi" "k8s.io/kops/upup/pkg/fi/nodeup/nodetasks" "k8s.io/kops/util/pkg/exec" @@ -85,14 +86,10 @@ func (b *KubeControllerManagerBuilder) Build(c *fi.ModelBuilderContext) error { // Add kubeconfig { - // @TODO: Change kubeconfig to be https - kubeconfig, err := b.BuildPKIKubeconfig("kube-controller-manager") - if err != nil { - return err - } + kubeconfig := b.BuildIssuedKubeconfig("kube-controller-manager", nodetasks.PKIXName{CommonName: rbac.KubeControllerManager}, c) c.AddTask(&nodetasks.File{ Path: "/var/lib/kube-controller-manager/kubeconfig", - Contents: fi.NewStringResource(kubeconfig), + Contents: kubeconfig, Type: nodetasks.FileType_File, Mode: s("0400"), }) diff --git a/nodeup/pkg/model/kube_scheduler.go b/nodeup/pkg/model/kube_scheduler.go index 4b2b2fc8ffcfe..593360cf4a20c 100644 --- a/nodeup/pkg/model/kube_scheduler.go +++ b/nodeup/pkg/model/kube_scheduler.go @@ -24,6 +24,7 @@ import ( "k8s.io/kops/pkg/flagbuilder" "k8s.io/kops/pkg/k8scodecs" "k8s.io/kops/pkg/kubemanifest" + "k8s.io/kops/pkg/rbac" "k8s.io/kops/upup/pkg/fi" "k8s.io/kops/upup/pkg/fi/nodeup/nodetasks" "k8s.io/kops/util/pkg/exec" @@ -83,14 +84,11 @@ func (b *KubeSchedulerBuilder) Build(c *fi.ModelBuilderContext) error { } { - kubeconfig, err := b.BuildPKIKubeconfig("kube-scheduler") - if err != nil { - return err - } + kubeconfig := b.BuildIssuedKubeconfig("kube-scheduler", nodetasks.PKIXName{CommonName: rbac.KubeScheduler}, c) c.AddTask(&nodetasks.File{ Path: "/var/lib/kube-scheduler/kubeconfig", - Contents: fi.NewStringResource(kubeconfig), + Contents: kubeconfig, Type: nodetasks.FileType_File, Mode: s("0400"), }) diff --git a/nodeup/pkg/model/networking/cilium.go b/nodeup/pkg/model/networking/cilium.go index 0fd5925bf76a9..d5befd63c3e98 100644 --- a/nodeup/pkg/model/networking/cilium.go +++ b/nodeup/pkg/model/networking/cilium.go @@ -17,7 +17,6 @@ limitations under the License. package networking import ( - "crypto/x509/pkix" "fmt" "golang.org/x/sys/unix" @@ -128,7 +127,7 @@ func (b *CiliumBuilder) buildCiliumEtcdSecrets(c *fi.ModelBuilderContext) error Name: name, Signer: "etcd-clients-ca-cilium", Type: "client", - Subject: pkix.Name{ + Subject: nodetasks.PKIXName{ CommonName: "cilium", }, } diff --git a/nodeup/pkg/model/tests/golden/minimal/tasks-kube-controller-manager.yaml b/nodeup/pkg/model/tests/golden/minimal/tasks-kube-controller-manager.yaml index f982a733e836f..aaf61b582be8d 100644 --- a/nodeup/pkg/model/tests/golden/minimal/tasks-kube-controller-manager.yaml +++ b/nodeup/pkg/model/tests/golden/minimal/tasks-kube-controller-manager.yaml @@ -163,25 +163,31 @@ mode: "0600" path: /srv/kubernetes/ca.key type: file --- -contents: | - apiVersion: v1 - clusters: - - cluster: - certificate-authority-data: LS0tLS1CRUdJTiBDRVJUSUZJQ0FURS0tLS0tCk1JSUMyRENDQWNDZ0F3SUJBZ0lSQUxKWEFrVmo5NjR0cTY3d01TSThvSlF3RFFZSktvWklodmNOQVFFTEJRQXcKRlRFVE1CRUdBMVVFQXhNS2EzVmlaWEp1WlhSbGN6QWVGdzB4TnpFeU1qY3lNelV5TkRCYUZ3MHlOekV5TWpjeQpNelV5TkRCYU1CVXhFekFSQmdOVkJBTVRDbXQxWW1WeWJtVjBaWE13Z2dFaU1BMEdDU3FHU0liM0RRRUJBUVVBCkE0SUJEd0F3Z2dFS0FvSUJBUURnbkNrU210bm1meEVnUzNxTlBhVUNINVFPQkdESC9pbkhiV0NPRExCQ0s5Z2QKWEVjQmw3RlZ2OFQya0ZyMURZYjBIVkR0TUk3dGl4UlZGRExna3dObFczNHh3V2RaWEI3R2VvRmdVMXhXT1FTWQpPQUNDOEpnWVRRLzEzOUhCRXZncTRzZWo2N3ArL3MvU05jdzM0S2s3SEl1RmhsazFyUms1a01leEtJbEpCS1AxCllZVVlldHNKL1FwVU9rcUo1SFc0R29ldEU3Nll0SG5PUmZZdm55YnZpU01yaDJ3R0dhTjZyL3M0Q2hPYUliWkMKQW44L1lpUEtHSURhWkdwajZHWG5tWEFSUlgvVElkZ1NRa0x3dDBhVERCblBaNFh2dHBJOGFhTDhEWUpJcUF6QQpOUEgyYjQvdU55bGF0NWpEbzBiMEc1NGFnTWk5NysyQVVyQzlVVVhwQWdNQkFBR2pJekFoTUE0R0ExVWREd0VCCi93UUVBd0lCQmpBUEJnTlZIUk1CQWY4RUJUQURBUUgvTUEwR0NTcUdTSWIzRFFFQkN3VUFBNElCQVFCVkdSMnIKaHpYelJNVTV3cmlQUUFKU2Nzek5PUnZvQnBYZlpvWjA5Rkl1cHVkRnhCVlUzZDRoVjlTdEtuUWdQU0dBNVhRTwpIRTk3K0J4SkR1QS9yQjVvQlVzTUJqYzd5MWNkZS9UNmhtaTNyTG9FWUJTblN1ZENPWEpFNEc5LzBmOGJ5QUplCnJOOCtObzFyMlZnWnZaaDZwNzRURWtYdi9sM0hCUFdNN0lkVVYwSE85SkRoU2dPVkYxZnlRS0p4UnVMSlI4anQKTzZtUEgyVVgwdk13VmE0anZ3dGtkZHFrMk9BZFlRdkg5cmJEampiemFpVzBLbm1kdWVSbzkyS0hBTjdCc0RaeQpWcFhIcHFvMUt6ZzdEM2ZwYVhDZjVzaTdscXFyZEpWWEg0SkM3Mnp4c1BlaHFnaThlSXVxT0JraURXbVJ4QXhoCjh5R2VSeDlBYmtuSGg0SWEKLS0tLS1FTkQgQ0VSVElGSUNBVEUtLS0tLQo= - server: https://127.0.0.1 - name: local - contexts: - - context: - cluster: local - user: kube-controller-manager - name: service-account-context - current-context: service-account-context - kind: Config - users: - - name: kube-controller-manager - user: - client-certificate-data: LS0tLS1CRUdJTiBDRVJUSUZJQ0FURS0tLS0tCk1JSUMyRENDQWNDZ0F3SUJBZ0lSQUxKWEFrVmo5NjR0cTY3d01TSThvSlF3RFFZSktvWklodmNOQVFFTEJRQXcKRlRFVE1CRUdBMVVFQXhNS2EzVmlaWEp1WlhSbGN6QWVGdzB4TnpFeU1qY3lNelV5TkRCYUZ3MHlOekV5TWpjeQpNelV5TkRCYU1CVXhFekFSQmdOVkJBTVRDbXQxWW1WeWJtVjBaWE13Z2dFaU1BMEdDU3FHU0liM0RRRUJBUVVBCkE0SUJEd0F3Z2dFS0FvSUJBUURnbkNrU210bm1meEVnUzNxTlBhVUNINVFPQkdESC9pbkhiV0NPRExCQ0s5Z2QKWEVjQmw3RlZ2OFQya0ZyMURZYjBIVkR0TUk3dGl4UlZGRExna3dObFczNHh3V2RaWEI3R2VvRmdVMXhXT1FTWQpPQUNDOEpnWVRRLzEzOUhCRXZncTRzZWo2N3ArL3MvU05jdzM0S2s3SEl1RmhsazFyUms1a01leEtJbEpCS1AxCllZVVlldHNKL1FwVU9rcUo1SFc0R29ldEU3Nll0SG5PUmZZdm55YnZpU01yaDJ3R0dhTjZyL3M0Q2hPYUliWkMKQW44L1lpUEtHSURhWkdwajZHWG5tWEFSUlgvVElkZ1NRa0x3dDBhVERCblBaNFh2dHBJOGFhTDhEWUpJcUF6QQpOUEgyYjQvdU55bGF0NWpEbzBiMEc1NGFnTWk5NysyQVVyQzlVVVhwQWdNQkFBR2pJekFoTUE0R0ExVWREd0VCCi93UUVBd0lCQmpBUEJnTlZIUk1CQWY4RUJUQURBUUgvTUEwR0NTcUdTSWIzRFFFQkN3VUFBNElCQVFCVkdSMnIKaHpYelJNVTV3cmlQUUFKU2Nzek5PUnZvQnBYZlpvWjA5Rkl1cHVkRnhCVlUzZDRoVjlTdEtuUWdQU0dBNVhRTwpIRTk3K0J4SkR1QS9yQjVvQlVzTUJqYzd5MWNkZS9UNmhtaTNyTG9FWUJTblN1ZENPWEpFNEc5LzBmOGJ5QUplCnJOOCtObzFyMlZnWnZaaDZwNzRURWtYdi9sM0hCUFdNN0lkVVYwSE85SkRoU2dPVkYxZnlRS0p4UnVMSlI4anQKTzZtUEgyVVgwdk13VmE0anZ3dGtkZHFrMk9BZFlRdkg5cmJEampiemFpVzBLbm1kdWVSbzkyS0hBTjdCc0RaeQpWcFhIcHFvMUt6ZzdEM2ZwYVhDZjVzaTdscXFyZEpWWEg0SkM3Mnp4c1BlaHFnaThlSXVxT0JraURXbVJ4QXhoCjh5R2VSeDlBYmtuSGg0SWEKLS0tLS1FTkQgQ0VSVElGSUNBVEUtLS0tLQo= - client-key-data: LS0tLS1CRUdJTiBSU0EgUFJJVkFURSBLRVktLS0tLQpNSUlFcEFJQkFBS0NBUUVBNEp3cEVwclo1bjhSSUV0NmpUMmxBaCtVRGdSZ3gvNHB4MjFnamd5d1FpdllIVnhICkFaZXhWYi9FOXBCYTlRMkc5QjFRN1RDTzdZc1VWUlF5NEpNRFpWdCtNY0ZuV1Z3ZXhucUJZRk5jVmprRW1EZ0EKZ3ZDWUdFMFA5ZC9Sd1JMNEt1TEhvK3U2ZnY3UDBqWE1OK0NwT3h5TGhZWlpOYTBaT1pESHNTaUpTUVNqOVdHRgpHSHJiQ2YwS1ZEcEtpZVIxdUJxSHJSTyttTFI1emtYMkw1OG03NGtqSzRkc0JobWplcS83T0FvVG1pRzJRZ0ovClAySWp5aGlBMm1ScVkraGw1NWx3RVVWLzB5SFlFa0pDOExkR2t3d1p6MmVGNzdhU1BHbWkvQTJDU0tnTXdEVHgKOW0rUDdqY3BXcmVZdzZORzlCdWVHb0RJdmUvdGdGS3d2VkZGNlFJREFRQUJBb0lCQUEwa3RqYVRmeXJBeHNUSQpCZXpiN1pyNU5CVzU1ZHZ1SUkyOTljZDZNSm8rckkvVFJZaHZVdjQ4a1k4SUZYcC9oeVVqemdlREx1bnhtSWY5Ci9aZ3NvaWM5T2w0NC9nNDVtTWR1aGNHWVB6QUFlQ2RjSjVPQjlyUjlWZkRDWHlqWUxsTjhIOGlVMDczNHRUcU0KMFYxM3RROXpkU3FrR1BaT0ljcS9rUi9weWxiT1phUU1lOTdCVGxzQW5PTVNNS0RnbmZ0WTQxMjJMcTNHWXkrdAp2cHIrYktWYVFad3ZrTG9TVTNyRUNDYUthZ2hnd0N5WDdqZnQ5YUVraGRKditLbHdic0dZNldFcnZ4T2FMV0hkCmN1TVFqR2FwWTFGYS80VUQwMG12ckEyNjBOeUtmenJwNitQNDZSclZNd0VZUkpNSVE4WUJBazZONkhoN2RjMEcKOFo2aTFtMENnWUVBOUhlQ0pSMFRTd2JJUTFiRFhVcnpwZnRIdWlkRzVCblNCdGF4L05EOXFJUGhSL0ZCVzVuagoyMm53TGM0OEtreWlybGZJVUxkMGFlNHFWWEpuN3dmWWN1WC9jSk1MRG1TVnRsTTVEem1pLzkxeFJpRmdJengxCkFzYkJ6YUZqSVNQMkhwU2dMK2U5RnRTWGFhcWVaVnJmbGl0VmhZS1VwSS9BS1YzMXFHSGYwNHNDZ1lFQTZ6VFYKOTlTYjQ5V2RsbnM1SWdzZm5YbDZUb1J0dEIxOGxmRUtjVmZqQU00ZnJua2swNkpwRkFaZVIrOUdHS1VYWkhxcwp6MnFjcGx3NGQvbW9DQzZwM3JZUEJNTFhzckdORVVGWnFCbGd6NzJRQTZCQnEzWDBDZzFCYzJaYks1Vkl6d2tnClNUMlNTdXg2Y2NST2ZnVUxtTjVaaUxPdGRVS05FWnBGRjNpM3F0c0NnWUFEVC9zN2RZRmxhdG9iejNrbU1uWEsKc2ZUdTJNbGxIZFJ5czBZR0h1N1E4YmlEdVFraHJKd2h4UFcwS1M4M2c0SlF5bSswYUVmemgzNmJXY2wrdTZSNwpLaEtqKzlvU2Y5cG5kZ2szNDVnSnozNVJiUEpZaCtFdUFITnZ6ZGdDQXZLNngxakVUV2VLZjZidGo1cEYxVTFpClE0UU5Jdy9RaXdJWGpXWmV1YlRHc1FLQmdRQ2JkdUx1MnJMbmx5eUFhSlpNOERsSFp5SDJnQVhiQlpweHFVOFQKdDltdGtKRFVTL0tSaUVvWUdGVjlDcVMwYVhyYXlWTXNEZlhZNkIvUy9VdVpqTzV1N0x0a2xEenFPZjFhS0czUQpkR1hQS2lia25xcUpZSCtiblVOanVZWU5lckVUVjU3bGlqTUdIdVNZQ2Y4dndMbjNveEJmRVJSWDYxTS9EVThaCndvcnovUUtCZ1FEQ1RKSTIramRYZzI2WHVZVW1NNFhYZm5vY2Z6QVhoWEJVTHQxbkVOY29nTmYxZmNwdEFWdHUKQkFpejQvSGlwUUtxb1dWVVlteGZnYmJMUktLTEswczBsT1dLYllkVmpoRW0vbTJaVTh3dFhUYWdOd2tJR295cQpZL0MxTG94NGYxUk9KbkNqYy9oZmNPamN4WDVNOEE4cGVlY0hXbFZ0VVBLVEpneFE3b01LY3c9PQotLS0tLUVORCBSU0EgUFJJVkFURSBLRVktLS0tLQo= +contents: + task: + CA: + task: + Name: kube-controller-manager + signer: ca + subject: + CommonName: system:kube-controller-manager + type: client + Cert: + task: + Name: kube-controller-manager + signer: ca + subject: + CommonName: system:kube-controller-manager + type: client + Key: + task: + Name: kube-controller-manager + signer: ca + subject: + CommonName: system:kube-controller-manager + type: client + Name: kube-controller-manager + ServerURL: https://127.0.0.1 mode: "0400" path: /var/lib/kube-controller-manager/kubeconfig type: file @@ -191,3 +197,33 @@ ifNotExists: true mode: "0400" path: /var/log/kube-controller-manager.log type: file +--- +Name: kube-controller-manager +signer: ca +subject: + CommonName: system:kube-controller-manager +type: client +--- +CA: + task: + Name: kube-controller-manager + signer: ca + subject: + CommonName: system:kube-controller-manager + type: client +Cert: + task: + Name: kube-controller-manager + signer: ca + subject: + CommonName: system:kube-controller-manager + type: client +Key: + task: + Name: kube-controller-manager + signer: ca + subject: + CommonName: system:kube-controller-manager + type: client +Name: kube-controller-manager +ServerURL: https://127.0.0.1 diff --git a/nodeup/pkg/model/tests/golden/minimal/tasks-kube-scheduler.yaml b/nodeup/pkg/model/tests/golden/minimal/tasks-kube-scheduler.yaml index c60da0493f3c4..7d40f1afea867 100644 --- a/nodeup/pkg/model/tests/golden/minimal/tasks-kube-scheduler.yaml +++ b/nodeup/pkg/model/tests/golden/minimal/tasks-kube-scheduler.yaml @@ -63,25 +63,31 @@ mode: "0400" path: /var/lib/kube-scheduler/config.yaml type: file --- -contents: | - apiVersion: v1 - clusters: - - cluster: - certificate-authority-data: LS0tLS1CRUdJTiBDRVJUSUZJQ0FURS0tLS0tCk1JSUMyRENDQWNDZ0F3SUJBZ0lSQUxKWEFrVmo5NjR0cTY3d01TSThvSlF3RFFZSktvWklodmNOQVFFTEJRQXcKRlRFVE1CRUdBMVVFQXhNS2EzVmlaWEp1WlhSbGN6QWVGdzB4TnpFeU1qY3lNelV5TkRCYUZ3MHlOekV5TWpjeQpNelV5TkRCYU1CVXhFekFSQmdOVkJBTVRDbXQxWW1WeWJtVjBaWE13Z2dFaU1BMEdDU3FHU0liM0RRRUJBUVVBCkE0SUJEd0F3Z2dFS0FvSUJBUURnbkNrU210bm1meEVnUzNxTlBhVUNINVFPQkdESC9pbkhiV0NPRExCQ0s5Z2QKWEVjQmw3RlZ2OFQya0ZyMURZYjBIVkR0TUk3dGl4UlZGRExna3dObFczNHh3V2RaWEI3R2VvRmdVMXhXT1FTWQpPQUNDOEpnWVRRLzEzOUhCRXZncTRzZWo2N3ArL3MvU05jdzM0S2s3SEl1RmhsazFyUms1a01leEtJbEpCS1AxCllZVVlldHNKL1FwVU9rcUo1SFc0R29ldEU3Nll0SG5PUmZZdm55YnZpU01yaDJ3R0dhTjZyL3M0Q2hPYUliWkMKQW44L1lpUEtHSURhWkdwajZHWG5tWEFSUlgvVElkZ1NRa0x3dDBhVERCblBaNFh2dHBJOGFhTDhEWUpJcUF6QQpOUEgyYjQvdU55bGF0NWpEbzBiMEc1NGFnTWk5NysyQVVyQzlVVVhwQWdNQkFBR2pJekFoTUE0R0ExVWREd0VCCi93UUVBd0lCQmpBUEJnTlZIUk1CQWY4RUJUQURBUUgvTUEwR0NTcUdTSWIzRFFFQkN3VUFBNElCQVFCVkdSMnIKaHpYelJNVTV3cmlQUUFKU2Nzek5PUnZvQnBYZlpvWjA5Rkl1cHVkRnhCVlUzZDRoVjlTdEtuUWdQU0dBNVhRTwpIRTk3K0J4SkR1QS9yQjVvQlVzTUJqYzd5MWNkZS9UNmhtaTNyTG9FWUJTblN1ZENPWEpFNEc5LzBmOGJ5QUplCnJOOCtObzFyMlZnWnZaaDZwNzRURWtYdi9sM0hCUFdNN0lkVVYwSE85SkRoU2dPVkYxZnlRS0p4UnVMSlI4anQKTzZtUEgyVVgwdk13VmE0anZ3dGtkZHFrMk9BZFlRdkg5cmJEampiemFpVzBLbm1kdWVSbzkyS0hBTjdCc0RaeQpWcFhIcHFvMUt6ZzdEM2ZwYVhDZjVzaTdscXFyZEpWWEg0SkM3Mnp4c1BlaHFnaThlSXVxT0JraURXbVJ4QXhoCjh5R2VSeDlBYmtuSGg0SWEKLS0tLS1FTkQgQ0VSVElGSUNBVEUtLS0tLQo= - server: https://127.0.0.1 - name: local - contexts: - - context: - cluster: local - user: kube-scheduler - name: service-account-context - current-context: service-account-context - kind: Config - users: - - name: kube-scheduler - user: - client-certificate-data: LS0tLS1CRUdJTiBDRVJUSUZJQ0FURS0tLS0tCk1JSUMyRENDQWNDZ0F3SUJBZ0lSQUxKWEFrVmo5NjR0cTY3d01TSThvSlF3RFFZSktvWklodmNOQVFFTEJRQXcKRlRFVE1CRUdBMVVFQXhNS2EzVmlaWEp1WlhSbGN6QWVGdzB4TnpFeU1qY3lNelV5TkRCYUZ3MHlOekV5TWpjeQpNelV5TkRCYU1CVXhFekFSQmdOVkJBTVRDbXQxWW1WeWJtVjBaWE13Z2dFaU1BMEdDU3FHU0liM0RRRUJBUVVBCkE0SUJEd0F3Z2dFS0FvSUJBUURnbkNrU210bm1meEVnUzNxTlBhVUNINVFPQkdESC9pbkhiV0NPRExCQ0s5Z2QKWEVjQmw3RlZ2OFQya0ZyMURZYjBIVkR0TUk3dGl4UlZGRExna3dObFczNHh3V2RaWEI3R2VvRmdVMXhXT1FTWQpPQUNDOEpnWVRRLzEzOUhCRXZncTRzZWo2N3ArL3MvU05jdzM0S2s3SEl1RmhsazFyUms1a01leEtJbEpCS1AxCllZVVlldHNKL1FwVU9rcUo1SFc0R29ldEU3Nll0SG5PUmZZdm55YnZpU01yaDJ3R0dhTjZyL3M0Q2hPYUliWkMKQW44L1lpUEtHSURhWkdwajZHWG5tWEFSUlgvVElkZ1NRa0x3dDBhVERCblBaNFh2dHBJOGFhTDhEWUpJcUF6QQpOUEgyYjQvdU55bGF0NWpEbzBiMEc1NGFnTWk5NysyQVVyQzlVVVhwQWdNQkFBR2pJekFoTUE0R0ExVWREd0VCCi93UUVBd0lCQmpBUEJnTlZIUk1CQWY4RUJUQURBUUgvTUEwR0NTcUdTSWIzRFFFQkN3VUFBNElCQVFCVkdSMnIKaHpYelJNVTV3cmlQUUFKU2Nzek5PUnZvQnBYZlpvWjA5Rkl1cHVkRnhCVlUzZDRoVjlTdEtuUWdQU0dBNVhRTwpIRTk3K0J4SkR1QS9yQjVvQlVzTUJqYzd5MWNkZS9UNmhtaTNyTG9FWUJTblN1ZENPWEpFNEc5LzBmOGJ5QUplCnJOOCtObzFyMlZnWnZaaDZwNzRURWtYdi9sM0hCUFdNN0lkVVYwSE85SkRoU2dPVkYxZnlRS0p4UnVMSlI4anQKTzZtUEgyVVgwdk13VmE0anZ3dGtkZHFrMk9BZFlRdkg5cmJEampiemFpVzBLbm1kdWVSbzkyS0hBTjdCc0RaeQpWcFhIcHFvMUt6ZzdEM2ZwYVhDZjVzaTdscXFyZEpWWEg0SkM3Mnp4c1BlaHFnaThlSXVxT0JraURXbVJ4QXhoCjh5R2VSeDlBYmtuSGg0SWEKLS0tLS1FTkQgQ0VSVElGSUNBVEUtLS0tLQo= - client-key-data: LS0tLS1CRUdJTiBSU0EgUFJJVkFURSBLRVktLS0tLQpNSUlFcEFJQkFBS0NBUUVBNEp3cEVwclo1bjhSSUV0NmpUMmxBaCtVRGdSZ3gvNHB4MjFnamd5d1FpdllIVnhICkFaZXhWYi9FOXBCYTlRMkc5QjFRN1RDTzdZc1VWUlF5NEpNRFpWdCtNY0ZuV1Z3ZXhucUJZRk5jVmprRW1EZ0EKZ3ZDWUdFMFA5ZC9Sd1JMNEt1TEhvK3U2ZnY3UDBqWE1OK0NwT3h5TGhZWlpOYTBaT1pESHNTaUpTUVNqOVdHRgpHSHJiQ2YwS1ZEcEtpZVIxdUJxSHJSTyttTFI1emtYMkw1OG03NGtqSzRkc0JobWplcS83T0FvVG1pRzJRZ0ovClAySWp5aGlBMm1ScVkraGw1NWx3RVVWLzB5SFlFa0pDOExkR2t3d1p6MmVGNzdhU1BHbWkvQTJDU0tnTXdEVHgKOW0rUDdqY3BXcmVZdzZORzlCdWVHb0RJdmUvdGdGS3d2VkZGNlFJREFRQUJBb0lCQUEwa3RqYVRmeXJBeHNUSQpCZXpiN1pyNU5CVzU1ZHZ1SUkyOTljZDZNSm8rckkvVFJZaHZVdjQ4a1k4SUZYcC9oeVVqemdlREx1bnhtSWY5Ci9aZ3NvaWM5T2w0NC9nNDVtTWR1aGNHWVB6QUFlQ2RjSjVPQjlyUjlWZkRDWHlqWUxsTjhIOGlVMDczNHRUcU0KMFYxM3RROXpkU3FrR1BaT0ljcS9rUi9weWxiT1phUU1lOTdCVGxzQW5PTVNNS0RnbmZ0WTQxMjJMcTNHWXkrdAp2cHIrYktWYVFad3ZrTG9TVTNyRUNDYUthZ2hnd0N5WDdqZnQ5YUVraGRKditLbHdic0dZNldFcnZ4T2FMV0hkCmN1TVFqR2FwWTFGYS80VUQwMG12ckEyNjBOeUtmenJwNitQNDZSclZNd0VZUkpNSVE4WUJBazZONkhoN2RjMEcKOFo2aTFtMENnWUVBOUhlQ0pSMFRTd2JJUTFiRFhVcnpwZnRIdWlkRzVCblNCdGF4L05EOXFJUGhSL0ZCVzVuagoyMm53TGM0OEtreWlybGZJVUxkMGFlNHFWWEpuN3dmWWN1WC9jSk1MRG1TVnRsTTVEem1pLzkxeFJpRmdJengxCkFzYkJ6YUZqSVNQMkhwU2dMK2U5RnRTWGFhcWVaVnJmbGl0VmhZS1VwSS9BS1YzMXFHSGYwNHNDZ1lFQTZ6VFYKOTlTYjQ5V2RsbnM1SWdzZm5YbDZUb1J0dEIxOGxmRUtjVmZqQU00ZnJua2swNkpwRkFaZVIrOUdHS1VYWkhxcwp6MnFjcGx3NGQvbW9DQzZwM3JZUEJNTFhzckdORVVGWnFCbGd6NzJRQTZCQnEzWDBDZzFCYzJaYks1Vkl6d2tnClNUMlNTdXg2Y2NST2ZnVUxtTjVaaUxPdGRVS05FWnBGRjNpM3F0c0NnWUFEVC9zN2RZRmxhdG9iejNrbU1uWEsKc2ZUdTJNbGxIZFJ5czBZR0h1N1E4YmlEdVFraHJKd2h4UFcwS1M4M2c0SlF5bSswYUVmemgzNmJXY2wrdTZSNwpLaEtqKzlvU2Y5cG5kZ2szNDVnSnozNVJiUEpZaCtFdUFITnZ6ZGdDQXZLNngxakVUV2VLZjZidGo1cEYxVTFpClE0UU5Jdy9RaXdJWGpXWmV1YlRHc1FLQmdRQ2JkdUx1MnJMbmx5eUFhSlpNOERsSFp5SDJnQVhiQlpweHFVOFQKdDltdGtKRFVTL0tSaUVvWUdGVjlDcVMwYVhyYXlWTXNEZlhZNkIvUy9VdVpqTzV1N0x0a2xEenFPZjFhS0czUQpkR1hQS2lia25xcUpZSCtiblVOanVZWU5lckVUVjU3bGlqTUdIdVNZQ2Y4dndMbjNveEJmRVJSWDYxTS9EVThaCndvcnovUUtCZ1FEQ1RKSTIramRYZzI2WHVZVW1NNFhYZm5vY2Z6QVhoWEJVTHQxbkVOY29nTmYxZmNwdEFWdHUKQkFpejQvSGlwUUtxb1dWVVlteGZnYmJMUktLTEswczBsT1dLYllkVmpoRW0vbTJaVTh3dFhUYWdOd2tJR295cQpZL0MxTG94NGYxUk9KbkNqYy9oZmNPamN4WDVNOEE4cGVlY0hXbFZ0VVBLVEpneFE3b01LY3c9PQotLS0tLUVORCBSU0EgUFJJVkFURSBLRVktLS0tLQo= +contents: + task: + CA: + task: + Name: kube-scheduler + signer: ca + subject: + CommonName: system:kube-scheduler + type: client + Cert: + task: + Name: kube-scheduler + signer: ca + subject: + CommonName: system:kube-scheduler + type: client + Key: + task: + Name: kube-scheduler + signer: ca + subject: + CommonName: system:kube-scheduler + type: client + Name: kube-scheduler + ServerURL: https://127.0.0.1 mode: "0400" path: /var/lib/kube-scheduler/kubeconfig type: file @@ -91,3 +97,33 @@ ifNotExists: true mode: "0400" path: /var/log/kube-scheduler.log type: file +--- +Name: kube-scheduler +signer: ca +subject: + CommonName: system:kube-scheduler +type: client +--- +CA: + task: + Name: kube-scheduler + signer: ca + subject: + CommonName: system:kube-scheduler + type: client +Cert: + task: + Name: kube-scheduler + signer: ca + subject: + CommonName: system:kube-scheduler + type: client +Key: + task: + Name: kube-scheduler + signer: ca + subject: + CommonName: system:kube-scheduler + type: client +Name: kube-scheduler +ServerURL: https://127.0.0.1 diff --git a/pkg/model/pki.go b/pkg/model/pki.go index 5eaccef53c92e..6ecaed3466bd5 100644 --- a/pkg/model/pki.go +++ b/pkg/model/pki.go @@ -72,16 +72,6 @@ func (b *PKIModelBuilder) Build(c *fi.ModelBuilderContext) error { Signer: defaultCA, }) } - { - t := &fitasks.Keypair{ - Name: fi.String("kube-scheduler"), - Lifecycle: b.Lifecycle, - Subject: "cn=" + rbac.KubeScheduler, - Type: "client", - Signer: defaultCA, - } - c.AddTask(t) - } { t := &fitasks.Keypair{ @@ -94,17 +84,6 @@ func (b *PKIModelBuilder) Build(c *fi.ModelBuilderContext) error { c.AddTask(t) } - { - t := &fitasks.Keypair{ - Name: fi.String("kube-controller-manager"), - Lifecycle: b.Lifecycle, - Subject: "cn=" + rbac.KubeControllerManager, - Type: "client", - Signer: defaultCA, - } - c.AddTask(t) - } - if b.UseEtcdManager() { // We generate keypairs in the etcdmanager task itself } else if b.UseEtcdTLS() { diff --git a/pkg/testutils/modelharness.go b/pkg/testutils/modelharness.go index d67bf501c57a9..498392b8ccfe7 100644 --- a/pkg/testutils/modelharness.go +++ b/pkg/testutils/modelharness.go @@ -97,4 +97,7 @@ func ValidateTasks(t *testing.T, expectedFile string, context *fi.ModelBuilderCo actualTasksYaml = strings.TrimSpace(actualTasksYaml) golden.AssertMatchesFile(t, actualTasksYaml, expectedFile) + + // Asserts that FindTaskDependencies doesn't call klog.Fatalf() + fi.FindTaskDependencies(context.Tasks) } diff --git a/upup/pkg/fi/nodeup/nodetasks/BUILD.bazel b/upup/pkg/fi/nodeup/nodetasks/BUILD.bazel index c461db20db79d..722ece69dd0d4 100644 --- a/upup/pkg/fi/nodeup/nodetasks/BUILD.bazel +++ b/upup/pkg/fi/nodeup/nodetasks/BUILD.bazel @@ -11,6 +11,7 @@ go_library( "file.go", "group.go", "issue_cert.go", + "kubeconfig.go", "load_image.go", "package.go", "service.go", @@ -20,7 +21,9 @@ go_library( importpath = "k8s.io/kops/upup/pkg/fi/nodeup/nodetasks", visibility = ["//visibility:public"], deps = [ + "//pkg/apis/kops:go_default_library", "//pkg/backoff:go_default_library", + "//pkg/kubeconfig:go_default_library", "//pkg/pki:go_default_library", "//upup/pkg/fi:go_default_library", "//upup/pkg/fi/nodeup/cloudinit:go_default_library", diff --git a/upup/pkg/fi/nodeup/nodetasks/issue_cert.go b/upup/pkg/fi/nodeup/nodetasks/issue_cert.go index cc157b4d0d258..49d9b900532fd 100644 --- a/upup/pkg/fi/nodeup/nodetasks/issue_cert.go +++ b/upup/pkg/fi/nodeup/nodetasks/issue_cert.go @@ -28,13 +28,25 @@ import ( "k8s.io/kops/upup/pkg/fi" ) +// PKIXName is a simplified form of pkix.Name, for better golden test output +type PKIXName struct { + fi.NotADependency + CommonName string +} + +func (n *PKIXName) toPKIXName() pkix.Name { + return pkix.Name{ + CommonName: n.CommonName, + } +} + type IssueCert struct { Name string - Signer string `json:"signer"` - Type string `json:"type"` - Subject pkix.Name `json:"subject"` - AlternateNames []string `json:"alternateNames,omitempty"` + Signer string `json:"signer"` + Type string `json:"type"` + Subject PKIXName `json:"subject"` + AlternateNames []string `json:"alternateNames,omitempty"` cert *fi.TaskDependentResource key *fi.TaskDependentResource @@ -101,7 +113,7 @@ func (e *IssueCert) Run(c *fi.Context) error { req := &pki.IssueCertRequest{ Signer: e.Signer, Type: e.Type, - Subject: e.Subject, + Subject: e.Subject.toPKIXName(), MinValidDays: 455, } diff --git a/upup/pkg/fi/nodeup/nodetasks/kubeconfig.go b/upup/pkg/fi/nodeup/nodetasks/kubeconfig.go new file mode 100644 index 0000000000000..1231b43e9287c --- /dev/null +++ b/upup/pkg/fi/nodeup/nodetasks/kubeconfig.go @@ -0,0 +1,132 @@ +/* +Copyright 2020 The Kubernetes 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. +*/ + +package nodetasks + +import ( + "fmt" + + "k8s.io/kops/pkg/apis/kops" + "k8s.io/kops/pkg/kubeconfig" + "k8s.io/kops/upup/pkg/fi" +) + +type KubeConfig struct { + Name string + Cert fi.Resource + Key fi.Resource + CA fi.Resource + ServerURL string + + config *fi.TaskDependentResource +} + +var _ fi.Task = &KubeConfig{} +var _ fi.HasName = &KubeConfig{} +var _ fi.HasDependencies = &KubeConfig{} + +func (k *KubeConfig) GetName() *string { + return &k.Name +} + +// String returns a string representation, implementing the Stringer interface +func (k *KubeConfig) String() string { + return fmt.Sprintf("KubeConfig: %s", k.Name) +} + +func (k *KubeConfig) GetDependencies(tasks map[string]fi.Task) []fi.Task { + var deps []fi.Task + + if hasDep, ok := k.Cert.(fi.HasDependencies); ok { + deps = append(deps, hasDep.GetDependencies(tasks)...) + } + if hasDep, ok := k.Key.(fi.HasDependencies); ok { + deps = append(deps, hasDep.GetDependencies(tasks)...) + } + if hasDep, ok := k.CA.(fi.HasDependencies); ok { + deps = append(deps, hasDep.GetDependencies(tasks)...) + } + + return deps +} + +func (k *KubeConfig) GetConfig() *fi.TaskDependentResource { + if k.config == nil { + k.config = &fi.TaskDependentResource{Task: k} + } + return k.config +} + +func (k *KubeConfig) Run(_ *fi.Context) error { + cert, err := fi.ResourceAsBytes(k.Cert) + if err != nil { + return err + } + key, err := fi.ResourceAsBytes(k.Key) + if err != nil { + return err + } + ca, err := fi.ResourceAsBytes(k.CA) + if err != nil { + return err + } + + user := kubeconfig.KubectlUser{ + ClientCertificateData: cert, + ClientKeyData: key, + } + cluster := kubeconfig.KubectlCluster{ + CertificateAuthorityData: ca, + Server: k.ServerURL, + } + + config := &kubeconfig.KubectlConfig{ + ApiVersion: "v1", + Kind: "Config", + Users: []*kubeconfig.KubectlUserWithName{ + { + Name: k.Name, + User: user, + }, + }, + Clusters: []*kubeconfig.KubectlClusterWithName{ + { + Name: "local", + Cluster: cluster, + }, + }, + Contexts: []*kubeconfig.KubectlContextWithName{ + { + Name: "service-account-context", + Context: kubeconfig.KubectlContext{ + Cluster: "local", + User: k.Name, + }, + }, + }, + CurrentContext: "service-account-context", + } + + yaml, err := kops.ToRawYaml(config) + if err != nil { + return fmt.Errorf("error marshaling kubeconfig to yaml: %v", err) + } + + output := k.GetConfig() + output.Resource = fi.NewBytesResource(yaml) + + return nil +} diff --git a/upup/pkg/fi/resources.go b/upup/pkg/fi/resources.go index f5a57e104acd4..5133516b915af 100644 --- a/upup/pkg/fi/resources.go +++ b/upup/pkg/fi/resources.go @@ -250,8 +250,8 @@ func WrapResource(r Resource) *ResourceHolder { } type TaskDependentResource struct { - Resource Resource - Task Task + Resource Resource `json:"resource,omitempty"` + Task Task `json:"task,omitempty"` } var _ Resource = &TaskDependentResource{} diff --git a/upup/pkg/fi/topological_sort.go b/upup/pkg/fi/topological_sort.go index c91d8e44f3c14..73a20c3141066 100644 --- a/upup/pkg/fi/topological_sort.go +++ b/upup/pkg/fi/topological_sort.go @@ -17,12 +17,10 @@ limitations under the License. package fi import ( - "crypto/x509/pkix" "fmt" "reflect" "k8s.io/klog" - "k8s.io/kops/util/pkg/reflectutils" ) @@ -30,6 +28,15 @@ type HasDependencies interface { GetDependencies(tasks map[string]Task) []Task } +// NotADependency is a marker type to prevent FindTaskDependencies() from considering it a potential dependency. +type NotADependency struct{} + +var _ HasDependencies = &NotADependency{} + +func (NotADependency) GetDependencies(map[string]Task) []Task { + return nil +} + // FindTaskDependencies returns a map from each task's key to the discovered list of dependencies func FindTaskDependencies(tasks map[string]Task) map[string][]string { taskToId := make(map[interface{}]string) @@ -107,8 +114,6 @@ func getDependencies(tasks map[string]Task, v reflect.Value) []Task { // Ignore: not a dependency (?) } else if _, ok := intf.(*ResourceHolder); ok { // Ignore: not a dependency (?) - } else if _, ok := intf.(*pkix.Name); ok { - // Ignore: not a dependency } else { return fmt.Errorf("Unhandled type for %q: %T", path, v.Interface()) }