Newer
Older
AnthosCertManager / pkg / controller / certificates / issuing / internal / secret.go
package internal

import (
	coreclient "k8s.io/client-go/kubernetes/typed/core/v1"
	corelisters "k8s.io/client-go/listers/core/v1"

	acmapi "gitbucket.jerxie.com/yangyangxie/AnthosCertManager/pkg/apis/anthoscertmanager/v1"
)

var (
	certificateGvk = acmapi.SchemeGroupVersion.WithKind("Certificate")
)

// SecretsManager creates and updates secrets with certificate and key data.
type SecretsManager struct {
	secretClient coreclient.SecretsGetter
	secretLister corelisters.SecretLister

	// fieldManager is the manager name used for the Apply operations on Secrets.
	fieldManager string

	// if true, Secret resources created by the controller will have an
	// 'owner reference' set, meaning when the Certificate is deleted, the
	// Secret resource will be automatically deleted.
	// This option is disabled by default.
	enableSecretOwnerReferences bool
}

// SecretData is a structure wrapping private key, Certificate and CA data
type SecretData struct {
	PrivateKey, Certificate, CA []byte
}

// NewSecretsManager returns a new SecretsManager. Setting
// enableSecretOwnerReferences to true will mean that secrets will be deleted
// when the corresponding Certificate is deleted.
func NewSecretsManager(
	secretClient coreclient.SecretsGetter,
	secretLister corelisters.SecretLister,
	fieldManager string,
	enableSecretOwnerReferences bool,
) *SecretsManager {
	return &SecretsManager{
		secretClient:                secretClient,
		secretLister:                secretLister,
		fieldManager:                fieldManager,
		enableSecretOwnerReferences: enableSecretOwnerReferences,
	}
}

// // UpdateData will ensure the Secret resource contains the given secret data as
// // well as appropriate metadata using an Apply call.
// // If the Secret resource does not exist, it will be created on Apply.
// // UpdateData will also update deprecated annotations if they exist.
// func (s *SecretsManager) UpdateData(ctx context.Context, crt *acmapi.Certificate, data SecretData) error {
// 	secret, err := s.getCertificateSecret(ctx, crt)
// 	if err != nil {
// 		return err
// 	}

// 	log := logf.FromContext(ctx).WithName("secrets_manager")
// 	log = logf.WithResource(log, secret)

// 	if err := s.setValues(crt, secret, data); err != nil {
// 		return err
// 	}

// 	// Build Secret apply configuration and options.
// 	applyOpts := metav1.ApplyOptions{FieldManager: s.fieldManager, Force: true}
// 	applyCnf := applycorev1.Secret(secret.Name, secret.Namespace).
// 		WithAnnotations(secret.Annotations).WithLabels(secret.Labels).
// 		WithData(secret.Data).WithType(secret.Type)

// 	// If Secret owner reference is enabled, set it on the Secret. This results
// 	// in a no-op if the Secret already exists and has the owner reference set,
// 	// and visa-versa.
// 	if s.enableSecretOwnerReferences {
// 		ref := *metav1.NewControllerRef(crt, certificateGvk)
// 		applyCnf = applyCnf.WithOwnerReferences(&applymetav1.OwnerReferenceApplyConfiguration{
// 			APIVersion: &ref.APIVersion, Kind: &ref.Kind,
// 			Name: &ref.Name, UID: &ref.UID,
// 			Controller: ref.Controller, BlockOwnerDeletion: ref.BlockOwnerDeletion,
// 		})
// 	}

// 	log.V(logf.DebugLevel).Info("applying secret")

// 	_, err = s.secretClient.Secrets(secret.Namespace).Apply(ctx, applyCnf, applyOpts)
// 	if err != nil {
// 		return fmt.Errorf("failed to apply secret %s/%s: %w", secret.Namespace, secret.Name, err)
// 	}

// 	return nil
// }

