| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161 |
- // Copyright 2019 Yunion
- //
- // 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 certs
- import (
- "crypto"
- "crypto/x509"
- "fmt"
- "yunion.io/x/pkg/errors"
- certutil "yunion.io/x/onecloud/pkg/util/tls/cert"
- pkiutil "yunion.io/x/onecloud/pkg/util/tls/pki"
- )
- type certKeyLocation struct {
- pkiDir string
- caBaseName string
- baseName string
- uxName string
- }
- // validateSignedCert tries to load a x509 certificate and private key from pkiDir and validates
- // that the cert is signed by a given CA
- func validateSignedCert(l certKeyLocation) error {
- // Try to load CA
- caCert, err := pkiutil.TryLoadCertFromDisk(l.pkiDir, l.caBaseName)
- if err != nil {
- return errors.Wrapf(err, "failure loading certificate authority for %s", l.uxName)
- }
- return validateSignedCertWithCA(l, caCert)
- }
- // validateSignedCertWithCA tries to load a certificate and validate it with the given caCert
- func validateSignedCertWithCA(l certKeyLocation, caCert *x509.Certificate) error {
- // Try to load key and signed certificate
- signedCert, _, err := pkiutil.TryLoadCertAndKeyFromDisk(l.pkiDir, l.baseName)
- if err != nil {
- return errors.Wrapf(err, "failure loading certificate for %s", l.uxName)
- }
- // Check if the cert is signed by the CA
- if err := signedCert.CheckSignatureFrom(caCert); err != nil {
- return errors.Wrapf(err, "certificate %s is not signed by corresponding CA", l.uxName)
- }
- return nil
- }
- // validatePrivatePublicKey tries to load a private key from pkiDir
- func validatePrivatePublicKey(l certKeyLocation) error {
- // Try to load key
- _, _, err := pkiutil.TryLoadPrivatePublicKeyFromDisk(l.pkiDir, l.baseName)
- if err != nil {
- return errors.Wrapf(err, "failure loading key for %s", l.uxName)
- }
- return nil
- }
- // writeCertificateAuthorithyFilesIfNotExist write a new certificate Authority to the given path.
- // If there already is a certificate file at the given path; tries to load it and check if the values in the
- // existing and the expected certificate equals. If they do; will just skip writing the file as it's up-to-date,
- // otherwise this function returns an error.
- func writeCertificateAuthorithyFilesIfNotExist(pkiDir string, baseName string, caCert *x509.Certificate, caKey crypto.Signer) error {
- // If cert or key exists, we should try to load them
- if pkiutil.CertOrKeyExist(pkiDir, baseName) {
- // Try to load .crt and .key from the PKI directory
- caCert, _, err := pkiutil.TryLoadCertAndKeyFromDisk(pkiDir, baseName)
- if err != nil {
- return errors.Wrapf(err, "failure loading %s certificate", baseName)
- }
- // Check if the existing cert is a CA
- if !caCert.IsCA {
- return errors.Errorf("certificate %s is not a CA", baseName)
- }
- // kubeadm doesn't validate the existing certificate Authority more than this;
- // Basically, if we find a certificate file with the same path; and it is a CA
- // kubeadm thinks those files are equal and doesn't bother writing a new file
- fmt.Printf("[certs] Using the existing %q certificate and key\n", baseName)
- } else {
- // Write .crt and .key files to disk
- fmt.Printf("[certs] Generating %q certificate and key\n", baseName)
- if err := pkiutil.WriteCertAndKey(pkiDir, baseName, caCert, caKey); err != nil {
- return errors.Wrapf(err, "failure while saving %s certificate and key", baseName)
- }
- }
- return nil
- }
- // writeCertificateFilesIfNotExist write a new certificate to the given path.
- // If there already is a certificate file at the given path; kubeadm tries to load it and check if the values in the
- // existing and the expected certificate equals. If they do; kubeadm will just skip writing the file as it's up-to-date,
- // otherwise this function returns an error.
- func writeCertificateFilesIfNotExist(pkiDir string, baseName string, signingCert *x509.Certificate, cert *x509.Certificate, key crypto.Signer, cfg *certutil.Config) error {
- // Checks if the signed certificate exists in the PKI directory
- if pkiutil.CertOrKeyExist(pkiDir, baseName) {
- // Try to load signed certificate .crt and .key from the PKI directory
- signedCert, _, err := pkiutil.TryLoadCertAndKeyFromDisk(pkiDir, baseName)
- if err != nil {
- return errors.Wrapf(err, "failure loading %s certificate", baseName)
- }
- // Check if the existing cert is signed by the given CA
- if err := signedCert.CheckSignatureFrom(signingCert); err != nil {
- return errors.Errorf("certificate %s is not signed by corresponding CA", baseName)
- }
- // Check if the certificate has the correct attributes
- if err := validateCertificateWithConfig(signedCert, baseName, cfg); err != nil {
- return err
- }
- fmt.Printf("[certs] Using the existing %q certificate and key\n", baseName)
- } else {
- // Write .crt and .key files to disk
- fmt.Printf("[certs] Generating %q certificate and key\n", baseName)
- if err := pkiutil.WriteCertAndKey(pkiDir, baseName, cert, key); err != nil {
- return errors.Wrapf(err, "failure while saving %s certificate and key", baseName)
- }
- if pkiutil.HasServerAuth(cert) {
- fmt.Printf("[certs] %s serving cert is signed for DNS names %v and IPs %v\n", baseName, cert.DNSNames, cert.IPAddresses)
- }
- }
- return nil
- }
- // validateCertificateWithConfig makes sure that a given certificate is valid at
- // least for the SANs defined in the configuration.
- func validateCertificateWithConfig(cert *x509.Certificate, baseName string, cfg *certutil.Config) error {
- for _, dnsName := range cfg.AltNames.DNSNames {
- if err := cert.VerifyHostname(dnsName); err != nil {
- return errors.Wrapf(err, "certificate %s is invalid", baseName)
- }
- }
- for _, ipAddress := range cfg.AltNames.IPs {
- if err := cert.VerifyHostname(ipAddress.String()); err != nil {
- return errors.Wrapf(err, "certificate %s is invalid", baseName)
- }
- }
- return nil
- }
|