Issue kube-scheduler cert in nodeup

This commit is contained in:
John Gardiner Myers 2020-06-08 23:09:56 -07:00
parent 10bb3cf334
commit b0694300df
6 changed files with 313 additions and 74 deletions

View File

@ -17,6 +17,7 @@ limitations under the License.
package model
import (
"crypto/x509/pkix"
"fmt"
"os"
"path/filepath"
@ -27,7 +28,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 +193,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 pkix.Name, 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 +242,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
kubeConfig.ServerURL = "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)
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

View File

@ -17,6 +17,7 @@ limitations under the License.
package model
import (
"crypto/x509/pkix"
"fmt"
"strconv"
@ -24,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"
@ -83,14 +85,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", pkix.Name{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"),
})

View File

@ -63,25 +63,65 @@ 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:
Resource: null
Task:
CA:
Resource: null
Task:
Name: kube-scheduler
signer: ca
subject:
CommonName: system:kube-scheduler
Country: null
ExtraNames: null
Locality: null
Names: null
Organization: null
OrganizationalUnit: null
PostalCode: null
Province: null
SerialNumber: ""
StreetAddress: null
type: client
Cert:
Resource: null
Task:
Name: kube-scheduler
signer: ca
subject:
CommonName: system:kube-scheduler
Country: null
ExtraNames: null
Locality: null
Names: null
Organization: null
OrganizationalUnit: null
PostalCode: null
Province: null
SerialNumber: ""
StreetAddress: null
type: client
Key:
Resource: null
Task:
Name: kube-scheduler
signer: ca
subject:
CommonName: system:kube-scheduler
Country: null
ExtraNames: null
Locality: null
Names: null
Organization: null
OrganizationalUnit: null
PostalCode: null
Province: null
SerialNumber: ""
StreetAddress: null
type: client
Name: kube-scheduler
ServerURL: https://127.0.0.1
mode: "0400"
path: /var/lib/kube-scheduler/kubeconfig
type: file
@ -91,3 +131,76 @@ ifNotExists: true
mode: "0400"
path: /var/log/kube-scheduler.log
type: file
---
Name: kube-scheduler
signer: ca
subject:
CommonName: system:kube-scheduler
Country: null
ExtraNames: null
Locality: null
Names: null
Organization: null
OrganizationalUnit: null
PostalCode: null
Province: null
SerialNumber: ""
StreetAddress: null
type: client
---
CA:
Resource: null
Task:
Name: kube-scheduler
signer: ca
subject:
CommonName: system:kube-scheduler
Country: null
ExtraNames: null
Locality: null
Names: null
Organization: null
OrganizationalUnit: null
PostalCode: null
Province: null
SerialNumber: ""
StreetAddress: null
type: client
Cert:
Resource: null
Task:
Name: kube-scheduler
signer: ca
subject:
CommonName: system:kube-scheduler
Country: null
ExtraNames: null
Locality: null
Names: null
Organization: null
OrganizationalUnit: null
PostalCode: null
Province: null
SerialNumber: ""
StreetAddress: null
type: client
Key:
Resource: null
Task:
Name: kube-scheduler
signer: ca
subject:
CommonName: system:kube-scheduler
Country: null
ExtraNames: null
Locality: null
Names: null
Organization: null
OrganizationalUnit: null
PostalCode: null
Province: null
SerialNumber: ""
StreetAddress: null
type: client
Name: kube-scheduler
ServerURL: https://127.0.0.1

View File

@ -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{

View File

@ -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",

View File

@ -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
}