github.com/googlecloudplatform/kubernetes-workshops@v0.0.0-20180501174420-d8199445b2c3/bundles/kubernetes-101/workshop/app/certgen/main.go (about)

     1  // Copyright 2016 Google, Inc. All rights reserved.
     2  // Use of this source code is governed by a BSD-style
     3  // license that can be found in the LICENSE file.
     4  
     5  package main
     6  
     7  import (
     8  	"crypto/rand"
     9  	"crypto/rsa"
    10  	"crypto/sha1"
    11  	"crypto/x509"
    12  	"crypto/x509/pkix"
    13  	"encoding/pem"
    14  	"flag"
    15  	"fmt"
    16  	"log"
    17  	"math/big"
    18  	"net"
    19  	"os"
    20  	"strings"
    21  	"time"
    22  )
    23  
    24  var (
    25  	notBefore, notAfter time.Time
    26  	serialNumberLimit   *big.Int
    27  	rsaBits             = 2048
    28  	host                string
    29  )
    30  
    31  var serverSubjectAlternateNames = []string{
    32  	"*.example.com",
    33  	"localhost",
    34  	"127.0.0.1",
    35  }
    36  
    37  type certificateConfig struct {
    38  	isCA        bool
    39  	caCert      *x509.Certificate
    40  	caKey       *rsa.PrivateKey
    41  	hosts       []string
    42  	keyUsage    x509.KeyUsage
    43  	extKeyUsage []x509.ExtKeyUsage
    44  }
    45  
    46  func init() {
    47  	notBefore = time.Now().Add(-5 * time.Minute).UTC()
    48  	notAfter = notBefore.Add(365 * 24 * time.Hour).UTC()
    49  	serialNumberLimit = new(big.Int).Lsh(big.NewInt(1), 128)
    50  
    51  	flag.StringVar(&host, "host", "", "Comma-separated hostnames and IPs to generate a certificate for")
    52  }
    53  
    54  func main() {
    55  	flag.Parse()
    56  
    57  	// Generate CA
    58  	caCert, caKey, err := generateCertificate(certificateConfig{
    59  		isCA:        true,
    60  		hosts:       []string{""},
    61  		keyUsage:    x509.KeyUsageKeyEncipherment | x509.KeyUsageDigitalSignature | x509.KeyUsageCertSign,
    62  		extKeyUsage: []x509.ExtKeyUsage{x509.ExtKeyUsageServerAuth},
    63  	})
    64  	if err != nil {
    65  		log.Fatal(err)
    66  	}
    67  
    68  	err = writeCert("ca", caCert, caKey)
    69  	if err != nil {
    70  		log.Fatal(err)
    71  	}
    72  
    73  	caParsedCertificates, err := x509.ParseCertificates(caCert)
    74  	if err != nil {
    75  		log.Fatal(err)
    76  	}
    77  
    78  	// Generate Server Certificates
    79  	hosts := make([]string, 0)
    80  	for _, h := range strings.Split(host, ",") {
    81  		if h == "" {
    82  			continue
    83  		}
    84  		hosts = append(hosts, h)
    85  	}
    86  	hosts = append(hosts, serverSubjectAlternateNames...)
    87  
    88  	serverCert, serverKey, err := generateCertificate(certificateConfig{
    89  		caCert:      caParsedCertificates[0],
    90  		caKey:       caKey,
    91  		hosts:       hosts,
    92  		keyUsage:    x509.KeyUsageKeyEncipherment | x509.KeyUsageDigitalSignature,
    93  		extKeyUsage: []x509.ExtKeyUsage{x509.ExtKeyUsageServerAuth},
    94  	})
    95  	if err != nil {
    96  		log.Fatal(err)
    97  	}
    98  
    99  	err = writeCert("server", serverCert, serverKey)
   100  	if err != nil {
   101  		log.Fatal(err)
   102  	}
   103  }
   104  
   105  func writeCert(name string, cert []byte, key *rsa.PrivateKey) error {
   106  	certFilename := fmt.Sprintf("%s.pem", name)
   107  	keyFilename := fmt.Sprintf("%s-key.pem", name)
   108  
   109  	certFile, err := os.Create(certFilename)
   110  	if err != nil {
   111  		return err
   112  	}
   113  	pem.Encode(certFile, &pem.Block{Type: "CERTIFICATE", Bytes: cert})
   114  	certFile.Close()
   115  	fmt.Printf("wrote %s\n", certFilename)
   116  
   117  	keyFile, err := os.OpenFile(keyFilename, os.O_WRONLY|os.O_CREATE|os.O_TRUNC, 0600)
   118  	if err != nil {
   119  		return err
   120  	}
   121  	pem.Encode(keyFile, &pem.Block{
   122  		Type:  "RSA PRIVATE KEY",
   123  		Bytes: x509.MarshalPKCS1PrivateKey(key),
   124  	})
   125  	keyFile.Close()
   126  	fmt.Printf("wrote %s\n", keyFilename)
   127  	return nil
   128  }
   129  
   130  func generateCertificate(c certificateConfig) ([]byte, *rsa.PrivateKey, error) {
   131  	serialNumber, err := rand.Int(rand.Reader, serialNumberLimit)
   132  	if err != nil {
   133  		return nil, nil, err
   134  	}
   135  
   136  	key, err := rsa.GenerateKey(rand.Reader, 2048)
   137  	if err != nil {
   138  		return nil, nil, err
   139  	}
   140  
   141  	// Generate the subject key ID
   142  	derEncodedPubKey, err := x509.MarshalPKIXPublicKey(&key.PublicKey)
   143  	if err != nil {
   144  		return nil, nil, err
   145  	}
   146  	pubKeyHash := sha1.New()
   147  	pubKeyHash.Write(derEncodedPubKey)
   148  
   149  	template := x509.Certificate{
   150  		SerialNumber: serialNumber,
   151  		Subject: pkix.Name{
   152  			Organization: []string{"Kubernetes"},
   153  		},
   154  		NotBefore:             notBefore,
   155  		NotAfter:              notAfter,
   156  		IsCA:                  c.isCA,
   157  		KeyUsage:              c.keyUsage,
   158  		ExtKeyUsage:           c.extKeyUsage,
   159  		BasicConstraintsValid: true,
   160  		SubjectKeyId:          pubKeyHash.Sum(nil),
   161  	}
   162  	if c.hosts[0] != "" {
   163  		template.Subject.CommonName = c.hosts[0]
   164  	}
   165  
   166  	if c.isCA {
   167  		c.caCert = &template
   168  		c.caKey = key
   169  	}
   170  
   171  	for _, h := range c.hosts {
   172  		if ip := net.ParseIP(h); ip != nil {
   173  			template.IPAddresses = append(template.IPAddresses, ip)
   174  		} else {
   175  			template.DNSNames = append(template.DNSNames, h)
   176  		}
   177  	}
   178  
   179  	derBytes, err := x509.CreateCertificate(rand.Reader, &template, c.caCert, &key.PublicKey, c.caKey)
   180  	if err != nil {
   181  		return nil, nil, err
   182  	}
   183  
   184  	return derBytes, key, nil
   185  }