mirror of
https://github.com/outbackdingo/kamaji.git
synced 2026-01-27 10:19:29 +00:00
* chore: improve error handling and logging for certificate operations - Enhance error reporting in GenerateCertificatePrivateKeyPair function - Add detailed error checks for CA certificate and private key parsing - Implement check for expected number of certificate files - Improve error logging in APIServerCertificate resource This commit preserves more details about certificate-related issues, aiding in debugging and troubleshooting. * feat: support loadbalancer hostname resolution Add functionality to resolve loadbalancer hostname to IP address in DeclaredControlPlaneAddress method. This enhances the existing IP address handling by allowing the use of hostnames for loadbalancers. - Add hostname check in addition to IP check - Implement hostname resolution using net.LookupIP - Return the first resolved IP address if available * fix: Remove hostname support for LoadBalancer ingress - Extract LoadBalancer address logic to separate function - Remove hostname resolution for LoadBalancer ingress - Add explanatory comments on reasons for not supporting hostnames * fix: replace fmt and vet with golint - Remove fmt and vet targets - Update build target to use golint instead of fmt and vet - Remove fmt and vet dependencies from run target * fix: lint errors
154 lines
4.7 KiB
Go
154 lines
4.7 KiB
Go
// Copyright 2022 Clastix Labs
|
|
// SPDX-License-Identifier: Apache-2.0
|
|
|
|
package kubeadm
|
|
|
|
import (
|
|
"crypto"
|
|
"crypto/x509"
|
|
"fmt"
|
|
"os"
|
|
"path/filepath"
|
|
|
|
kubeadmconstants "k8s.io/kubernetes/cmd/kubeadm/app/constants"
|
|
"k8s.io/kubernetes/cmd/kubeadm/app/phases/certs"
|
|
|
|
cryptoKamaji "github.com/clastix/kamaji/internal/crypto"
|
|
)
|
|
|
|
func GenerateCACertificatePrivateKeyPair(baseName string, config *Configuration) (*CertificatePrivateKeyPair, error) {
|
|
defer deleteCertificateDirectory(config.InitConfiguration.CertificatesDir)
|
|
|
|
kubeadmCert, err := getKubeadmCert(baseName)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
if _, _, err = initPhaseAsCA(kubeadmCert, config); err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
contents, err := readCertificateFiles(baseName, config.InitConfiguration.CertificatesDir, "crt", "key")
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
certificatePrivateKeyPair := &CertificatePrivateKeyPair{
|
|
Certificate: contents[0],
|
|
PrivateKey: contents[1],
|
|
}
|
|
|
|
return certificatePrivateKeyPair, err
|
|
}
|
|
|
|
func GenerateCertificatePrivateKeyPair(baseName string, config *Configuration, ca CertificatePrivateKeyPair) (*CertificatePrivateKeyPair, error) {
|
|
defer deleteCertificateDirectory(config.InitConfiguration.CertificatesDir)
|
|
|
|
certificate, err := cryptoKamaji.ParseCertificateBytes(ca.Certificate)
|
|
if err != nil {
|
|
return nil, fmt.Errorf("failed to parse CA certificate: %w", err)
|
|
}
|
|
|
|
signer, err := cryptoKamaji.ParsePrivateKeyBytes(ca.PrivateKey)
|
|
if err != nil {
|
|
return nil, fmt.Errorf("failed to parse CA private key: %w", err)
|
|
}
|
|
|
|
kubeadmCert, err := getKubeadmCert(baseName)
|
|
if err != nil {
|
|
return nil, fmt.Errorf("failed to get kubeadm cert: %w", err)
|
|
}
|
|
|
|
if err = initPhaseFromCA(kubeadmCert, config, certificate, signer); err != nil {
|
|
return nil, fmt.Errorf("failed to initialize phase from CA: %w", err)
|
|
}
|
|
|
|
contents, err := readCertificateFiles(baseName, config.InitConfiguration.CertificatesDir, "crt", "key")
|
|
if err != nil {
|
|
return nil, fmt.Errorf("failed to read certificate files: %w", err)
|
|
}
|
|
|
|
if len(contents) != 2 {
|
|
return nil, fmt.Errorf("unexpected number of certificate files: expected 2, got %d", len(contents))
|
|
}
|
|
|
|
certificatePrivateKeyPair := &CertificatePrivateKeyPair{
|
|
Certificate: contents[0],
|
|
PrivateKey: contents[1],
|
|
}
|
|
|
|
return certificatePrivateKeyPair, nil
|
|
}
|
|
|
|
func getKubeadmCert(baseName string) (*certs.KubeadmCert, error) {
|
|
switch baseName {
|
|
case kubeadmconstants.CACertAndKeyBaseName:
|
|
return certs.KubeadmCertRootCA(), nil
|
|
case kubeadmconstants.APIServerCertAndKeyBaseName:
|
|
return certs.KubeadmCertAPIServer(), nil
|
|
case kubeadmconstants.APIServerKubeletClientCertAndKeyBaseName:
|
|
return certs.KubeadmCertKubeletClient(), nil
|
|
case kubeadmconstants.FrontProxyCACertAndKeyBaseName:
|
|
return certs.KubeadmCertFrontProxyCA(), nil
|
|
case kubeadmconstants.FrontProxyClientCertAndKeyBaseName:
|
|
return certs.KubeadmCertFrontProxyClient(), nil
|
|
default:
|
|
return nil, fmt.Errorf("wrong ca file name %s", baseName)
|
|
}
|
|
}
|
|
|
|
func GeneratePublicKeyPrivateKeyPair(baseName string, config *Configuration) (*PublicKeyPrivateKeyPair, error) {
|
|
defer deleteCertificateDirectory(config.InitConfiguration.CertificatesDir)
|
|
|
|
if err := initPhaseCertsSA(config); err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
contents, err := readCertificateFiles(baseName, config.InitConfiguration.CertificatesDir, "pub", "key")
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
publicKeyPrivateKeyPair := &PublicKeyPrivateKeyPair{
|
|
PublicKey: contents[0],
|
|
PrivateKey: contents[1],
|
|
}
|
|
|
|
return publicKeyPrivateKeyPair, err
|
|
}
|
|
|
|
func initPhaseCertsSA(config *Configuration) error {
|
|
return certs.CreateServiceAccountKeyAndPublicKeyFiles(config.InitConfiguration.CertificatesDir, config.InitConfiguration.EncryptionAlgorithmType())
|
|
}
|
|
|
|
func initPhaseFromCA(kubeadmCert *certs.KubeadmCert, config *Configuration, certificate *x509.Certificate, signer crypto.Signer) error {
|
|
return kubeadmCert.CreateFromCA(&config.InitConfiguration, certificate, signer)
|
|
}
|
|
|
|
func initPhaseAsCA(kubeadmCert *certs.KubeadmCert, config *Configuration) (*x509.Certificate, crypto.Signer, error) {
|
|
return kubeadmCert.CreateAsCA(&config.InitConfiguration)
|
|
}
|
|
|
|
func readCertificateFiles(name string, directory string, extensions ...string) ([][]byte, error) {
|
|
result := make([][]byte, 0, len(extensions))
|
|
|
|
for _, extension := range extensions {
|
|
fileName := fmt.Sprintf("%s.%s", name, extension)
|
|
path := filepath.Join(directory, fileName)
|
|
content, err := os.ReadFile(path)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
result = append(result, content)
|
|
}
|
|
|
|
return result, nil
|
|
}
|
|
|
|
func deleteCertificateDirectory(certificateDirectory string) {
|
|
if err := os.RemoveAll(certificateDirectory); err != nil {
|
|
// TODO(prometherion): we should log rather than printing to stdout
|
|
fmt.Printf("Error removing %s: %s", certificateDirectory, err.Error()) //nolint:forbidigo
|
|
}
|
|
}
|