diff --git a/pkg/network/network.go b/pkg/network/network.go index f696362a15d0..0a81ac8d9ed8 100644 --- a/pkg/network/network.go +++ b/pkg/network/network.go @@ -109,6 +109,10 @@ var ( // that specifies enabling auto-TLS or not. AutoTLSKey = "autoTLS" + // CheckExistingCertsKey is the name of the configuration entry + // that specifies creation of TLS entries in gateway with existing secrets. + CheckExistingCertsKey = "checkExistingCerts" + // HTTPProtocolKey is the name of the configuration entry that // specifies the HTTP endpoint behavior of Knative ingress. HTTPProtocolKey = "httpProtocol" @@ -153,6 +157,8 @@ type Config struct { // AutoTLS specifies if auto-TLS is enabled or not. AutoTLS bool + CheckExistingCerts bool + // HTTPProtocol specifics the behavior of HTTP endpoint of Knative // ingress. HTTPProtocol HTTPProtocol @@ -248,6 +254,8 @@ func NewConfigFromConfigMap(configMap *corev1.ConfigMap) (*Config, error) { nc.AutoTLS = strings.ToLower(configMap.Data[AutoTLSKey]) == "enabled" + nc.CheckExistingCerts = strings.ToLower(configMap.Data[CheckExistingCertsKey]) == "enabled" + switch strings.ToLower(configMap.Data[HTTPProtocolKey]) { case string(HTTPEnabled): nc.HTTPProtocol = HTTPEnabled diff --git a/pkg/reconciler/clusteringress/clusteringress.go b/pkg/reconciler/clusteringress/clusteringress.go index 7d647a738052..9c938dae3ab8 100644 --- a/pkg/reconciler/clusteringress/clusteringress.go +++ b/pkg/reconciler/clusteringress/clusteringress.go @@ -177,6 +177,36 @@ func (c *Reconciler) reconcile(ctx context.Context, ci *v1alpha1.ClusterIngress) ci.Status.MarkLoadBalancerReady(getLBStatus(gatewayServiceURLFromContext(ctx, ci))) ci.Status.ObservedGeneration = ci.Generation + if checkExistingCerts(ctx) { + + // Add the finalizer before adding `Servers` into Gateway so that we can be sure + // the `Servers` get cleaned up from Gateway. + if err := c.ensureFinalizer(ci); err != nil { + return err + } + + // This works under the assumption the secrets/certs exist under istio-system namespace + secrets, err := resources.GetClusterIngressHostSecrets(ci, c.secretLister, "istio-system") + if err != nil { + return err + } + + for _, gatewayName := range gatewayNames { + ns, err := resources.GatewayServiceNamespace(config.FromContext(ctx).Istio.IngressGateways, gatewayName) + if err != nil { + return err + } + desired, err := resources.MakeServersFromExistingCerts(ci, ns, secrets) + if err != nil { + return err + } + if err := c.reconcileGateway(ctx, ci, gatewayName, desired); err != nil { + return err + } + } + + } + if enablesAutoTLS(ctx) { if !ci.IsPublic() { logger.Infof("ClusterIngress %s is not public. So no need to configure TLS.", ci.Name) @@ -222,6 +252,10 @@ func enablesAutoTLS(ctx context.Context) bool { return config.FromContext(ctx).Network.AutoTLS } +func checkExistingCerts(ctx context.Context) bool { + return config.FromContext(ctx).Network.CheckExistingCerts +} + func getLBStatus(gatewayServiceURL string) []v1alpha1.LoadBalancerIngressStatus { // The ClusterIngress isn't load-balanced by any particular // Service, but through a Service mesh. diff --git a/pkg/reconciler/clusteringress/resources/gateway.go b/pkg/reconciler/clusteringress/resources/gateway.go index 03979deb51f2..18f84762692e 100644 --- a/pkg/reconciler/clusteringress/resources/gateway.go +++ b/pkg/reconciler/clusteringress/resources/gateway.go @@ -118,6 +118,30 @@ func MakeServers(ci *v1alpha1.ClusterIngress, gatewayServiceNamespace string, or return SortServers(servers), nil } +// MakeServersFromExistingCerts creates the expected Gateway Servers that are referenced by the ClusterIngree. +// This method builds these Servers with manually added secrets instead of AutoTLS created ones. +func MakeServersFromExistingCerts(ci *v1alpha1.ClusterIngress, gatewayServiceNamespace string, originSecrets map[string]*corev1.Secret) ([]v1alpha3.Server, error) { + servers := []v1alpha3.Server{} + for i, rules := range ci.Spec.Rules { + // Replace first part of fqdn with wildcard to be used as the Hosts field. + credName = rules.Hosts[0] + hostname := []string{"*" + credName[strings.Index(credName, "."):len(credName)]} + servers = append(servers, v1alpha3.Server{ + Hosts: hostname, + Port: v1alpha3.Port{ + Name: fmt.Sprintf("%s:%d", ci.Name, i), + Number: 443, + Protocol: v1alpha3.ProtocolHTTPS, + }, + TLS: &v1alpha3.TLSOptions{ + Mode: v1alpha3.TLSModeMutual, + CredentialName: credName, + }, + }) + } + return SortServers(servers), nil +} + // MakeHTTPServer creates a HTTP Gateway `Server` based on the HTTPProtocol // configureation. func MakeHTTPServer(httpProtocol network.HTTPProtocol) *v1alpha3.Server { diff --git a/pkg/reconciler/clusteringress/resources/secret.go b/pkg/reconciler/clusteringress/resources/secret.go index 174866089e98..92bbc3bc69eb 100644 --- a/pkg/reconciler/clusteringress/resources/secret.go +++ b/pkg/reconciler/clusteringress/resources/secret.go @@ -46,6 +46,22 @@ func GetSecrets(ci *v1alpha1.ClusterIngress, secretLister corev1listers.SecretLi return secrets, nil } +// GetClusterIngressHostSecrets gets the secrets whose name matches the host listed in the given ClusterIngress. +func GetClusterIngressHostSecrets(ci *v1alpha1.ClusterIngress, secretLister corev1listers.SecretLister, ns string) (map[string]*corev1.Secret, error) { + + secrets := map[string]*corev1.Secret{} + var host = ci.Spec.Rules[0].Hosts[0] + secret, err := secretLister.Secrets(ns).Get(host) + if err != nil { + return nil, err + } + + ref := fmt.Sprintf("%s/%s", ns, host) + secrets[ref] = secret + + return secrets, nil +} + // MakeSecrets makes copies of the origin Secrets under the namespace of Istio gateway service. func MakeSecrets(ctx context.Context, originSecrets map[string]*corev1.Secret, ci *v1alpha1.ClusterIngress) []*corev1.Secret { gatewaySvcNamespaces := getAllGatewaySvcNamespaces(ctx)