github.com/sealerio/sealer@v0.11.1-0.20240507115618-f4f89c5853ae/pkg/clustercert/kube_certs.go (about) 1 // Copyright © 2021 Alibaba Group Holding Ltd. 2 // 3 // Licensed under the Apache License, Version 2.0 (the "License"); 4 // you may not use this file except in compliance with the License. 5 // You may obtain a copy of the License at 6 // 7 // http://www.apache.org/licenses/LICENSE-2.0 8 // 9 // Unless required by applicable law or agreed to in writing, software 10 // distributed under the License is distributed on an "AS IS" BASIS, 11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 // See the License for the specific language governing permissions and 13 // limitations under the License. 14 15 package clustercert 16 17 import ( 18 "crypto" 19 "crypto/x509" 20 "fmt" 21 "net" 22 "os" 23 "strings" 24 25 "github.com/pkg/errors" 26 "github.com/sirupsen/logrus" 27 utilnet "k8s.io/utils/net" 28 29 "github.com/sealerio/sealer/pkg/clustercert/cert" 30 ) 31 32 const ( 33 34 // KubernetesConfigDir kubernetes default certificate directory 35 KubernetesConfigDir = "/etc/kubernetes" 36 37 // KubeDefaultCertPath kubernetes components default certificate directory 38 KubeDefaultCertPath = "/etc/kubernetes/pki" 39 40 // KubeDefaultCertEtcdPath etcd default certificate directory 41 KubeDefaultCertEtcdPath = "/etc/kubernetes/pki/etcd" 42 ) 43 44 type CertificateConfig struct { 45 // file saved path only for this cert 46 certPath string 47 certName string 48 descriptor *cert.CertificateDescriptor 49 } 50 51 type CertificateConfigFamily struct { 52 // default file saved path for this cert Family 53 certPath string 54 caConfig CertificateConfig 55 commonConfig []CertificateConfig 56 } 57 58 func (c CertificateConfigFamily) GenerateAll() error { 59 var ( 60 err error 61 caCert *x509.Certificate 62 caKey crypto.Signer 63 ) 64 65 _, err = os.Stat(cert.PathForCert(c.certPath, c.caConfig.certName)) 66 if os.IsNotExist(err) { 67 caCert, caKey, err = c.generateAuthorityCertificate() 68 if err != nil { 69 return err 70 } 71 } else { 72 logrus.Info("authority certificate is already exist") 73 caCert, caKey, err = c.loadAuthorityCertificate(c.certPath, c.caConfig.certName) 74 if err != nil { 75 return fmt.Errorf("failed to load an exist cert(%s): %v", c.caConfig.certName, err) 76 } 77 } 78 79 err = c.generateCommonCertificate(caCert, caKey) 80 if err != nil { 81 return err 82 } 83 84 return nil 85 } 86 87 func (c CertificateConfigFamily) generateAuthorityCertificate() (*x509.Certificate, crypto.Signer, error) { 88 // New authority certificate generator to gen ca cert. 89 caGenerator := cert.NewAuthorityCertificateGenerator(*c.caConfig.descriptor) 90 caCert, caKey, err := caGenerator.Generate() 91 if err != nil { 92 return nil, nil, fmt.Errorf("unable to generate %s cert: %v", c.caConfig.certName, err) 93 } 94 95 // write cert file to disk 96 err = cert.NewCertificateFileManger(c.certPath, c.caConfig.certName).Write(caCert, caKey) 97 if err != nil { 98 return nil, nil, fmt.Errorf("unable to save %s cert: %v", c.caConfig.certName, err) 99 } 100 101 return caCert, caKey, nil 102 } 103 104 func (c CertificateConfigFamily) loadAuthorityCertificate(certPath, certName string) (*x509.Certificate, crypto.Signer, error) { 105 caCert, caKey, err := cert.NewCertificateFileManger(certPath, certName).Read() 106 if err != nil { 107 return nil, nil, fmt.Errorf("unable to load cert(%s) from disk: %v", certName, err) 108 } 109 return caCert, caKey, nil 110 } 111 112 func (c CertificateConfigFamily) generateCommonCertificate(caCert *x509.Certificate, caKey crypto.Signer) error { 113 for _, config := range c.commonConfig { 114 certPath := c.certPath 115 if config.certPath != "" { 116 certPath = config.certPath 117 } 118 119 g, err := cert.NewCommonCertificateGenerator(*config.descriptor, caCert, caKey) 120 if err != nil { 121 return err 122 } 123 124 commonCert, key, err := g.Generate() 125 if err != nil { 126 return err 127 } 128 129 err = cert.NewCertificateFileManger(certPath, config.certName).Write(commonCert, key) 130 if err != nil { 131 return fmt.Errorf("unable to save %s key: %v", config.certName, err) 132 } 133 } 134 return nil 135 } 136 137 type KubernetesCertService struct { 138 kubeCert CertificateConfigFamily 139 etcdCert CertificateConfigFamily 140 frontProxyCert CertificateConfigFamily 141 serviceAccount cert.KeyPairFileGenerator 142 } 143 144 func (s KubernetesCertService) GenerateKubeComponentCert() (err error) { 145 err = s.kubeCert.GenerateAll() 146 if err != nil { 147 return err 148 } 149 150 err = s.etcdCert.GenerateAll() 151 if err != nil { 152 return err 153 } 154 155 err = s.frontProxyCert.GenerateAll() 156 if err != nil { 157 return err 158 } 159 160 return nil 161 } 162 163 func (s KubernetesCertService) GenerateServiceAccountKeyPair() (err error) { 164 err = s.serviceAccount.GenerateAll() 165 if err != nil { 166 return err 167 } 168 169 return nil 170 } 171 172 type Args struct { 173 APIServerAltNames cert.AltNames 174 NodeName string 175 NodeIP net.IP 176 DNSDomain string 177 } 178 179 // GenerateAllKubernetesCerts generate all cert. 180 func GenerateAllKubernetesCerts(certPath, etcdCertPath, nodeName, serviceCIRD, DNSDomain string, altNames []string, nodeIP net.IP) error { 181 if certPath == "" || etcdCertPath == "" { 182 return fmt.Errorf("must provide cert path") 183 } 184 185 if nodeName == "" || nodeIP == nil { 186 return fmt.Errorf("must provide node name and node IP") 187 } 188 189 if DNSDomain == "" { 190 return fmt.Errorf("must provide cluster DNS domain") 191 } 192 193 // parse cluster cert args 194 clusterCertArgs := Args{ 195 DNSDomain: DNSDomain, 196 NodeIP: nodeIP, 197 NodeName: nodeName, 198 APIServerAltNames: cert.AltNames{ 199 DNSNames: map[string]string{}, 200 IPs: map[string]net.IP{}, 201 }, 202 } 203 204 clusterCertArgs.APIServerAltNames.IPs[nodeIP.String()] = nodeIP 205 206 for _, svcCidr := range strings.Split(serviceCIRD, ",") { 207 _, svcSubnet, err := net.ParseCIDR(svcCidr) 208 if err != nil { 209 return errors.Wrapf(err, "unable to parse ServiceSubnet %v", svcCidr) 210 } 211 svcFirstIP, err := utilnet.GetIndexedIP(svcSubnet, 1) 212 if err != nil { 213 return err 214 } 215 clusterCertArgs.APIServerAltNames.IPs[svcFirstIP.String()] = svcFirstIP 216 } 217 218 for _, altName := range altNames { 219 ip := net.ParseIP(altName) 220 if ip != nil { 221 clusterCertArgs.APIServerAltNames.IPs[ip.String()] = ip 222 continue 223 } 224 clusterCertArgs.APIServerAltNames.DNSNames[altName] = altName 225 } 226 227 // generate all cert. 228 certService := KubernetesCertService{ 229 kubeCert: getKubeCertificateConfig(certPath, clusterCertArgs.APIServerAltNames, clusterCertArgs.NodeName, clusterCertArgs.DNSDomain), 230 etcdCert: getEtcdCertificateConfig(etcdCertPath, certPath, clusterCertArgs.NodeName, clusterCertArgs.NodeIP), 231 frontProxyCert: getFrontProxyCertificateConfig(certPath), 232 serviceAccount: cert.NewKeyPairFileGenerator(certPath, "sa"), 233 } 234 235 err := certService.GenerateKubeComponentCert() 236 if err != nil { 237 return err 238 } 239 240 err = certService.GenerateServiceAccountKeyPair() 241 if err != nil { 242 return err 243 } 244 245 return nil 246 } 247 248 func getKubeCertificateConfig(certPath string, APIServerAltNames cert.AltNames, nodeName string, DNSDomain string) CertificateConfigFamily { 249 kubeCert := CertificateConfigFamily{ 250 certPath: certPath, 251 caConfig: CertificateConfig{ 252 certName: "ca", 253 descriptor: &cert.CertificateDescriptor{ 254 CommonName: "kubernetes", 255 Organization: nil, 256 Year: 100, 257 AltNames: cert.AltNames{}, 258 Usages: nil, 259 }, 260 }, 261 commonConfig: []CertificateConfig{ 262 { 263 certName: "apiserver", 264 descriptor: &cert.CertificateDescriptor{ 265 CommonName: "kube-apiserver", 266 Organization: nil, 267 Year: 100, 268 AltNames: cert.AltNames{}, 269 Usages: []x509.ExtKeyUsage{x509.ExtKeyUsageServerAuth}, 270 }, 271 }, 272 { 273 certName: "apiserver-kubelet-client", 274 descriptor: &cert.CertificateDescriptor{ 275 CommonName: "kube-apiserver-kubelet-client", 276 Organization: []string{"system:masters"}, 277 Year: 100, 278 AltNames: cert.AltNames{}, 279 Usages: []x509.ExtKeyUsage{x509.ExtKeyUsageClientAuth}, 280 }, 281 }, 282 }, 283 } 284 285 IPs := map[string]net.IP{ 286 "127.0.0.1": net.IPv4(127, 0, 0, 1), 287 } 288 289 dnsName := map[string]string{ 290 "localhost": "localhost", 291 "kubernetes": "kubernetes", 292 "kubernetes.default": "kubernetes.default", 293 "kubernetes.default.svc": "kubernetes.default.svc", 294 nodeName: nodeName, 295 fmt.Sprintf("kubernetes.default.svc.%s", DNSDomain): fmt.Sprintf("kubernetes.default.svc.%s", DNSDomain), 296 } 297 298 for _, dns := range APIServerAltNames.DNSNames { 299 dnsName[dns] = dns 300 } 301 302 for _, ip := range APIServerAltNames.IPs { 303 IPs[ip.String()] = ip 304 } 305 306 for _, config := range kubeCert.commonConfig { 307 // add altNames and node name to etcd server cert and peer cert. 308 if config.certName == "apiserver" { 309 config.descriptor.AltNames.DNSNames = dnsName 310 config.descriptor.AltNames.IPs = IPs 311 logrus.Info("API server altNames: ", config.descriptor.AltNames) 312 } 313 } 314 315 return kubeCert 316 } 317 318 func getEtcdCertificateConfig(etcdCertPath, certPath, nodeName string, nodeIP net.IP) CertificateConfigFamily { 319 etcdCert := CertificateConfigFamily{ 320 certPath: etcdCertPath, 321 caConfig: CertificateConfig{ 322 certName: "ca", 323 descriptor: &cert.CertificateDescriptor{ 324 CommonName: "etcd-ca", 325 Organization: nil, 326 Year: 100, 327 AltNames: cert.AltNames{}, 328 Usages: nil, 329 }, 330 }, 331 commonConfig: []CertificateConfig{ 332 { 333 certPath: certPath, 334 certName: "apiserver-etcd-client", 335 descriptor: &cert.CertificateDescriptor{ 336 CommonName: "kube-apiserver-etcd-client", 337 Organization: []string{"system:masters"}, 338 Year: 100, 339 AltNames: cert.AltNames{}, 340 Usages: []x509.ExtKeyUsage{x509.ExtKeyUsageClientAuth}, 341 }, 342 }, 343 { 344 certName: "server", 345 descriptor: &cert.CertificateDescriptor{ 346 CommonName: "etcd", 347 Organization: nil, 348 Year: 100, 349 AltNames: cert.AltNames{}, 350 Usages: []x509.ExtKeyUsage{x509.ExtKeyUsageServerAuth, x509.ExtKeyUsageClientAuth}, 351 }, 352 }, 353 { 354 certName: "peer", 355 descriptor: &cert.CertificateDescriptor{ 356 CommonName: "etcd-peer", 357 Organization: nil, 358 Year: 100, 359 AltNames: cert.AltNames{}, 360 Usages: []x509.ExtKeyUsage{x509.ExtKeyUsageServerAuth, x509.ExtKeyUsageClientAuth}, 361 }, 362 }, 363 { 364 certName: "healthcheck-client", 365 descriptor: &cert.CertificateDescriptor{ 366 CommonName: "kube-etcd-healthcheck-client", 367 Organization: []string{"system:masters"}, 368 Year: 100, 369 AltNames: cert.AltNames{}, 370 Usages: []x509.ExtKeyUsage{x509.ExtKeyUsageClientAuth}, 371 }, 372 }, 373 }, 374 } 375 376 altNames := cert.AltNames{ 377 DNSNames: map[string]string{ 378 "localhost": "localhost", 379 nodeName: nodeName, 380 }, 381 IPs: map[string]net.IP{ 382 net.IPv4(127, 0, 0, 1).String(): net.IPv4(127, 0, 0, 1), 383 nodeIP.String(): nodeIP, 384 net.IPv6loopback.String(): net.IPv6loopback, 385 }, 386 } 387 388 for _, config := range etcdCert.commonConfig { 389 // add altNames and node name to etcd server cert and peer cert. 390 if config.certName == "server" || config.certName == "peer" { 391 config.descriptor.AltNames = altNames 392 config.descriptor.CommonName = nodeName 393 } 394 } 395 396 return etcdCert 397 } 398 399 func getFrontProxyCertificateConfig(certPath string) CertificateConfigFamily { 400 return CertificateConfigFamily{ 401 certPath: certPath, 402 caConfig: CertificateConfig{ 403 certName: "front-proxy-ca", 404 descriptor: &cert.CertificateDescriptor{ 405 CommonName: "front-proxy-ca", 406 Organization: nil, 407 Year: 100, 408 AltNames: cert.AltNames{}, 409 Usages: nil, 410 }, 411 }, 412 commonConfig: []CertificateConfig{ 413 { 414 certName: "front-proxy-client", 415 descriptor: &cert.CertificateDescriptor{ 416 CommonName: "front-proxy-client", 417 Organization: nil, 418 Year: 100, 419 AltNames: cert.AltNames{}, 420 Usages: []x509.ExtKeyUsage{x509.ExtKeyUsageClientAuth}, 421 }, 422 }, 423 }, 424 } 425 } 426 427 // UpdateAPIServerCertSans :renew apiserver cert sans with given ca under pkiPath. 428 func UpdateAPIServerCertSans(pkiPath string, certSans []string) error { 429 baseName := "apiserver" 430 431 APIServerCertSans := cert.AltNames{ 432 DNSNames: map[string]string{}, 433 IPs: map[string]net.IP{}, 434 } 435 436 for _, altName := range certSans { 437 ip := net.ParseIP(altName) 438 if ip != nil { 439 APIServerCertSans.IPs[ip.String()] = ip 440 continue 441 } 442 APIServerCertSans.DNSNames[altName] = altName 443 } 444 445 apiCert, _, err := cert.NewCertificateFileManger(pkiPath, baseName).Read() 446 if err != nil { 447 return fmt.Errorf("unable to load %s cert: %v", baseName, err) 448 } 449 450 for _, dns := range apiCert.DNSNames { 451 APIServerCertSans.DNSNames[dns] = dns 452 } 453 454 for _, ip := range apiCert.IPAddresses { 455 APIServerCertSans.IPs[ip.String()] = ip 456 } 457 458 apiCertConfig := cert.CertificateDescriptor{ 459 Year: 100, 460 CommonName: apiCert.Subject.CommonName, 461 Organization: apiCert.Subject.Organization, 462 AltNames: APIServerCertSans, 463 Usages: apiCert.ExtKeyUsage, 464 } 465 466 // load ca cert form pkiPath 467 caCert, caKey, err := cert.NewCertificateFileManger(pkiPath, "ca").Read() 468 if err != nil { 469 return fmt.Errorf("unable to load %s cert: %v", baseName, err) 470 } 471 472 if err != nil { 473 return err 474 } 475 476 // new api server cert 477 generator, err := cert.NewCommonCertificateGenerator(apiCertConfig, caCert, caKey) 478 if err != nil { 479 return fmt.Errorf("unable to generate %s cert: %v", baseName, err) 480 } 481 482 newCert, newKey, err := generator.Generate() 483 if err != nil { 484 return fmt.Errorf("unable to generate %s cert: %v", baseName, err) 485 } 486 487 // write cert file to disk 488 err = cert.NewCertificateFileManger(pkiPath, baseName).Write(newCert, newKey) 489 if err != nil { 490 return fmt.Errorf("unable to save %s cert: %v", baseName, err) 491 } 492 493 return nil 494 }