// // setValues will update the Secret resource 'secret' with the data contained
// // in the given secretData.
// // It will update labels and annotations on the Secret resource appropriately.
// // The Secret resource 's' must be non-nil, although may be a resource that does
// // not exist in the Kubernetes apiserver yet.
// // setValues will NOT actually update the resource in the apiserver.
// // It will also update depreciated issuer name and kind annotations if they
// // exist.
// func (s *SecretsManager) setValues(crt *acmapi.Certificate, secret *corev1.Secret, data SecretData) error {
// 	if err := s.setKeystores(crt, secret, data); err != nil {
// 		return fmt.Errorf("failed to add keystores to Secret: %w", err)
// 	}

// 	// Add additional output formats if feature enabled.
// 	if utilfeature.DefaultFeatureGate.Enabled(feature.AdditionalCertificateOutputFormats) {
// 		if err := setAdditionalOutputFormats(crt, secret, data); err != nil {
// 			return fmt.Errorf("failed to add additional output formats to Secret: %w", err)
// 		}
// 	}

// 	secret.Data[corev1.TLSPrivateKeyKey] = data.PrivateKey
// 	secret.Data[corev1.TLSCertKey] = data.Certificate
// 	if len(data.CA) > 0 {
// 		secret.Data[acmmeta.TLSCAKey] = data.CA
// 	}

// 	var certificate *x509.Certificate
// 	if len(data.Certificate) > 0 {
// 		var err error
// 		certificate, err = utilpki.DecodeX509CertificateBytes(data.Certificate)
// 		// TODO: handle InvalidData here?
// 		if err != nil {
// 			return err
// 		}
// 	}

// 	secret.Annotations = certificates.AnnotationsForCertificateSecret(crt, certificate)
// 	if secret.Labels == nil {
// 		secret.Labels = make(map[string]string)
// 	}

// 	if crt.Spec.SecretTemplate != nil {
// 		for k, v := range crt.Spec.SecretTemplate.Labels {
// 			secret.Labels[k] = v
// 		}
// 		for k, v := range crt.Spec.SecretTemplate.Annotations {
// 			secret.Annotations[k] = v
// 		}
// 	}

// 	return nil
// }

// // getCertificateSecret will return a secret which is ready for fields to be
// // applied. Only the Secret Type will be persisted from the original Secret.
// func (s *SecretsManager) getCertificateSecret(ctx context.Context, crt *cmapi.Certificate) (*corev1.Secret, error) {
// 	// Get existing secret if it exists.
// 	existingSecret, err := s.secretLister.Secrets(crt.Namespace).Get(crt.Spec.SecretName)

// 	// If secret doesn't exist yet, return an empty secret that should be
// 	// created.
// 	if apierrors.IsNotFound(err) {
// 		return &corev1.Secret{
// 			ObjectMeta: metav1.ObjectMeta{
// 				Name:      crt.Spec.SecretName,
// 				Namespace: crt.Namespace,
// 			},
// 			Data: make(map[string][]byte),
// 			Type: corev1.SecretTypeTLS,
// 		}, nil
// 	}

// 	// Transient error.
// 	if err != nil {
// 		return nil, err
// 	}

// 	// Only copy Secret Type to not take ownership of annotations or labels on
// 	// Apply.
// 	return &corev1.Secret{
// 		ObjectMeta: metav1.ObjectMeta{
// 			Name:      crt.Spec.SecretName,
// 			Namespace: crt.Namespace,
// 		},
// 		Data: make(map[string][]byte),
// 		// Use the existing Secret's type since this may not be of type
// 		// `kubernetes.io/tls`, if for example it was created beforehand. Type is
// 		// immutable, so we must keep it to its original value.
// 		Type: existingSecret.Type,
// 	}, nil
// }

