Skip to content

Commit

Permalink
considering external issuers
Browse files Browse the repository at this point in the history
  • Loading branch information
gvicentin committed Aug 2, 2024
1 parent 5881160 commit f725d85
Show file tree
Hide file tree
Showing 3 changed files with 89 additions and 23 deletions.
2 changes: 1 addition & 1 deletion api/api.go
Original file line number Diff line number Diff line change
Expand Up @@ -343,7 +343,7 @@ func (a *RouterAPI) issueCertManagerCert(_ http.ResponseWriter, r *http.Request)
}
}

return cmRouter.IssueCertManagerCertificate(ctx, instanceID(r), certName, cert)
return cmRouter.IssueCertManagerCertificate(ctx, instanceID(r), certName, cert.Issuer)
}

// removeCertManagerCert Removes certificate for the app
Expand Down
104 changes: 85 additions & 19 deletions kubernetes/ingress.go
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,6 @@ import (
"strconv"
"strings"

cmv1 "github.com/cert-manager/cert-manager/pkg/apis/certmanager/v1"
"github.com/opentracing/opentracing-go"
"github.com/pkg/errors"
"github.com/tsuru/kubernetes-router/router"
Expand All @@ -36,6 +35,8 @@ var (

CertManagerIssuerKey = "cert-manager.io/issuer"
CertManagerClusterIssuerKey = "cert-manager.io/cluster-issuer"
CertManagerIssuerKindKey = "cert-manager.io/issuer-kind"
CertManagerIssuerGroupKey = "cert-manager.io/issuer-group"

defaultClassOpt = "class"
defaultOptsAsAnnotations = map[string]string{
Expand All @@ -48,6 +49,8 @@ var (
unwantedAnnotationsForCNames = []string{
CertManagerIssuerKey,
CertManagerClusterIssuerKey,
CertManagerIssuerKindKey,
CertManagerIssuerGroupKey,
}
)

Expand All @@ -72,6 +75,29 @@ type IngressService struct {
OptsAsAnnotationsDocs map[string]string
}

/* Cert-manager types */

const (
errIssuerNotFound = "issuer %s not found"
errExternalIssuerNotFound = "external issuer %s not found"
errExternalIssuerInvalid = "invalid external issuer: %s (requires <resource name>.<resource kind>.<resource group>)"
)

type CertManagerIssuerType int

const (
CertManagerIssuerTypeIssuer = iota
CertManagerIssuerTypeClusterIssuer
CertManagerIssuerTypeExternalIssuer
)

type CertManagerIssuerData struct {
Name string
Kind string
Group string
Type CertManagerIssuerType
}

// Ensure creates or updates an Ingress resource to point it to either
// the only service or the one responsible for the process web
func (k *IngressService) Ensure(ctx context.Context, id router.InstanceID, o router.EnsureBackendOpts) error {
Expand Down Expand Up @@ -514,8 +540,8 @@ func isCnamePresent(cname string, ingress *networkingV1.Ingress) error {
if !foundCname {
return fmt.Errorf(
"cname %s is not found in ingress %s, found cnames: %s",
cname,
ingress.Name,
cname,
ingress.Name,
strings.Join(foundCNames, ", "),
)
}
Expand Down Expand Up @@ -702,30 +728,60 @@ func (s *IngressService) SupportedOptions(ctx context.Context) map[string]string
return opts
}

func (s *IngressService) validateIssuer(ctx context.Context, issuerName, namespace string) error {
cmV1, err := s.getCertManagerClient()
func (s *IngressService) getCertManagerIssuerData(ctx context.Context, issuerName, namespace string) (CertManagerIssuerData, error) {
if strings.Contains(issuerName, ".") {
// Treat as external issuer since it's more general
parts := strings.Split(issuerName, ".")
if len(parts) != 3 {
return CertManagerIssuerData{}, fmt.Errorf(errExternalIssuerInvalid, issuerName)
}

// TODO: Check if the external issuer exists

return CertManagerIssuerData{
Name: parts[0],
Kind: parts[1],
Group: parts[2],
Type: CertManagerIssuerTypeExternalIssuer,
}, nil
}

// Treat as CertManager issuer
cmClient, err := s.getCertManagerClient()
if err != nil {
return err
return CertManagerIssuerData{}, err
}

_, err = cmV1.CertmanagerV1().Issuers(namespace).Get(ctx, issuerName, metav1.GetOptions{})
_, err = cmClient.CertmanagerV1().Issuers(namespace).Get(ctx, issuerName, metav1.GetOptions{})
if err != nil && !k8sErrors.IsNotFound(err) {
return err
return CertManagerIssuerData{}, err
}

if err == nil {
return nil
return CertManagerIssuerData{
Name: issuerName,
Type: CertManagerIssuerTypeIssuer,
}, nil
}

_, err = cmV1.CertmanagerV1().ClusterIssuers().Get(ctx, issuerName, metav1.GetOptions{})
// Check if it's a cluster issuer
_, err = cmClient.CertmanagerV1().ClusterIssuers().Get(ctx, issuerName, metav1.GetOptions{})
if err != nil && !k8sErrors.IsNotFound(err) {
return err
return CertManagerIssuerData{}, err
}

return fmt.Errorf("issuer %s not found", issuerName)
if err == nil {
return CertManagerIssuerData{
Name: issuerName,
Type: CertManagerIssuerTypeClusterIssuer,
}, nil
}

// Issuer not found
return CertManagerIssuerData{}, fmt.Errorf(errIssuerNotFound, issuerName)
}

func (k *IngressService) IssueCertManagerCertificate(ctx context.Context, id router.InstanceID, certCname string, issuer router.CertManagerIssuerData) error {
func (k *IngressService) IssueCertManagerCertificate(ctx context.Context, id router.InstanceID, certCname string, issuerName string) error {
ns, err := k.getAppNamespace(ctx, id.AppName)
if err != nil {
return err
Expand All @@ -747,17 +803,25 @@ func (k *IngressService) IssueCertManagerCertificate(ctx context.Context, id rou
return err
}

issuerName := issuer.Issuer
err = k.validateIssuer(ctx, issuerName, ns)
// Parse issuer data
issuerData, err := k.getCertManagerIssuerData(ctx, issuerName, ns)
if err != nil {
return err
}

// Add cert-manager annotation to the ingress
if len(issuer.Issuer) > 0 {
ingress.ObjectMeta.Annotations[CertManagerIssuerKey] = issuer.Issuer
} else if len(issuer.ClusterIssuer) > 0 {
ingress.ObjectMeta.Annotations[CertManagerClusterIssuerKey] = issuer.ClusterIssuer
switch issuerData.Type {

case CertManagerIssuerTypeIssuer:
ingress.ObjectMeta.Annotations[CertManagerIssuerKey] = issuerData.Name

case CertManagerIssuerTypeClusterIssuer:
ingress.ObjectMeta.Annotations[CertManagerClusterIssuerKey] = issuerData.Name

case CertManagerIssuerTypeExternalIssuer:
ingress.ObjectMeta.Annotations[CertManagerIssuerKey] = issuerData.Name
ingress.ObjectMeta.Annotations[CertManagerIssuerKindKey] = issuerData.Kind
ingress.ObjectMeta.Annotations[CertManagerIssuerGroupKey] = issuerData.Group
}

// Find TLS spec for the certName
Expand Down Expand Up @@ -804,6 +868,8 @@ func (k *IngressService) RemoveCertManagerCertificate(ctx context.Context, id ro
// Remove cert-manager annotation from the ingress
delete(ingress.ObjectMeta.Annotations, CertManagerIssuerKey)
delete(ingress.ObjectMeta.Annotations, CertManagerClusterIssuerKey)
delete(ingress.ObjectMeta.Annotations, CertManagerIssuerKindKey)
delete(ingress.ObjectMeta.Annotations, CertManagerIssuerGroupKey)

// Remove TLS spec from the ingress
for k := range ingress.Spec.TLS {
Expand Down
6 changes: 3 additions & 3 deletions router/service.go
Original file line number Diff line number Diff line change
Expand Up @@ -84,7 +84,7 @@ type RouterTLS interface {

type RouterCertManager interface {
RouterTLS
IssueCertManagerCertificate(ctx context.Context, id InstanceID, certName string, issuer CertManagerIssuerData) error
IssueCertManagerCertificate(ctx context.Context, id InstanceID, certName string, issuerName string) error
RemoveCertManagerCertificate(ctx context.Context, id InstanceID, certName string) error
}

Expand All @@ -110,9 +110,9 @@ type CertData struct {
Key string `json:"key"`
}

// Issuer data for CertManager
type CertManagerIssuerData struct {
Issuer string `json:"issuer"`
ClusterIssuer string `json:"clusterIssuer"`
Issuer string `json:"issuer"`
}

type BackendPrefix struct {
Expand Down

0 comments on commit f725d85

Please sign in to comment.