github.com/jenkins-x/jx/v2@v2.1.155/pkg/kube/pki/cert-manager.go (about)

     1  package pki
     2  
     3  import (
     4  	"github.com/jenkins-x/jx-logging/pkg/log"
     5  	"github.com/jenkins-x/jx/v2/pkg/kube"
     6  	"github.com/jenkins-x/jx/v2/pkg/util"
     7  	certmng "github.com/jetstack/cert-manager/pkg/apis/certmanager/v1alpha1"
     8  	certclient "github.com/jetstack/cert-manager/pkg/client/clientset/versioned"
     9  	"github.com/pkg/errors"
    10  	metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
    11  )
    12  
    13  const (
    14  	// CertManagerNamespace indicates the namespace where is cert-manager deployed
    15  	CertManagerNamespace = "cert-manager"
    16  	// CertManagerDeployment indicates the name of the cert-manager deployment
    17  	CertManagerDeployment = "cert-manager"
    18  	// CertManagerReleaseName indicates the release name for cert-manager chart
    19  	CertManagerReleaseName = "cert-manager"
    20  	// CertManagerChartOwner is the owner of the cert-manager chart repo
    21  	CertManagerChartOwner = "jetstack"
    22  	// CertManagerChartURL is the URL for the repo containing the cert-manager chart
    23  	CertManagerChartURL = "https://charts.jetstack.io"
    24  	// CertManagerChart name of the cert-manager chart
    25  	CertManagerChart = "jetstack/cert-manager"
    26  	// CertManagerCRDsFile files which contains the cert-manager CRDs
    27  	CertManagerCRDsFile = "https://raw.githubusercontent.com/jetstack/cert-manager/v0.9.1/deploy/manifests/00-crds.yaml"
    28  
    29  	// CertManagerIssuerProd name of the production issuer
    30  	CertManagerIssuerProd       = "letsencrypt-prod"
    31  	certManagerIssuerProdServer = "https://acme-v02.api.letsencrypt.org/directory"
    32  
    33  	// CertManagerIssuerStaging name of the staging issuer
    34  	CertManagerIssuerStaging       = "letsencrypt-staging"
    35  	certManagerIssuerStagingServer = "https://acme-staging-v02.api.letsencrypt.org/directory"
    36  )
    37  
    38  // CleanCertManagerResources removed the cert-manager resources from the given namespaces
    39  func CleanCertManagerResources(certclient certclient.Interface, ns string, ic kube.IngressConfig) error {
    40  	if ic.Issuer == CertManagerIssuerProd {
    41  		_, err := certclient.CertmanagerV1alpha1().Issuers(ns).Get(CertManagerIssuerProd, metav1.GetOptions{})
    42  		if err == nil {
    43  			err := certclient.CertmanagerV1alpha1().Issuers(ns).Delete(CertManagerIssuerProd, &metav1.DeleteOptions{})
    44  			if err != nil {
    45  				return errors.Wrapf(err, "deleting cert-manager issuer %q", CertManagerIssuerProd)
    46  			}
    47  		}
    48  		_ = certclient.CertmanagerV1alpha1().Certificates(ns).Delete(CertManagerIssuerProd, &metav1.DeleteOptions{})
    49  	} else {
    50  		_, err := certclient.CertmanagerV1alpha1().Issuers(ns).Get(CertManagerIssuerStaging, metav1.GetOptions{})
    51  		if err == nil {
    52  			err := certclient.CertmanagerV1alpha1().Issuers(ns).Delete(CertManagerIssuerStaging, &metav1.DeleteOptions{})
    53  			if err != nil {
    54  				return errors.Wrapf(err, "deleting cert-manager issuer %q", CertManagerIssuerStaging)
    55  			}
    56  		}
    57  		_ = certclient.CertmanagerV1alpha1().Certificates(ns).Delete(CertManagerIssuerStaging, &metav1.DeleteOptions{})
    58  	}
    59  	return nil
    60  }
    61  
    62  // CreateIssuer creates a cert-manager issuer according with the ingress configuration
    63  func CreateIssuer(certclient certclient.Interface, ns string, ic kube.IngressConfig) error {
    64  	if ic.Issuer == CertManagerIssuerProd {
    65  		_, err := certclient.CertmanagerV1alpha1().Issuers(ns).Get(CertManagerIssuerProd, metav1.GetOptions{})
    66  		if err != nil {
    67  			_, err := certclient.CertmanagerV1alpha1().Issuers(ns).Create(
    68  				issuer(CertManagerIssuerProd, certManagerIssuerProdServer, ic.Email))
    69  			if err != nil {
    70  				return errors.Wrapf(err, "creating cert-manager issuer %q", CertManagerIssuerProd)
    71  			}
    72  		}
    73  	} else {
    74  		_, err := certclient.CertmanagerV1alpha1().Issuers(ns).Get(CertManagerIssuerStaging, metav1.GetOptions{})
    75  		if err != nil {
    76  			_, err := certclient.CertmanagerV1alpha1().Issuers(ns).Create(
    77  				issuer(CertManagerIssuerStaging, certManagerIssuerStagingServer, ic.Email))
    78  			if err != nil {
    79  				return errors.Wrapf(err, "creating cert-manager issuer %q", CertManagerIssuerStaging)
    80  			}
    81  		}
    82  	}
    83  
    84  	return nil
    85  }
    86  
    87  func issuer(name string, server string, email string) *certmng.Issuer {
    88  	return &certmng.Issuer{
    89  		ObjectMeta: metav1.ObjectMeta{
    90  			Name: name,
    91  		},
    92  		Spec: certmng.IssuerSpec{
    93  			IssuerConfig: certmng.IssuerConfig{
    94  				ACME: &certmng.ACMEIssuer{
    95  					Email:         email,
    96  					Server:        server,
    97  					SkipTLSVerify: false,
    98  					PrivateKey: certmng.SecretKeySelector{
    99  						LocalObjectReference: certmng.LocalObjectReference{
   100  							Name: name,
   101  						},
   102  					},
   103  					HTTP01: &certmng.ACMEIssuerHTTP01Config{},
   104  				},
   105  			},
   106  		},
   107  		Status: certmng.IssuerStatus{
   108  			Conditions: []certmng.IssuerCondition{},
   109  		},
   110  	}
   111  }
   112  
   113  // CreateCertManagerResources creates the cert-manager resources such as issuer in the target namespace
   114  func CreateCertManagerResources(certclient certclient.Interface, targetNamespace string, ic kube.IngressConfig) error {
   115  	if !ic.TLS {
   116  		return nil
   117  	}
   118  
   119  	// do not recreate the issuer if it is already there and correctly configured
   120  	if alreadyConfigured(certclient, targetNamespace, ic) {
   121  		return nil
   122  	}
   123  
   124  	err := CleanCertManagerResources(certclient, targetNamespace, ic)
   125  	if err != nil {
   126  		return errors.Wrapf(err, "cleaning the cert-manager resources from namespace %q", targetNamespace)
   127  	}
   128  
   129  	err = CreateIssuer(certclient, targetNamespace, ic)
   130  	if err != nil {
   131  		return errors.Wrapf(err, "creating the cert-manager issuer %s/%s", targetNamespace, ic.Issuer)
   132  	}
   133  
   134  	return nil
   135  }
   136  
   137  // alreadyConfigured checks if cert-manager resources are already configured and match with the ingress configuration
   138  func alreadyConfigured(certClient certclient.Interface, targetNamespace string, ingressConfig kube.IngressConfig) bool {
   139  	issuer, err := certClient.CertmanagerV1alpha1().Issuers(targetNamespace).Get(ingressConfig.Issuer, metav1.GetOptions{})
   140  	if err != nil {
   141  		log.Logger().Infof("Certificate issuer %s does not exist. Creating...", util.ColorInfo(ingressConfig.Issuer))
   142  		return false
   143  	}
   144  	// ingress and issuer email must match
   145  	if issuer.Spec.ACME.Email != ingressConfig.Email {
   146  		issuer.Spec.ACME.Email = ingressConfig.Email
   147  		_, err := certClient.CertmanagerV1alpha1().Issuers(targetNamespace).Update(issuer)
   148  		if err != nil {
   149  			// can not update the issuer, let's assume it needs recreation
   150  			log.Logger().Infof("Certificate issuer %s can not be updated. Recreating...", util.ColorInfo(ingressConfig.Issuer))
   151  			return false
   152  		}
   153  	}
   154  	log.Logger().Infof("Certificate issuer %s already configured.", util.ColorInfo(ingressConfig.Issuer))
   155  	return true
   156  }