github.com/theishshah/operator-sdk@v0.6.0/pkg/tls/primitives.go (about) 1 // Copyright 2018 The Operator-SDK Authors 2 // 3 // Licensed under the Apache License, Version 2.0 (the "License"); 4 // you may not use this file except in compliance with the License. 5 // You may obtain a copy of the License at 6 // 7 // http://www.apache.org/licenses/LICENSE-2.0 8 // 9 // Unless required by applicable law or agreed to in writing, software 10 // distributed under the License is distributed on an "AS IS" BASIS, 11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 // See the License for the specific language governing permissions and 13 // limitations under the License. 14 15 package tlsutil 16 17 import ( 18 "crypto/rand" 19 "crypto/rsa" 20 "crypto/x509" 21 "crypto/x509/pkix" 22 "encoding/pem" 23 "errors" 24 "fmt" 25 "math" 26 "math/big" 27 "time" 28 29 "k8s.io/api/core/v1" 30 ) 31 32 const ( 33 rsaKeySize = 2048 34 duration365d = time.Hour * 24 * 365 35 ) 36 37 // newPrivateKey returns randomly generated RSA private key. 38 func newPrivateKey() (*rsa.PrivateKey, error) { 39 return rsa.GenerateKey(rand.Reader, rsaKeySize) 40 } 41 42 // encodePrivateKeyPEM encodes the given private key pem and returns bytes (base64). 43 func encodePrivateKeyPEM(key *rsa.PrivateKey) []byte { 44 return pem.EncodeToMemory(&pem.Block{ 45 Type: "RSA PRIVATE KEY", 46 Bytes: x509.MarshalPKCS1PrivateKey(key), 47 }) 48 } 49 50 // encodeCertificatePEM encodes the given certificate pem and returns bytes (base64). 51 func encodeCertificatePEM(cert *x509.Certificate) []byte { 52 return pem.EncodeToMemory(&pem.Block{ 53 Type: "CERTIFICATE", 54 Bytes: cert.Raw, 55 }) 56 } 57 58 // parsePEMEncodedCert parses a certificate from the given pemdata 59 func parsePEMEncodedCert(pemdata []byte) (*x509.Certificate, error) { 60 decoded, _ := pem.Decode(pemdata) 61 if decoded == nil { 62 return nil, errors.New("no PEM data found") 63 } 64 return x509.ParseCertificate(decoded.Bytes) 65 } 66 67 // parsePEMEncodedPrivateKey parses a private key from given pemdata 68 func parsePEMEncodedPrivateKey(pemdata []byte) (*rsa.PrivateKey, error) { 69 decoded, _ := pem.Decode(pemdata) 70 if decoded == nil { 71 return nil, errors.New("no PEM data found") 72 } 73 return x509.ParsePKCS1PrivateKey(decoded.Bytes) 74 } 75 76 // newSelfSignedCACertificate returns a self-signed CA certificate based on given configuration and private key. 77 // The certificate has one-year lease. 78 func newSelfSignedCACertificate(key *rsa.PrivateKey) (*x509.Certificate, error) { 79 serial, err := rand.Int(rand.Reader, new(big.Int).SetInt64(math.MaxInt64)) 80 if err != nil { 81 return nil, err 82 } 83 now := time.Now() 84 tmpl := x509.Certificate{ 85 SerialNumber: serial, 86 NotBefore: now.UTC(), 87 NotAfter: now.Add(duration365d).UTC(), 88 KeyUsage: x509.KeyUsageKeyEncipherment | x509.KeyUsageDigitalSignature | x509.KeyUsageCertSign, 89 BasicConstraintsValid: true, 90 IsCA: true, 91 } 92 certDERBytes, err := x509.CreateCertificate(rand.Reader, &tmpl, &tmpl, key.Public(), key) 93 if err != nil { 94 return nil, err 95 } 96 return x509.ParseCertificate(certDERBytes) 97 } 98 99 // newSignedCertificate signs a certificate using the given private key, CA and returns a signed certificate. 100 // The certificate could be used for both client and server auth. 101 // The certificate has one-year lease. 102 func newSignedCertificate(cfg *CertConfig, service *v1.Service, key *rsa.PrivateKey, caCert *x509.Certificate, caKey *rsa.PrivateKey) (*x509.Certificate, error) { 103 serial, err := rand.Int(rand.Reader, new(big.Int).SetInt64(math.MaxInt64)) 104 if err != nil { 105 return nil, err 106 } 107 eku := []x509.ExtKeyUsage{} 108 switch cfg.CertType { 109 case ClientCert: 110 eku = append(eku, x509.ExtKeyUsageClientAuth) 111 case ServingCert: 112 eku = append(eku, x509.ExtKeyUsageServerAuth) 113 case ClientAndServingCert: 114 eku = append(eku, x509.ExtKeyUsageClientAuth, x509.ExtKeyUsageServerAuth) 115 } 116 certTmpl := x509.Certificate{ 117 Subject: pkix.Name{ 118 CommonName: cfg.CommonName, 119 Organization: cfg.Organization, 120 }, 121 DNSNames: []string{fmt.Sprintf("%s.%s.svc.cluster.local", service.Name, service.Namespace)}, 122 SerialNumber: serial, 123 NotBefore: caCert.NotBefore, 124 NotAfter: time.Now().Add(duration365d).UTC(), 125 KeyUsage: x509.KeyUsageKeyEncipherment | x509.KeyUsageDigitalSignature, 126 ExtKeyUsage: eku, 127 } 128 certDERBytes, err := x509.CreateCertificate(rand.Reader, &certTmpl, caCert, key.Public(), caKey) 129 if err != nil { 130 return nil, err 131 } 132 return x509.ParseCertificate(certDERBytes) 133 }