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 }