github.com/verrazzano/verrazzano-monitoring-operator@v0.0.30/pkg/vmo/certificate.go (about)

     1  // Copyright (c) 2020, 2021, Oracle and/or its affiliates.
     2  // Licensed under the Universal Permissive License v 1.0 as shown at https://oss.oracle.com/licenses/upl.
     3  
     4  package vmo
     5  
     6  import (
     7  	"bytes"
     8  	cryptorand "crypto/rand"
     9  	"crypto/rsa"
    10  	"crypto/x509"
    11  	"crypto/x509/pkix"
    12  	"encoding/pem"
    13  	"fmt"
    14  	"math/big"
    15  	"os"
    16  	"time"
    17  )
    18  
    19  const (
    20  	// OperatorName is the resource name for the Verrazzano monitoring operator
    21  	OperatorName = "verrazzano-monitoring-operator"
    22  	// OperatorNamespace is the resource namespace for the Verrazzano monitoring operator
    23  	OperatorNamespace = "verrazzano-system"
    24  )
    25  
    26  // CreateCertificates creates the needed certificates for the validating webhook
    27  func CreateCertificates(certDir string) (*bytes.Buffer, error) {
    28  	var caPEM, serverCertPEM, serverPrivKeyPEM *bytes.Buffer
    29  
    30  	commonName := fmt.Sprintf("%s.%s.svc", OperatorName, OperatorNamespace)
    31  	serialNumber, err := newSerialNumber()
    32  	if err != nil {
    33  		return nil, err
    34  	}
    35  
    36  	// CA config
    37  	ca := &x509.Certificate{
    38  		DNSNames:     []string{commonName},
    39  		SerialNumber: serialNumber,
    40  		Subject: pkix.Name{
    41  			CommonName: commonName,
    42  		},
    43  		NotBefore:             time.Now(),
    44  		NotAfter:              time.Now().AddDate(1, 0, 0),
    45  		IsCA:                  true,
    46  		ExtKeyUsage:           []x509.ExtKeyUsage{x509.ExtKeyUsageClientAuth, x509.ExtKeyUsageServerAuth},
    47  		KeyUsage:              x509.KeyUsageDigitalSignature | x509.KeyUsageCertSign,
    48  		BasicConstraintsValid: true,
    49  	}
    50  
    51  	// CA private key
    52  	caPrivKey, err := rsa.GenerateKey(cryptorand.Reader, 4096)
    53  	if err != nil {
    54  		return nil, err
    55  	}
    56  
    57  	// Self signed CA certificate
    58  	caBytes, err := x509.CreateCertificate(cryptorand.Reader, ca, ca, &caPrivKey.PublicKey, caPrivKey)
    59  	if err != nil {
    60  		return nil, err
    61  	}
    62  
    63  	// PEM encode CA cert
    64  	caPEM = new(bytes.Buffer)
    65  	_ = pem.Encode(caPEM, &pem.Block{
    66  		Type:  "CERTIFICATE",
    67  		Bytes: caBytes,
    68  	})
    69  
    70  	serialNumber, err = newSerialNumber()
    71  	if err != nil {
    72  		return nil, err
    73  	}
    74  
    75  	// server cert config
    76  	cert := &x509.Certificate{
    77  		DNSNames:     []string{commonName},
    78  		SerialNumber: serialNumber,
    79  		Subject: pkix.Name{
    80  			CommonName: commonName,
    81  		},
    82  		NotBefore:    time.Now(),
    83  		NotAfter:     time.Now().AddDate(1, 0, 0),
    84  		IsCA:         true,
    85  		SubjectKeyId: []byte{1, 2, 3, 4, 6},
    86  		ExtKeyUsage:  []x509.ExtKeyUsage{x509.ExtKeyUsageClientAuth, x509.ExtKeyUsageServerAuth},
    87  		KeyUsage:     x509.KeyUsageDigitalSignature,
    88  	}
    89  
    90  	// server private key
    91  	serverPrivKey, err := rsa.GenerateKey(cryptorand.Reader, 4096)
    92  	if err != nil {
    93  		return nil, err
    94  	}
    95  
    96  	// sign the server cert
    97  	serverCertBytes, err := x509.CreateCertificate(cryptorand.Reader, cert, ca, &serverPrivKey.PublicKey, caPrivKey)
    98  	if err != nil {
    99  		return nil, err
   100  	}
   101  
   102  	// PEM encode the server cert and key
   103  	serverCertPEM = new(bytes.Buffer)
   104  	_ = pem.Encode(serverCertPEM, &pem.Block{
   105  		Type:  "CERTIFICATE",
   106  		Bytes: serverCertBytes,
   107  	})
   108  
   109  	serverPrivKeyPEM = new(bytes.Buffer)
   110  	_ = pem.Encode(serverPrivKeyPEM, &pem.Block{
   111  		Type:  "RSA PRIVATE KEY",
   112  		Bytes: x509.MarshalPKCS1PrivateKey(serverPrivKey),
   113  	})
   114  
   115  	err = os.MkdirAll(certDir, 0666)
   116  	if err != nil {
   117  		return nil, err
   118  	}
   119  
   120  	err = writeFile(fmt.Sprintf("%s/tls.crt", certDir), serverCertPEM)
   121  	if err != nil {
   122  		return nil, err
   123  	}
   124  
   125  	err = writeFile(fmt.Sprintf("%s/tls.key", certDir), serverPrivKeyPEM)
   126  	if err != nil {
   127  		return nil, err
   128  	}
   129  
   130  	return caPEM, nil
   131  }
   132  
   133  // newSerialNumber returns a new random serial number suitable for use in a certificate.
   134  func newSerialNumber() (*big.Int, error) {
   135  	// A serial number can be up to 20 octets in size.
   136  	return cryptorand.Int(cryptorand.Reader, new(big.Int).Lsh(big.NewInt(1), 8*20))
   137  }
   138  
   139  // writeFile writes data in the file at the given path
   140  func writeFile(filepath string, pem *bytes.Buffer) error {
   141  	f, err := os.Create(filepath)
   142  	if err != nil {
   143  		return err
   144  	}
   145  	defer f.Close()
   146  
   147  	_, err = f.Write(pem.Bytes())
   148  	if err != nil {
   149  		return err
   150  	}
   151  
   152  	return nil
   153  }