...

Source file src/github.com/GoogleCloudPlatform/k8s-config-connector/pkg/webhook/cert/generator/selfsigned.go

Documentation: github.com/GoogleCloudPlatform/k8s-config-connector/pkg/webhook/cert/generator

     1  /*
     2  Copyright 2018 The Kubernetes Authors.
     3  
     4  Licensed under the Apache License, Version 2.0 (the "License");
     5  you may not use this file except in compliance with the License.
     6  You may obtain a copy of the License at
     7  
     8      http://www.apache.org/licenses/LICENSE-2.0
     9  
    10  Unless required by applicable law or agreed to in writing, software
    11  distributed under the License is distributed on an "AS IS" BASIS,
    12  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    13  See the License for the specific language governing permissions and
    14  limitations under the License.
    15  */
    16  
    17  package generator
    18  
    19  import (
    20  	"crypto"
    21  	"crypto/rand"
    22  	"crypto/rsa"
    23  	"crypto/x509"
    24  	"crypto/x509/pkix"
    25  	"encoding/pem"
    26  	"errors"
    27  	"fmt"
    28  	"math"
    29  	"math/big"
    30  	"time"
    31  
    32  	"k8s.io/client-go/util/keyutil"
    33  
    34  	"k8s.io/client-go/util/cert"
    35  )
    36  
    37  const (
    38  	rsaKeySize   = 2048
    39  	duration365d = time.Hour * 24 * 365
    40  )
    41  
    42  // ServiceToCommonName generates the CommonName for the certificate when using a k8s service.
    43  func ServiceToCommonName(serviceNamespace, serviceName string) string {
    44  	return fmt.Sprintf("%s.%s.svc", serviceName, serviceNamespace)
    45  }
    46  
    47  // SelfSignedCertGenerator implements the certGenerator interface.
    48  // It provisions self-signed certificates.
    49  type SelfSignedCertGenerator struct {
    50  	caKey  []byte
    51  	caCert []byte
    52  }
    53  
    54  var _ CertGenerator = &SelfSignedCertGenerator{}
    55  
    56  // SetCA sets the PEM-encoded CA private key and CA cert for signing the generated serving cert.
    57  func (cp *SelfSignedCertGenerator) SetCA(caKey, caCert []byte) {
    58  	cp.caKey = caKey
    59  	cp.caCert = caCert
    60  }
    61  
    62  // Generate creates and returns a CA certificate, certificate and
    63  // key for the server. serverKey and serverCert are used by the server
    64  // to establish trust for clients, CA certificate is used by the
    65  // client to verify the server authentication chain.
    66  // The cert will be valid for 365 days.
    67  func (cp *SelfSignedCertGenerator) Generate(commonName string) (*Artifacts, error) {
    68  	var signingKey *rsa.PrivateKey
    69  	var signingCert *x509.Certificate
    70  	var valid bool
    71  	var err error
    72  
    73  	valid, signingKey, signingCert = cp.validCACert()
    74  	if !valid {
    75  		signingKey, err = NewPrivateKey()
    76  		if err != nil {
    77  			return nil, fmt.Errorf("failed to create the CA private key: %v", err)
    78  		}
    79  		signingCert, err = NewSelfSignedCACert(cert.Config{CommonName: "webhook-cert-ca"}, signingKey)
    80  		if err != nil {
    81  			return nil, fmt.Errorf("failed to create the CA cert: %v", err)
    82  		}
    83  	}
    84  
    85  	key, err := NewPrivateKey()
    86  	if err != nil {
    87  		return nil, fmt.Errorf("failed to create the private key: %v", err)
    88  	}
    89  	signedCert, err := newSignedCert(
    90  		cert.Config{
    91  			CommonName: commonName,
    92  			Usages:     []x509.ExtKeyUsage{x509.ExtKeyUsageServerAuth},
    93  		},
    94  		key, signingCert, signingKey,
    95  	)
    96  	if err != nil {
    97  		return nil, fmt.Errorf("failed to create the cert: %v", err)
    98  	}
    99  	return &Artifacts{
   100  		Key:    encodePrivateKeyPEM(key),
   101  		Cert:   encodeCertPEM(signedCert),
   102  		CAKey:  encodePrivateKeyPEM(signingKey),
   103  		CACert: encodeCertPEM(signingCert),
   104  	}, nil
   105  }
   106  
   107  func (cp *SelfSignedCertGenerator) validCACert() (bool, *rsa.PrivateKey, *x509.Certificate) {
   108  	if !ValidCACert(cp.caKey, cp.caCert, cp.caCert, "",
   109  		time.Now().AddDate(1, 0, 0)) {
   110  		return false, nil, nil
   111  	}
   112  
   113  	var ok bool
   114  	key, err := keyutil.ParsePrivateKeyPEM(cp.caKey)
   115  	if err != nil {
   116  		return false, nil, nil
   117  	}
   118  	privateKey, ok := key.(*rsa.PrivateKey)
   119  	if !ok {
   120  		return false, nil, nil
   121  	}
   122  
   123  	certs, err := cert.ParseCertsPEM(cp.caCert)
   124  	if err != nil {
   125  		return false, nil, nil
   126  	}
   127  	if len(certs) != 1 {
   128  		return false, nil, nil
   129  	}
   130  	return true, privateKey, certs[0]
   131  }
   132  
   133  func NewPrivateKey() (*rsa.PrivateKey, error) {
   134  	return rsa.GenerateKey(rand.Reader, rsaKeySize)
   135  }
   136  
   137  // NewSelfSignedCACert creates a self signed CA certificate
   138  func NewSelfSignedCACert(cfg cert.Config, key crypto.Signer) (*x509.Certificate, error) {
   139  	now := time.Now()
   140  	tmpl := x509.Certificate{
   141  		SerialNumber: new(big.Int).SetInt64(0),
   142  		Subject: pkix.Name{
   143  			CommonName:   cfg.CommonName,
   144  			Organization: cfg.Organization,
   145  		},
   146  		DNSNames:              []string{cfg.CommonName},
   147  		NotBefore:             now.UTC(),
   148  		NotAfter:              now.Add(time.Hour * 24 * 365 * 10).UTC(),
   149  		KeyUsage:              x509.KeyUsageKeyEncipherment | x509.KeyUsageDigitalSignature | x509.KeyUsageCertSign,
   150  		BasicConstraintsValid: true,
   151  		IsCA:                  true,
   152  	}
   153  
   154  	certDERBytes, err := x509.CreateCertificate(rand.Reader, &tmpl, &tmpl, key.Public(), key)
   155  	if err != nil {
   156  		return nil, err
   157  	}
   158  	return x509.ParseCertificate(certDERBytes)
   159  }
   160  
   161  // newSignedCert creates a signed certificate using the given CA certificate and key
   162  func newSignedCert(cfg cert.Config, key crypto.Signer, caCert *x509.Certificate, caKey crypto.Signer) (*x509.Certificate, error) {
   163  	serial, err := rand.Int(rand.Reader, new(big.Int).SetInt64(math.MaxInt64))
   164  	if err != nil {
   165  		return nil, err
   166  	}
   167  	if len(cfg.CommonName) == 0 {
   168  		return nil, errors.New("must specify a CommonName")
   169  	}
   170  	if len(cfg.Usages) == 0 {
   171  		return nil, errors.New("must specify at least one ExtKeyUsage")
   172  	}
   173  
   174  	altNames := []string{cfg.CommonName}
   175  	altNames = append(altNames, cfg.AltNames.DNSNames...)
   176  	certTmpl := x509.Certificate{
   177  		Subject: pkix.Name{
   178  			CommonName:   cfg.CommonName,
   179  			Organization: cfg.Organization,
   180  		},
   181  		DNSNames:     altNames,
   182  		IPAddresses:  cfg.AltNames.IPs,
   183  		SerialNumber: serial,
   184  		NotBefore:    caCert.NotBefore,
   185  		NotAfter:     time.Now().Add(duration365d).UTC(),
   186  		KeyUsage:     x509.KeyUsageKeyEncipherment | x509.KeyUsageDigitalSignature,
   187  		ExtKeyUsage:  cfg.Usages,
   188  	}
   189  	certDERBytes, err := x509.CreateCertificate(rand.Reader, &certTmpl, caCert, key.Public(), caKey)
   190  	if err != nil {
   191  		return nil, err
   192  	}
   193  	return x509.ParseCertificate(certDERBytes)
   194  }
   195  
   196  func encodePrivateKeyPEM(key *rsa.PrivateKey) []byte {
   197  	block := pem.Block{
   198  		Type:  keyutil.RSAPrivateKeyBlockType,
   199  		Bytes: x509.MarshalPKCS1PrivateKey(key),
   200  	}
   201  	return pem.EncodeToMemory(&block)
   202  }
   203  
   204  func encodeCertPEM(c *x509.Certificate) []byte {
   205  	block := pem.Block{
   206  		Type:  cert.CertificateBlockType,
   207  		Bytes: c.Raw,
   208  	}
   209  	return pem.EncodeToMemory(&block)
   210  }
   211  

View as plain text