pkg/controller/keyvault/ingress_tls.go (93 lines of code) (raw):
package keyvault
import (
"context"
"errors"
"fmt"
"reflect"
"strings"
"github.com/Azure/aks-app-routing-operator/pkg/config"
"github.com/Azure/aks-app-routing-operator/pkg/controller/controllername"
"github.com/Azure/aks-app-routing-operator/pkg/controller/metrics"
"github.com/Azure/aks-app-routing-operator/pkg/util"
"github.com/go-logr/logr"
corev1 "k8s.io/api/core/v1"
netv1 "k8s.io/api/networking/v1"
"k8s.io/client-go/tools/record"
ctrl "sigs.k8s.io/controller-runtime"
"sigs.k8s.io/controller-runtime/pkg/client"
)
var ingressTlsControllerName = controllername.New("keyvault", "ingress", "tls")
// ingressTlsReconciler manages the TLS spec of an Ingress object using the Key Vault integration. Ingresses with
// the App Routing Key Vault annotation will have their TLS spec populated with the Key Vault secret name.
type ingressTlsReconciler struct {
client client.Client
events record.EventRecorder
ingressManager IngressManager
}
func NewIngressTlsReconciler(manager ctrl.Manager, conf *config.Config, ingressManager IngressManager) error {
metrics.InitControllerMetrics(ingressTlsControllerName)
if conf.DisableKeyvault {
return nil
}
return ingressTlsControllerName.AddToController(
ctrl.
NewControllerManagedBy(manager).
For(&netv1.Ingress{}), manager.GetLogger(),
).Complete(&ingressTlsReconciler{
client: manager.GetClient(),
events: manager.GetEventRecorderFor("aks-app-routing-operator"),
ingressManager: ingressManager,
})
}
func (i *ingressTlsReconciler) Reconcile(ctx context.Context, req ctrl.Request) (res ctrl.Result, err error) {
defer func() {
metrics.HandleControllerReconcileMetrics(ingressTlsControllerName, res, err)
}()
logger, err := logr.FromContext(ctx)
if err != nil {
return ctrl.Result{}, errors.New("getting logger from context")
}
logger = ingressTlsControllerName.AddToLogger(logger).WithValues("name", req.Name, "namespace", req.Namespace)
logger.Info("getting Ingress")
ing := &netv1.Ingress{}
if err = i.client.Get(ctx, req.NamespacedName, ing); err != nil {
return ctrl.Result{}, client.IgnoreNotFound(err)
}
managed, err := i.ingressManager.IsManaging(ing)
if err != nil {
logger.Error(err, "error checking if ingress is managed")
return ctrl.Result{}, fmt.Errorf("checking if ingress is managed: %w", err)
}
if !managed {
logger.Info("ingress is not managed by app routing")
return ctrl.Result{}, nil
}
if val, ok := ing.Annotations[tlsCertManagedAnnotation]; !ok || strings.ToLower(val) != "true" {
logger.Info("ingress does not have managed annotation")
return ctrl.Result{}, nil
}
if _, ok := ing.Annotations[tlsCertKvUriAnnotation]; !ok {
logger.Info("ingress does not have keyvault annotation")
i.events.Eventf(ing, corev1.EventTypeWarning, "KeyvaultUriAnnotationMissing", "Ingress has %[1]s annotation but is missing %[2]s annotation. %[2]s annotation is needed to manage Ingress TLS.", tlsCertManagedAnnotation, tlsCertKvUriAnnotation)
return ctrl.Result{}, nil
}
oldTls := ing.Spec.TLS
logger.Info("adding TLS spec to ingress")
ing.Spec.TLS = []netv1.IngressTLS{
{
SecretName: certSecretName(ing.Name),
Hosts: []string{},
},
}
for _, rule := range ing.Spec.Rules {
if host := rule.Host; host != "" {
ing.Spec.TLS[0].Hosts = append(ing.Spec.TLS[0].Hosts, host)
}
}
if !reflect.DeepEqual(oldTls, ing.Spec.TLS) {
logger.Info("overwriting TLS spec on ingress", "old", fmt.Sprintf("%s", oldTls), "new", fmt.Sprintf("%s", ing.Spec.TLS))
}
if err := util.Upsert(ctx, i.client, ing); err != nil {
logger.Error(err, "error updating ingress")
return ctrl.Result{}, fmt.Errorf("updating ingress: %w", err)
}
return ctrl.Result{}, nil
}