github.com/sealerio/sealer@v0.11.1-0.20240507115618-f4f89c5853ae/pkg/clustercert/cert/generator.go (about) 1 // Copyright © 2022 Alibaba Group Holding Ltd. 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 cert 16 17 import ( 18 "crypto" 19 "crypto/ecdsa" 20 "crypto/elliptic" 21 "crypto/rand" 22 "crypto/rsa" 23 "crypto/x509" 24 "crypto/x509/pkix" 25 "encoding/pem" 26 "fmt" 27 "math" 28 "math/big" 29 "net" 30 "os" 31 "path" 32 "path/filepath" 33 "time" 34 35 "github.com/pkg/errors" 36 "github.com/sirupsen/logrus" 37 "k8s.io/client-go/util/keyutil" 38 ) 39 40 const ( 41 // PrivateKeyBlockType is a possible value for pem.Block.Type. 42 PrivateKeyBlockType = "PRIVATE KEY" 43 // PublicKeyBlockType is a possible value for pem.Block.Type. 44 PublicKeyBlockType = "PUBLIC KEY" 45 // CertificateBlockType is a possible value for pem.Block.Type. 46 CertificateBlockType = "CERTIFICATE" 47 // RSAPrivateKeyBlockType is a possible value for pem.Block.Type. 48 RSAPrivateKeyBlockType = "RSA PRIVATE KEY" 49 rsaKeySize = 2048 50 duration365d = time.Hour * 24 * 365 51 ) 52 53 // KeyPairFileGenerator write symmetric encryption key, like: sa.key and sa.pub 54 type KeyPairFileGenerator struct { 55 path string 56 name string 57 } 58 59 func NewKeyPairFileGenerator(certPath string, certName string) KeyPairFileGenerator { 60 return KeyPairFileGenerator{ 61 path: certPath, 62 name: certName, 63 } 64 } 65 66 func (k KeyPairFileGenerator) GenerateAll() error { 67 _, err := os.Stat(path.Join(k.path, "sa.key")) 68 if !os.IsNotExist(err) { 69 logrus.Info("sa.key sa.pub already exist") 70 return nil 71 } 72 73 key, err := NewPrivateKey(x509.RSA) 74 if err != nil { 75 return err 76 } 77 78 err = k.writePrivateKey(key) 79 if err != nil { 80 return err 81 } 82 83 return k.writePublicKey(key.Public()) 84 } 85 86 func (k KeyPairFileGenerator) writePrivateKey(key crypto.Signer) error { 87 if key == nil { 88 return errors.New("private key cannot be nil when writing to file") 89 } 90 91 privateKeyPath := PathForKey(k.path, k.name) 92 encoded, err := keyutil.MarshalPrivateKeyToPEM(key) 93 if err != nil { 94 return fmt.Errorf("unable to marshal private key to PEM :%v", err) 95 } 96 if err := keyutil.WriteKey(privateKeyPath, encoded); err != nil { 97 return fmt.Errorf("unable to write private key to file %s :%v", privateKeyPath, err) 98 } 99 100 return nil 101 } 102 103 func (k KeyPairFileGenerator) writePublicKey(key crypto.PublicKey) error { 104 if key == nil { 105 return errors.New("public key cannot be nil when writing to file") 106 } 107 108 der, err := x509.MarshalPKIXPublicKey(key) 109 if err != nil { 110 return err 111 } 112 113 block := pem.Block{ 114 Type: PublicKeyBlockType, 115 Bytes: der, 116 } 117 118 publicKeyPath := PathForPublicKey(k.path, k.name) 119 if err := keyutil.WriteKey(publicKeyPath, pem.EncodeToMemory(&block)); err != nil { 120 return fmt.Errorf("unable to write public key to file %s %v", publicKeyPath, err) 121 } 122 123 return nil 124 } 125 126 // AltNames contains the domain names and IP addresses that will be added 127 // to the API Server's x509 certificate SubAltNames field. The values will 128 // be passed directly to the x509.Certificate object. 129 type AltNames struct { 130 DNSNames map[string]string 131 IPs map[string]net.IP 132 } 133 134 // CertificateDescriptor contains the basic fields required for creating a certificate 135 type CertificateDescriptor struct { 136 CommonName string 137 DNSNames []string 138 Organization []string 139 Year time.Duration 140 AltNames AltNames 141 Usages []x509.ExtKeyUsage 142 } 143 144 type CertificateGenerator interface { 145 Generate() (*x509.Certificate, crypto.Signer, error) 146 } 147 148 type AuthorityCertificateGenerator struct { 149 config CertificateDescriptor 150 } 151 152 func (m AuthorityCertificateGenerator) Generate() (*x509.Certificate, crypto.Signer, error) { 153 key, err := NewPrivateKey(x509.UnknownPublicKeyAlgorithm) 154 if err != nil { 155 return nil, nil, fmt.Errorf("unable to create private key while generating CA certificate: %v", err) 156 } 157 158 cert, err := m.generateSelfSignedCACert(key) 159 if err != nil { 160 return nil, nil, fmt.Errorf("unable to generate cert %v", err) 161 } 162 163 return cert, key, nil 164 } 165 166 func (m AuthorityCertificateGenerator) generateSelfSignedCACert(key crypto.Signer) (*x509.Certificate, error) { 167 now := time.Now() 168 tmpl := x509.Certificate{ 169 SerialNumber: new(big.Int).SetInt64(0), 170 Subject: pkix.Name{ 171 CommonName: m.config.CommonName, 172 Organization: m.config.Organization, 173 }, 174 DNSNames: m.config.DNSNames, 175 NotBefore: now.UTC(), 176 NotAfter: now.Add(duration365d * m.config.Year).UTC(), 177 KeyUsage: x509.KeyUsageKeyEncipherment | x509.KeyUsageDigitalSignature | x509.KeyUsageCertSign, 178 BasicConstraintsValid: true, 179 IsCA: true, 180 } 181 182 certDERBytes, err := x509.CreateCertificate(rand.Reader, &tmpl, &tmpl, key.Public(), key) 183 if err != nil { 184 return nil, err 185 } 186 return x509.ParseCertificate(certDERBytes) 187 } 188 189 func NewAuthorityCertificateGenerator(config CertificateDescriptor) CertificateGenerator { 190 return AuthorityCertificateGenerator{ 191 config: config, 192 } 193 } 194 195 type CommonCertificateGenerator struct { 196 config CertificateDescriptor 197 caCert *x509.Certificate 198 caKey crypto.Signer 199 } 200 201 func (m CommonCertificateGenerator) Generate() (*x509.Certificate, crypto.Signer, error) { 202 key, err := NewPrivateKey(x509.UnknownPublicKeyAlgorithm) 203 if err != nil { 204 return nil, nil, fmt.Errorf("unable to create private key while generating common certificate: %v", err) 205 } 206 207 cert, err := m.generateSignedCert(key) 208 if err != nil { 209 return nil, nil, fmt.Errorf("failed to generate signed cert: %v", err) 210 } 211 212 return cert, key, nil 213 } 214 215 // generateSignedCert creates a signed certificate using the given CA certificate and key 216 func (m CommonCertificateGenerator) generateSignedCert(key crypto.Signer) (*x509.Certificate, error) { 217 var dnsNames []string 218 var ips []net.IP 219 220 for _, v := range m.config.AltNames.DNSNames { 221 dnsNames = append(dnsNames, v) 222 } 223 for _, v := range m.config.AltNames.IPs { 224 ips = append(ips, v) 225 } 226 227 serial, err := rand.Int(rand.Reader, new(big.Int).SetInt64(math.MaxInt64)) 228 if err != nil { 229 return nil, err 230 } 231 232 certTmpl := x509.Certificate{ 233 Subject: pkix.Name{ 234 CommonName: m.config.CommonName, 235 Organization: m.config.Organization, 236 }, 237 DNSNames: dnsNames, 238 IPAddresses: ips, 239 SerialNumber: serial, 240 NotBefore: m.caCert.NotBefore, 241 NotAfter: time.Now().Add(duration365d * m.config.Year).UTC(), 242 KeyUsage: x509.KeyUsageKeyEncipherment | x509.KeyUsageDigitalSignature, 243 ExtKeyUsage: m.config.Usages, 244 } 245 certDERBytes, err := x509.CreateCertificate(rand.Reader, &certTmpl, m.caCert, key.Public(), m.caKey) 246 if err != nil { 247 return nil, err 248 } 249 return x509.ParseCertificate(certDERBytes) 250 } 251 252 func NewCommonCertificateGenerator(config CertificateDescriptor, caCert *x509.Certificate, caKey crypto.Signer) (CertificateGenerator, error) { 253 if config.CommonName == "" { 254 return nil, errors.New("must specify a CommonName for cert") 255 } 256 257 if len(config.Usages) == 0 { 258 return nil, errors.New("must specify at least one ExtKeyUsage") 259 } 260 261 return CommonCertificateGenerator{ 262 config: config, 263 caCert: caCert, 264 caKey: caKey, 265 }, nil 266 } 267 268 func PathForCert(pkiPath, name string) string { 269 return filepath.Join(pkiPath, fmt.Sprintf("%s.crt", name)) 270 } 271 272 func PathForKey(pkiPath, name string) string { 273 return filepath.Join(pkiPath, fmt.Sprintf("%s.key", name)) 274 } 275 276 func PathForPublicKey(pkiPath, name string) string { 277 return filepath.Join(pkiPath, fmt.Sprintf("%s.pub", name)) 278 } 279 280 // NewPrivateKey creates an RSA private key 281 func NewPrivateKey(keyType x509.PublicKeyAlgorithm) (crypto.Signer, error) { 282 if keyType == x509.ECDSA { 283 return ecdsa.GenerateKey(elliptic.P256(), rand.Reader) 284 } 285 286 return rsa.GenerateKey(rand.Reader, rsaKeySize) 287 } 288 289 // EncodeCertPEM returns PEM-encoded certificate data 290 func EncodeCertPEM(cert *x509.Certificate) []byte { 291 block := pem.Block{ 292 Type: CertificateBlockType, 293 Bytes: cert.Raw, 294 } 295 return pem.EncodeToMemory(&block) 296 }