| package component | 
 |  | 
 | import ( | 
 | 	"crypto/ed25519" | 
 | 	"crypto/rand" | 
 | 	"crypto/tls" | 
 | 	"crypto/x509" | 
 | 	"encoding/pem" | 
 | 	"fmt" | 
 | 	"math/big" | 
 | 	"os" | 
 | 	"time" | 
 |  | 
 | 	"k8s.io/klog/v2" | 
 |  | 
 | 	"source.monogon.dev/metropolis/pkg/pki" | 
 | ) | 
 |  | 
 | // GetDevCerts returns paths to this component's development certificate, key | 
 | // and CA, or panics if unavailable. | 
 | func (c *ComponentConfig) GetDevCerts() (certPath, keyPath, caPath string) { | 
 | 	klog.Infof("Using developer certificates at %s", c.DevCertsPath) | 
 |  | 
 | 	caPath = c.ensureDevCA() | 
 | 	certPath, keyPath = c.ensureDevComponent() | 
 | 	return | 
 | } | 
 |  | 
 | // ensureDevComponent ensures that a development certificate/key exists for this | 
 | // component and returns paths to them. This data is either read from disk if it | 
 | // already exists, or is generated when this function is called. If any problem | 
 | // occurs, the code panics. | 
 | func (c *ComponentConfig) ensureDevComponent() (certPath, keyPath string) { | 
 | 	caKeyPath := c.DevCertsPath + "/ca.key" | 
 | 	caCertPath := c.DevCertsPath + "/ca.cert" | 
 |  | 
 | 	// Load CA. By convention, we are always called after ensureDevCA. | 
 | 	ca, err := tls.LoadX509KeyPair(caCertPath, caKeyPath) | 
 | 	if err != nil { | 
 | 		klog.Exitf("Could not load Dev CA: %v", err) | 
 | 	} | 
 | 	caCert, err := x509.ParseCertificate(ca.Certificate[0]) | 
 | 	if err != nil { | 
 | 		klog.Exitf("Could not parse Dev CA: %v", err) | 
 | 	} | 
 |  | 
 | 	// Check if we have keys already. | 
 | 	keyPath = c.DevCertsPath + fmt.Sprintf("/%s.key", c.ComponentName) | 
 | 	certPath = c.DevCertsPath + fmt.Sprintf("/%s.crt", c.ComponentName) | 
 | 	noKey := false | 
 | 	if _, err := os.Stat(keyPath); os.IsNotExist(err) { | 
 | 		noKey = true | 
 | 	} | 
 | 	noCert := false | 
 | 	if _, err := os.Stat(certPath); os.IsNotExist(err) { | 
 | 		noCert = true | 
 | 	} | 
 |  | 
 | 	if noKey || noCert { | 
 | 		klog.Infof("Generating developer %s certificate...", c.ComponentName) | 
 | 	} else { | 
 | 		return | 
 | 	} | 
 |  | 
 | 	// Generate key/certificate. | 
 | 	cert := pki.Server([]string{ | 
 | 		fmt.Sprintf("%s.local", c.ComponentName), | 
 | 	}, nil) | 
 |  | 
 | 	serialNumberLimit := new(big.Int).Lsh(big.NewInt(1), 127) | 
 | 	serialNumber, err := rand.Int(rand.Reader, serialNumberLimit) | 
 | 	if err != nil { | 
 | 		klog.Exitf("Failed to generate %s serial number: %v", c.ComponentName, err) | 
 | 	} | 
 | 	cert.ExtKeyUsage = append(cert.ExtKeyUsage, x509.ExtKeyUsageClientAuth) | 
 | 	cert.SerialNumber = serialNumber | 
 | 	cert.NotBefore = time.Now() | 
 | 	cert.NotAfter = pki.UnknownNotAfter | 
 | 	cert.BasicConstraintsValid = true | 
 |  | 
 | 	pub, priv, err := ed25519.GenerateKey(rand.Reader) | 
 | 	if err != nil { | 
 | 		klog.Exitf("Failed to generate %s key: %v", c.ComponentName, err) | 
 | 	} | 
 | 	certBytes, err := x509.CreateCertificate(rand.Reader, &cert, caCert, pub, ca.PrivateKey) | 
 | 	if err != nil { | 
 | 		klog.Exitf("Failed to generate %s certificate: %v", c.ComponentName, err) | 
 | 	} | 
 |  | 
 | 	// And marshal them to disk. | 
 | 	privPKCS, err := x509.MarshalPKCS8PrivateKey(priv) | 
 | 	if err != nil { | 
 | 		klog.Exitf("Failed to marshal %s private key: %v", c.ComponentName, err) | 
 | 	} | 
 | 	err = os.WriteFile(keyPath, pem.EncodeToMemory(&pem.Block{ | 
 | 		Type:  "PRIVATE KEY", | 
 | 		Bytes: privPKCS, | 
 | 	}), 0600) | 
 | 	if err != nil { | 
 | 		klog.Exitf("Failed to write %s private key: %v", c.ComponentName, err) | 
 | 	} | 
 | 	err = os.WriteFile(certPath, pem.EncodeToMemory(&pem.Block{ | 
 | 		Type:  "CERTIFICATE", | 
 | 		Bytes: certBytes, | 
 | 	}), 0644) | 
 | 	if err != nil { | 
 | 		klog.Exitf("Failed to write %s certificate: %v", c.ComponentName, err) | 
 | 	} | 
 |  | 
 | 	return | 
 | } | 
 |  | 
 | // ensureDevCA ensures that a development CA certificate/key exists and returns | 
 | // paths to them. This data is either read from disk if it already exists, or is | 
 | // generated when this function is called. If any problem occurs, the code | 
 | // panics. | 
 | func (c *ComponentConfig) ensureDevCA() (caCertPath string) { | 
 | 	caKeyPath := c.DevCertsPath + "/ca.key" | 
 | 	caCertPath = c.DevCertsPath + "/ca.cert" | 
 |  | 
 | 	if err := os.MkdirAll(c.DevCertsPath, 0700); err != nil { | 
 | 		klog.Exitf("Failed to make developer certificate directory: %v", err) | 
 | 	} | 
 |  | 
 | 	// Check if we already have a key/certificate. | 
 | 	noKey := false | 
 | 	if _, err := os.Stat(caKeyPath); os.IsNotExist(err) { | 
 | 		noKey = true | 
 | 	} | 
 | 	noCert := false | 
 | 	if _, err := os.Stat(caCertPath); os.IsNotExist(err) { | 
 | 		noCert = true | 
 | 	} | 
 |  | 
 | 	if noKey || noCert { | 
 | 		klog.Infof("Generating developer CA certificate...") | 
 | 	} else { | 
 | 		return | 
 | 	} | 
 | 	hostname, err := os.Hostname() | 
 | 	if err != nil { | 
 | 		hostname = "unknown" | 
 | 	} | 
 |  | 
 | 	// No key/certificate, generate them. | 
 | 	ca := pki.CA(fmt.Sprintf("monogon dev certs CA (%s)", hostname)) | 
 |  | 
 | 	serialNumberLimit := new(big.Int).Lsh(big.NewInt(1), 127) | 
 | 	serialNumber, err := rand.Int(rand.Reader, serialNumberLimit) | 
 | 	if err != nil { | 
 | 		klog.Exitf("Failed to generate CA serial number: %v", err) | 
 | 	} | 
 | 	ca.SerialNumber = serialNumber | 
 | 	ca.NotBefore = time.Now() | 
 | 	ca.NotAfter = pki.UnknownNotAfter | 
 | 	ca.BasicConstraintsValid = true | 
 |  | 
 | 	caPub, caPriv, err := ed25519.GenerateKey(rand.Reader) | 
 | 	if err != nil { | 
 | 		klog.Exitf("Failed to generate CA key: %v", err) | 
 | 	} | 
 | 	caBytes, err := x509.CreateCertificate(rand.Reader, &ca, &ca, caPub, caPriv) | 
 | 	if err != nil { | 
 | 		klog.Exitf("Failed to generate CA certificate: %v", err) | 
 | 	} | 
 |  | 
 | 	// And marshal them to disk. | 
 | 	caPrivPKCS, err := x509.MarshalPKCS8PrivateKey(caPriv) | 
 | 	if err != nil { | 
 | 		klog.Exitf("Failed to marshal %s private key: %v", c.ComponentName, err) | 
 | 	} | 
 | 	err = os.WriteFile(caKeyPath, pem.EncodeToMemory(&pem.Block{ | 
 | 		Type:  "PRIVATE KEY", | 
 | 		Bytes: caPrivPKCS, | 
 | 	}), 0600) | 
 | 	if err != nil { | 
 | 		klog.Exitf("Failed to write CA private key: %v", err) | 
 | 	} | 
 | 	err = os.WriteFile(caCertPath, pem.EncodeToMemory(&pem.Block{ | 
 | 		Type:  "CERTIFICATE", | 
 | 		Bytes: caBytes, | 
 | 	}), 0644) | 
 | 	if err != nil { | 
 | 		klog.Exitf("Failed to write CA certificate: %v", err) | 
 | 	} | 
 |  | 
 | 	return | 
 | } |