1
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
43 func ServiceToCommonName(serviceNamespace, serviceName string) string {
44 return fmt.Sprintf("%s.%s.svc", serviceName, serviceNamespace)
45 }
46
47
48
49 type SelfSignedCertGenerator struct {
50 caKey []byte
51 caCert []byte
52 }
53
54 var _ CertGenerator = &SelfSignedCertGenerator{}
55
56
57 func (cp *SelfSignedCertGenerator) SetCA(caKey, caCert []byte) {
58 cp.caKey = caKey
59 cp.caCert = caCert
60 }
61
62
63
64
65
66
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
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
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