// // setKeystores will set extra Secret Data keys according to any Keystores
// // which have been configured.
// func (s *SecretsManager) setKeystores(crt *acmapi.Certificate, secret *corev1.Secret, data SecretData) error {
// 	// Handle the experimental PKCS12 support
// 	if crt.Spec.Keystores != nil && crt.Spec.Keystores.PKCS12 != nil && crt.Spec.Keystores.PKCS12.Create {
// 		ref := crt.Spec.Keystores.PKCS12.PasswordSecretRef
// 		pwSecret, err := s.secretLister.Secrets(crt.Namespace).Get(ref.Name)
// 		if err != nil {
// 			return fmt.Errorf("fetching PKCS12 keystore password from Secret: %v", err)
// 		}
// 		if pwSecret.Data == nil || len(pwSecret.Data[ref.Key]) == 0 {
// 			return fmt.Errorf("PKCS12 keystore password Secret contains no data for key %q", ref.Key)
// 		}
// 		pw := pwSecret.Data[ref.Key]
// 		keystoreData, err := encodePKCS12Keystore(string(pw), data.PrivateKey, data.Certificate, data.CA)
// 		if err != nil {
// 			return fmt.Errorf("error encoding PKCS12 bundle: %w", err)
// 		}
// 		// always overwrite the keystore entry for now
// 		secret.Data[pkcs12SecretKey] = keystoreData

// 		if len(data.CA) > 0 {
// 			truststoreData, err := encodePKCS12Truststore(string(pw), data.CA)
// 			if err != nil {
// 				return fmt.Errorf("error encoding PKCS12 trust store bundle: %w", err)
// 			}
// 			// always overwrite the truststore entry
// 			secret.Data[pkcs12TruststoreKey] = truststoreData
// 		}
// 	}

// 	// Handle the experimental JKS support
// 	if crt.Spec.Keystores != nil && crt.Spec.Keystores.JKS != nil && crt.Spec.Keystores.JKS.Create {
// 		ref := crt.Spec.Keystores.JKS.PasswordSecretRef
// 		pwSecret, err := s.secretLister.Secrets(crt.Namespace).Get(ref.Name)
// 		if err != nil {
// 			return fmt.Errorf("fetching JKS keystore password from Secret: %v", err)
// 		}
// 		if pwSecret.Data == nil || len(pwSecret.Data[ref.Key]) == 0 {
// 			return fmt.Errorf("JKS keystore password Secret contains no data for key %q", ref.Key)
// 		}
// 		pw := pwSecret.Data[ref.Key]
// 		keystoreData, err := encodeJKSKeystore(pw, data.PrivateKey, data.Certificate, data.CA)
// 		if err != nil {
// 			return fmt.Errorf("error encoding JKS bundle: %w", err)
// 		}
// 		// always overwrite the keystore entry
// 		secret.Data[jksSecretKey] = keystoreData

// 		if len(data.CA) > 0 {
// 			truststoreData, err := encodeJKSTruststore(pw, data.CA)
// 			if err != nil {
// 				return fmt.Errorf("error encoding JKS trust store bundle: %w", err)
// 			}
// 			// always overwrite the keystore entry
// 			secret.Data[jksTruststoreKey] = truststoreData
// 		}
// 	}

// 	return nil
// }

// // setAdditionalOutputFormat will set extra Secret Data keys with additional
// // output formats according to any OutputFormats which have been configured.
// func setAdditionalOutputFormats(crt *acmapi.Certificate, secret *corev1.Secret, data SecretData) error {
// 	for _, format := range crt.Spec.AdditionalOutputFormats {
// 		switch format.Type {
// 		case cmapi.CertificateOutputFormatDER:
// 			// Store binary format of the private key
// 			secret.Data[cmapi.CertificateOutputFormatDERKey] = certificates.OutputFormatDER(data.PrivateKey)
// 		case cmapi.CertificateOutputFormatCombinedPEM:
// 			// Combine tls.key and tls.crt
// 			secret.Data[cmapi.CertificateOutputFormatCombinedPEMKey] = certificates.OutputFormatCombinedPEM(data.PrivateKey, data.Certificate)
// 		default:
// 			return fmt.Errorf("unknown additional output format %s", format.Type)
// 		}
// 	}

// 	return nil
// }