blob: 75717175d646894a2e4a0c3e37b67f2ddbe5459e [file] [log] [blame]
Serge Bazanski9f0e1e82023-03-31 22:36:54 +00001package certs
2
3import (
4 "net"
5 "time"
6)
7
8// Certificates is the set of certificates required to run our Kubernetes
9// production.
10type Certificates struct {
11 CAs CAs
12
13 ProdviderIntermediateCA *Certificate
14
15 Global Global
16 PerNode map[string]PerNode
17}
18
19type ensurer interface {
20 Ensure() error
21}
22
23// Ensure checks that all the Kubernetes production certificates and keys are
24// present on disk, generating them as necessary.
25//
26// If the user has not decrypted cluster/secrets, an error will be returned.
27// However, deeper sync checks are not currently performed.
28func (c *Certificates) Ensure() error {
29 sub := []ensurer{
30 &c.CAs,
31 c.ProdviderIntermediateCA,
32 &c.Global,
33 }
34 for _, pn := range c.PerNode {
35 sub = append(sub, &pn)
36 }
37 for _, s := range sub {
38 if err := s.Ensure(); err != nil {
39 return err
40 }
41 }
42 return nil
43}
44
45// CAs are the root certificate authorities we use.
46type CAs struct {
47 // EtcdPeer is used by etcd member nodes to authenticate peers.
48 EtcdPeer *Certificate
49 // Etcd is used by etcd membrer nodes to authenticate clients (ie.
50 // kube-apiservers).
51 Etcd *Certificate
52 // Kube is the main Kubernetes 'identity' CA, used to identify components
53 // and users.
54 Kube *Certificate
55 // KubeFront is the proxy/aggregation CA used by external apiservices to
56 // authenticate incoming apiserver connections.
57 KubeFront *Certificate
58 // Admitomatic is the CA used by the admitomatic webhook to authenticate
59 // incoming apiserver connections.
60 Admitomatic *Certificate
61}
62
63func (c *CAs) Ensure() error {
64 sub := []ensurer{
65 c.EtcdPeer,
66 c.Etcd,
67 c.Kube,
68 c.KubeFront,
69 c.Admitomatic,
70 }
71 for _, s := range sub {
72 if err := s.Ensure(); err != nil {
73 return err
74 }
75 }
76 return nil
77}
78
79// Global are all the non-per-node certificates we use.
80type Global struct {
81 // EtcdKube is used by kubernetes apiservers to authenticate to etcd
82 // members.
83 EtcdKube *Certificate
84
85 // KubeApiserver is used by kubernetes apiservers to authenticate to other
86 // kubernetes components/users.
87 KubeApiserver *Certificate
88 // KubeControllerManager is used by kubernetes controller managers to
89 // authenticate to the kubernetes apiservers.
90 KubeControllerManager *Certificate
91 // KubeScheduler is used by the kubernetes schedulers to authenticate to
92 // the kubernetes apiservers.
93 KubeScheduler *Certificate
94
95 // KubefrontApiserver is used by the kubernetes apiserver to authenticate
96 // to external apiservices.
97 KubefrontApiserver *Certificate
98
99 // AdmitomaticWebhook is used by the admitomatic webhook to authenticate to
100 // the Kubernetes apiservers.
101 AdmitomaticWebhook *Certificate
102}
103
104func (g *Global) Ensure() error {
105 sub := []ensurer{
106 g.EtcdKube,
107 g.KubeApiserver,
108 g.KubeControllerManager,
109 g.KubeScheduler,
110 g.KubefrontApiserver,
111 g.AdmitomaticWebhook,
112 }
113 for _, s := range sub {
114 if err := s.Ensure(); err != nil {
115 return err
116 }
117 }
118 return nil
119}
120
121func (c *Certificates) MakeKubeEmergencyCreds(root, breadcrumb string) *Certificate {
122 return &Certificate{
123 name: "emergency",
124 duration: 7 * 24 * time.Hour,
125 root: root,
126 kind: kindClient,
127 cn: "admin",
128 san: []string{"admin", breadcrumb},
129 o: "system:masters",
130 issuer: c.CAs.Kube,
131 }
132}
133
134// Per node are all the per-node certificates we use.
135type PerNode struct {
136 // EtcdPeer is used by etcd members to authenticate to other etcd members.
137 EtcdPeer *Certificate
138 // EtcdClient is used by etcd members to authenticate to their clients.
139 EtcdClient *Certificate
140
141 // Kubelet is used by kubelets to authenticate to other kubernetes
142 // components.
143 Kubelet *Certificate
144}
145
146func (p *PerNode) Ensure() error {
147 sub := []ensurer{
148 p.EtcdPeer,
149 p.EtcdClient,
150 p.Kubelet,
151 }
152 for _, s := range sub {
153 if err := s.Ensure(); err != nil {
154 return err
155 }
156 }
157 return nil
158}
159
160func mkCA(root, name, cn string) *Certificate {
161 return &Certificate{
162 name: name,
163 root: root,
164 kind: kindCA,
165 cn: cn,
166 }
167}
168
169// Prepare builds our Certificates structure at a given location on the
170// filesystem, for the given nodes.
171//
172// Calling Ensure() on the returned Certificates will actually engage
173// generation logic. Before that, no disk accesses are performed.
174func Prepare(root string, fqdns []string) Certificates {
175 certs := Certificates{
176 CAs: CAs{
177 EtcdPeer: mkCA(root, "ca-etcdpeer", "etcd peer ca"),
178 Etcd: mkCA(root, "ca-etcd", "etcd ca"),
179 Kube: mkCA(root, "ca-kube", "kubernetes main CA"),
180 KubeFront: mkCA(root, "ca-kubefront", "kubernetes frontend CA"),
181 Admitomatic: mkCA(root, "ca-admitomatic", "admitomatic webhook CA"),
182 },
183 PerNode: make(map[string]PerNode),
184 }
185
186 certs.ProdviderIntermediateCA = &Certificate{
187 name: "ca-kube-prodvider",
188 root: root,
189 kind: kindProdvider,
190 cn: "kubernetes prodvider intermediate",
191 issuer: certs.CAs.Kube,
192 }
193 certs.Global = Global{
194 EtcdKube: &Certificate{
195 name: "etcd-kube",
196 root: root,
197 kind: kindClient,
198 cn: "kube etcd client certificate",
199 san: []string{"kube"},
200 issuer: certs.CAs.Etcd,
201 },
202 KubeApiserver: &Certificate{
203 name: "kube-apiserver",
204 root: root,
205 kind: kindClientServer,
206 cn: "k0.hswaw.net",
207 san: []string{
208 "k0.hswaw.net",
209 "kubernetes.default.svc.k0.hswaw.net",
210 },
211 ips: []net.IP{
212 {10, 10, 12, 1},
213 },
214 issuer: certs.CAs.Kube,
215 },
216 KubeControllerManager: &Certificate{
217 name: "kube-controllermanager",
218 root: root,
219 kind: kindClientServer,
220 cn: "system:kube-controller-manager",
221 san: []string{"system:kube-controller-manager"},
222 o: "system:kube-controller-manager",
223 issuer: certs.CAs.Kube,
224 },
225 KubeScheduler: &Certificate{
226 name: "kube-scheduler",
227 root: root,
228 kind: kindClientServer,
229 cn: "system:kube-scheduler",
230 san: []string{"system:kube-scheduler"},
231 o: "system:kube-scheduler",
232 issuer: certs.CAs.Kube,
233 },
234 KubefrontApiserver: &Certificate{
235 name: "kubefront-apiserver",
236 root: root,
237 kind: kindClientServer,
238 cn: "Kubernetes Frontend",
239 san: []string{"apiserver"},
240 issuer: certs.CAs.KubeFront,
241 },
242 AdmitomaticWebhook: &Certificate{
243 name: "admitomatic-webhook",
244 root: root,
245 kind: kindServer,
246 cn: "Admitomatic Webhook",
247 san: []string{"admitomatic.admitomatic.svc"},
248 issuer: certs.CAs.Admitomatic,
249 },
250 }
251 for _, fqdn := range fqdns {
252 certs.PerNode[fqdn] = PerNode{
253 EtcdPeer: &Certificate{
254 name: "etcdpeer-" + fqdn,
255 root: root,
256 kind: kindClientServer,
257 cn: "node etcd peer certificate",
258 san: []string{fqdn},
259 issuer: certs.CAs.EtcdPeer,
260 },
261 EtcdClient: &Certificate{
262 name: "etcd-" + fqdn,
263 root: root,
264 // etcd seems to need client too, as it's connecting to itself
265 // for... some reason?
266 // https://github.com/etcd-io/etcd/issues/9785
267 kind: kindClientServer,
268 cn: "node etcd server certificate",
269 san: []string{fqdn},
270 issuer: certs.CAs.Etcd,
271 },
272 Kubelet: &Certificate{
273 name: "kube-kubelet-" + fqdn,
274 root: root,
275 kind: kindClientServer,
276 cn: "system:node:" + fqdn,
277 o: "system:nodes",
278 san: []string{
279 "system:node:" + fqdn,
280 fqdn,
281 },
282 issuer: certs.CAs.Kube,
283 },
284 }
285 }
286
287 return certs
288}