Newer
Older
AnthosCertManager / pkg / controller / certificaterequests / selfsigned / selfsigned.go
package selfsigned

import (
	"context"
	"crypto"
	"crypto/x509"
	"errors"
	"fmt"

	acmapi "gitbucket.jerxie.com/yangyangxie/AnthosCertManager/pkg/apis/anthoscertmanager/v1"
	controllerpkg "gitbucket.jerxie.com/yangyangxie/AnthosCertManager/pkg/controller"
	"gitbucket.jerxie.com/yangyangxie/AnthosCertManager/pkg/issuer"
	logf "gitbucket.jerxie.com/yangyangxie/AnthosCertManager/pkg/logs"
	acmerrors "gitbucket.jerxie.com/yangyangxie/AnthosCertManager/pkg/util/errors"
	"gitbucket.jerxie.com/yangyangxie/AnthosCertManager/pkg/util/kube"
	"gitbucket.jerxie.com/yangyangxie/AnthosCertManager/pkg/util/pki"

	corev1 "k8s.io/api/core/v1"
	k8sErrors "k8s.io/apimachinery/pkg/api/errors"

	corelisters "k8s.io/client-go/listers/core/v1"
	"k8s.io/client-go/tools/record"
)

const (
	CRControllerName = "certificaterequests-issuer-selfsigned"
	emptyDNMessage   = "Certificate will be issued with an empty Issuer DN, which contravenes RFC 5280 and could break some strict clients"
)

type signingFn func(*x509.Certificate, *x509.Certificate, crypto.PublicKey, interface{}) ([]byte, *x509.Certificate, error)

type SelfSigned struct {
	issuerOptions controllerpkg.IssuerOptions
	secretsLister corelisters.SecretLister

	// reporter *crutil.Reporter
	recorder record.EventRecorder

	// Used for testing to get reproducible resulting certificates
	signingFn signingFn
}

func (s *SelfSigned) Sign(ctx context.Context, cr *acmapi.CertificateRequest, issuerObj acmapi.GenericIssuer) (*issuer.IssueResponse, error) {
	log := logf.FromContext(ctx, "sign")
	resourceNamespace := s.issuerOptions.ResourceNamespace(issuerObj)

	secretName, ok := cr.ObjectMeta.Annotations[acmapi.CertificateRequestPrivateKeyAnnotationKey]
	if !ok || secretName == "" {
		message := fmt.Sprintf("Annotation %q missing or reference empty", acmapi.CertificateRequestPrivateKeyAnnotationKey)
		err := errors.New("secret name missing")
		// s.reporter.Failed(cr, err, "MissingAnnotation", message)
		log.Error(err, message)
		return nil, nil
	}

	privatekey, err := kube.SecretTLSKey(ctx, s.secretsLister, cr.Namespace, secretName)
	if k8sErrors.IsNotFound(err) {
		message := fmt.Sprintf("Referenced secret %s/%s not found", cr.Namespace, secretName)

		//s.reporter.Pending(cr, err, "MissingSecret", message)
		log.Error(err, message)

		return nil, nil
	}

	if acmerrors.IsInvalidData(err) {
		message := fmt.Sprintf("Failed to get key %q referenced in annotation %q",
			secretName, acmapi.CertificateRequestPrivateKeyAnnotationKey)

		//s.reporter.Pending(cr, err, "ErrorParsingKey", message)
		log.Error(err, message)

		return nil, nil
	}

	if err != nil {
		// We are probably in a network error here so we should backoff and retry
		message := fmt.Sprintf("Failed to get certificate key pair from secret %s/%s", resourceNamespace, secretName)
		//s.reporter.Pending(cr, err, "ErrorGettingSecret", message)
		log.Error(err, message)
		return nil, err
	}

	template, err := pki.GenerateTemplateFromCertificateRequest(cr)
	if err != nil {
		message := "Error generating certificate template"
		//s.reporter.Failed(cr, err, "ErrorGenerating", message)
		log.Error(err, message)
		return nil, nil
	}

	template.CRLDistributionPoints = issuerObj.GetSpec().SelfSigned.CRLDistributionPoints

	if template.Subject.String() == "" {
		// RFC 5280 (https://tools.ietf.org/html/rfc5280#section-4.1.2.4) says that:
		// "The issuer field MUST contain a non-empty distinguished name (DN)."
		// Since we're creating a self-signed cert, the issuer will match whatever is
		// in the template's subject DN.
		log.V(logf.DebugLevel).Info("issued cert will have an empty issuer DN, which contravenes RFC 5280. emitting warning event")
		s.recorder.Event(cr, corev1.EventTypeWarning, "BadConfig", emptyDNMessage)
	}

	// extract the public component of the key
	publickey, err := pki.PublicKeyForPrivateKey(privatekey)
	if err != nil {
		message := "Failed to get public key from private key"
		//s.reporter.Failed(cr, err, "ErrorPublicKey", message)
		log.Error(err, message)
		return nil, nil
	}

	ok, err = pki.PublicKeysEqual(publickey, template.PublicKey)
	if err != nil || !ok {

		if err == nil {
			err = errors.New("CSR not signed by referenced private key")
		}

		message := "Error generating certificate template"
		//s.reporter.Failed(cr, err, "ErrorKeyMatch", message)
		log.Error(err, message)

		return nil, nil
	}

	// sign and encode the certificate
	certPem, _, err := s.signingFn(template, template, publickey, privatekey)
	if err != nil {
		message := "Error signing certificate"
		//s.reporter.Failed(cr, err, "ErrorSigning", message)
		log.Error(err, message)
		return nil, nil
	}

	log.V(logf.DebugLevel).Info("self signed certificate issued")

	// We set the CA to the returned certificate here since this is self signed.
	return &issuer.IssueResponse{
		Certificate: certPem,
		CA:          certPem,
	}, nil

}