talos

Форк
0
/
generate.go 
152 строки · 4.1 Кб
1
// This Source Code Form is subject to the terms of the Mozilla Public
2
// License, v. 2.0. If a copy of the MPL was not distributed with this
3
// file, You can obtain one at http://mozilla.org/MPL/2.0/.
4

5
package kubeconfig
6

7
import (
8
	"bytes"
9
	stdlibx509 "crypto/x509"
10
	"encoding/base64"
11
	"fmt"
12
	"io"
13
	"net/url"
14
	"text/template"
15
	"time"
16

17
	"github.com/siderolabs/crypto/x509"
18
	"github.com/siderolabs/gen/xslices"
19

20
	"github.com/siderolabs/talos/pkg/machinery/config/config"
21
)
22

23
const kubeConfigTemplate = `apiVersion: v1
24
kind: Config
25
clusters:
26
- name: {{ .ClusterName }}
27
  cluster:
28
    server: {{ .Endpoint }}
29
    certificate-authority-data: {{ .CACert | base64Encode }}
30
users:
31
- name: {{ .Username }}@{{ .ClusterName }}
32
  user:
33
    client-certificate-data: {{ .ClientCert | base64Encode }}
34
    client-key-data: {{ .ClientKey | base64Encode }}
35
contexts:
36
- context:
37
    cluster: {{ .ClusterName }}
38
    namespace: default
39
    user: {{ .Username }}@{{ .ClusterName }}
40
  name: {{ .ContextName }}@{{ .ClusterName }}
41
current-context: {{ .ContextName }}@{{ .ClusterName }}
42
`
43

44
// GenerateAdminInput is the interface for the GenerateAdmin function.
45
//
46
// This interface is implemented by config.Cluster().
47
type GenerateAdminInput interface {
48
	Name() string
49
	Endpoint() *url.URL
50
	IssuingCA() *x509.PEMEncodedCertificateAndKey
51
	AcceptedCAs() []*x509.PEMEncodedCertificate
52
	AdminKubeconfig() config.AdminKubeconfig
53
}
54

55
// GenerateAdmin generates admin kubeconfig for the cluster.
56
func GenerateAdmin(config GenerateAdminInput, out io.Writer) error {
57
	acceptedCAs := config.AcceptedCAs()
58

59
	if config.IssuingCA() != nil {
60
		acceptedCAs = append(acceptedCAs, &x509.PEMEncodedCertificate{Crt: config.IssuingCA().Crt})
61
	}
62

63
	return Generate(
64
		&GenerateInput{
65
			ClusterName:         config.Name(),
66
			IssuingCA:           config.IssuingCA(),
67
			AcceptedCAs:         acceptedCAs,
68
			CertificateLifetime: config.AdminKubeconfig().CertLifetime(),
69

70
			CommonName:   config.AdminKubeconfig().CommonName(),
71
			Organization: config.AdminKubeconfig().CertOrganization(),
72

73
			Endpoint:    config.Endpoint().String(),
74
			Username:    "admin",
75
			ContextName: "admin",
76
		},
77
		out,
78
	)
79
}
80

81
// GenerateInput are input parameters for Generate.
82
type GenerateInput struct {
83
	ClusterName string
84

85
	IssuingCA           *x509.PEMEncodedCertificateAndKey
86
	AcceptedCAs         []*x509.PEMEncodedCertificate
87
	CertificateLifetime time.Duration
88

89
	CommonName   string
90
	Organization string
91

92
	Endpoint    string
93
	Username    string
94
	ContextName string
95
}
96

97
const allowedTimeSkew = 10 * time.Second
98

99
// Generate a kubeconfig for the cluster from the given Input.
100
func Generate(in *GenerateInput, out io.Writer) error {
101
	tpl, err := template.New("kubeconfig").Funcs(template.FuncMap{
102
		"base64Encode": base64Encode,
103
	}).Parse(kubeConfigTemplate)
104
	if err != nil {
105
		return fmt.Errorf("error parsing kubeconfig template: %w", err)
106
	}
107

108
	k8sCA, err := x509.NewCertificateAuthorityFromCertificateAndKey(in.IssuingCA)
109
	if err != nil {
110
		return fmt.Errorf("error getting Kubernetes CA: %w", err)
111
	}
112

113
	clientCert, err := x509.NewKeyPair(k8sCA,
114
		x509.CommonName(in.CommonName),
115
		x509.Organization(in.Organization),
116
		x509.NotBefore(time.Now().Add(-allowedTimeSkew)),
117
		x509.NotAfter(time.Now().Add(in.CertificateLifetime)),
118
		x509.KeyUsage(stdlibx509.KeyUsageDigitalSignature|stdlibx509.KeyUsageKeyEncipherment),
119
		x509.ExtKeyUsage([]stdlibx509.ExtKeyUsage{
120
			stdlibx509.ExtKeyUsageClientAuth,
121
		}),
122
	)
123
	if err != nil {
124
		return fmt.Errorf("error generating Kubernetes client certificate: %w", err)
125
	}
126

127
	clientCertPEM := x509.NewCertificateAndKeyFromKeyPair(clientCert)
128

129
	serverCAs := bytes.Join(xslices.Map(in.AcceptedCAs, func(ca *x509.PEMEncodedCertificate) []byte { return ca.Crt }), nil)
130

131
	return tpl.Execute(out, struct {
132
		GenerateInput
133

134
		CACert     string
135
		ClientCert string
136
		ClientKey  string
137
	}{
138
		GenerateInput: *in,
139
		CACert:        string(serverCAs),
140
		ClientCert:    string(clientCertPEM.Crt),
141
		ClientKey:     string(clientCertPEM.Key),
142
	})
143
}
144

145
func base64Encode(content interface{}) (string, error) {
146
	str, ok := content.(string)
147
	if !ok {
148
		return "", fmt.Errorf("argument to base64 encode is not a string: %v", content)
149
	}
150

151
	return base64.StdEncoding.EncodeToString([]byte(str)), nil
152
}
153

Использование cookies

Мы используем файлы cookie в соответствии с Политикой конфиденциальности и Политикой использования cookies.

Нажимая кнопку «Принимаю», Вы даете АО «СберТех» согласие на обработку Ваших персональных данных в целях совершенствования нашего веб-сайта и Сервиса GitVerse, а также повышения удобства их использования.

Запретить использование cookies Вы можете самостоятельно в настройках Вашего браузера.