Skip to content

Commit

Permalink
Host cluster-local-domain TLS on local listener with SNI
Browse files Browse the repository at this point in the history
  • Loading branch information
ReToCode committed Dec 19, 2023
1 parent 4af3076 commit a9c85e4
Show file tree
Hide file tree
Showing 7 changed files with 82 additions and 47 deletions.
3 changes: 3 additions & 0 deletions config/203-local-gateway.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -55,3 +55,6 @@ spec:
- name: http2
port: 80
targetPort: 8081
- name: https
port: 443
targetPort: 8443
73 changes: 50 additions & 23 deletions pkg/reconciler/ingress/ingress.go
Original file line number Diff line number Diff line change
Expand Up @@ -57,10 +57,9 @@ import (
)

const (
virtualServiceConditionReconciled = "Reconciled"
virtualServiceNotReconciled = "ReconcileVirtualServiceFailed"
notReconciledReason = "ReconcileIngressFailed"
notReconciledMessage = "Ingress reconciliation failed"
virtualServiceNotReconciled = "ReconcileVirtualServiceFailed"
notReconciledReason = "ReconcileIngressFailed"
notReconciledMessage = "Ingress reconciliation failed"
)

// Reconciler implements the control loop for the Ingress resources.
Expand Down Expand Up @@ -106,8 +105,8 @@ func (r *Reconciler) reconcileIngress(ctx context.Context, ing *v1alpha1.Ingress
logger := logging.FromContext(ctx)

// We may be reading a version of the object that was stored at an older version
// and may not have had all of the assumed defaults specified. This won't result
// in this getting written back to the API Server, but lets downstream logic make
// and may not have had all the assumed defaults specified. This won't result
// in this getting written back to the API Server, but let's downstream logic make
// assumptions about defaulting.
ing.SetDefaults(ctx)

Expand All @@ -118,9 +117,9 @@ func (r *Reconciler) reconcileIngress(ctx context.Context, ing *v1alpha1.Ingress
gatewayNames[v1alpha1.IngressVisibilityClusterLocal] = qualifiedGatewayNamesFromContext(ctx)[v1alpha1.IngressVisibilityClusterLocal]
gatewayNames[v1alpha1.IngressVisibilityExternalIP] = sets.New[string]()

ingressGateways := []*v1beta1.Gateway{}
if shouldReconcileTLS(ing) {
originSecrets, err := resources.GetSecrets(ing, r.secretLister)
externalIngressGateways := []*v1beta1.Gateway{}
if shouldReconcileExternalDomainTLS(ing) {
originSecrets, err := resources.GetSecrets(ing, v1alpha1.IngressVisibilityExternalIP, r.secretLister)
if err != nil {
return err
}
Expand All @@ -144,7 +143,8 @@ func (r *Reconciler) reconcileIngress(ctx context.Context, ing *v1alpha1.Ingress
}

nonWildcardIngressTLS := resources.GetNonWildcardIngressTLS(ing.GetIngressTLSForVisibility(v1alpha1.IngressVisibilityExternalIP), nonWildcardSecrets)
ingressGateways, err = resources.MakeIngressTLSGateways(ctx, ing, nonWildcardIngressTLS, nonWildcardSecrets, r.svcLister)
externalIngressGateways, err = resources.MakeIngressTLSGateways(ctx, ing, v1alpha1.IngressVisibilityExternalIP,
nonWildcardIngressTLS, nonWildcardSecrets, r.svcLister)
if err != nil {
return err
}
Expand All @@ -164,17 +164,35 @@ func (r *Reconciler) reconcileIngress(ctx context.Context, ing *v1alpha1.Ingress
gatewayNames[v1alpha1.IngressVisibilityExternalIP].Insert(resources.GetQualifiedGatewayNames(desiredWildcardGateways)...)
}

cfg := config.FromContext(ctx)
clusterLocalIngressGateways := []*v1beta1.Gateway{}
if cfg.Network.ClusterLocalDomainTLS == netconfig.EncryptionEnabled && shouldReconcileClusterLocalDomainTLS(ing) {
originSecrets, err := resources.GetSecrets(ing, v1alpha1.IngressVisibilityClusterLocal, r.secretLister)
if err != nil {
return err
}
targetSecrets, err := resources.MakeSecrets(ctx, originSecrets, ing)

Check failure on line 174 in pkg/reconciler/ingress/ingress.go

View workflow job for this annotation

GitHub Actions / style / Golang / Lint

ineffectual assignment to err (ineffassign)
if err := r.reconcileCertSecrets(ctx, ing, targetSecrets); err != nil {
return err
}
clusterLocalIngressGateways, err = resources.MakeIngressTLSGateways(ctx, ing, v1alpha1.IngressVisibilityClusterLocal,
ing.GetIngressTLSForVisibility(v1alpha1.IngressVisibilityClusterLocal), originSecrets, r.svcLister)
if err != nil {
return err
}
}

if shouldReconcileHTTPServer(ing) {
httpServer := resources.MakeHTTPServer(ing.Spec.HTTPOption, getPublicHosts(ing))
if len(ingressGateways) == 0 {
if len(externalIngressGateways) == 0 {
var err error
if ingressGateways, err = resources.MakeIngressGateways(ctx, ing, []*istiov1beta1.Server{httpServer}, r.svcLister); err != nil {
if externalIngressGateways, err = resources.MakeExternalIngressGateways(ctx, ing, []*istiov1beta1.Server{httpServer}, r.svcLister); err != nil {
return err
}
} else {
// add HTTP Server into ingressGateways.
for i := range ingressGateways {
ingressGateways[i].Spec.Servers = append(ingressGateways[i].Spec.Servers, httpServer)
for i := range externalIngressGateways {
externalIngressGateways[i].Spec.Servers = append(externalIngressGateways[i].Spec.Servers, httpServer)
}
}
} else {
Expand All @@ -184,10 +202,15 @@ func (r *Reconciler) reconcileIngress(ctx context.Context, ing *v1alpha1.Ingress
gatewayNames[v1alpha1.IngressVisibilityExternalIP].Insert(sets.List(defaultGlobalHTTPGateways)...)
}

if err := r.reconcileIngressGateways(ctx, ingressGateways); err != nil {
if err := r.reconcileIngressGateways(ctx, externalIngressGateways); err != nil {
return err
}
gatewayNames[v1alpha1.IngressVisibilityExternalIP].Insert(resources.GetQualifiedGatewayNames(externalIngressGateways)...)

if err := r.reconcileIngressGateways(ctx, clusterLocalIngressGateways); err != nil {
return err
}
gatewayNames[v1alpha1.IngressVisibilityExternalIP].Insert(resources.GetQualifiedGatewayNames(ingressGateways)...)
gatewayNames[v1alpha1.IngressVisibilityClusterLocal].Insert(resources.GetQualifiedGatewayNames(clusterLocalIngressGateways)...)

if config.FromContext(ctx).Network.SystemInternalTLSEnabled() {
logger.Info("reconciling DestinationRules for system-internal-tls")
Expand Down Expand Up @@ -410,16 +433,16 @@ func (r *Reconciler) FinalizeKind(ctx context.Context, ing *v1alpha1.Ingress) pk
}
}

return r.reconcileDeletion(ctx, ing)
return r.cleanupCertificateSecrets(ctx, ing)
}

func (r *Reconciler) reconcileDeletion(ctx context.Context, ing *v1alpha1.Ingress) error {
if !shouldReconcileTLS(ing) {
func (r *Reconciler) cleanupCertificateSecrets(ctx context.Context, ing *v1alpha1.Ingress) error {
if !shouldReconcileExternalDomainTLS(ing) && !shouldReconcileClusterLocalDomainTLS(ing) {
return nil
}

errs := []error{}
for _, tls := range ing.GetIngressTLSForVisibility(v1alpha1.IngressVisibilityExternalIP) {
for _, tls := range ing.Spec.TLS {
nameNamespaces, err := resources.GetIngressGatewaySvcNameNamespaces(ctx)
if err != nil {
errs = append(errs, err)
Expand Down Expand Up @@ -541,13 +564,17 @@ func getLBStatus(gatewayServiceURL string) []v1alpha1.LoadBalancerIngressStatus
}
}

func shouldReconcileTLS(ing *v1alpha1.Ingress) bool {
func shouldReconcileExternalDomainTLS(ing *v1alpha1.Ingress) bool {
return isIngressPublic(ing) && len(ing.GetIngressTLSForVisibility(v1alpha1.IngressVisibilityExternalIP)) > 0
}

func shouldReconcileClusterLocalDomainTLS(ing *v1alpha1.Ingress) bool {
return len(ing.GetIngressTLSForVisibility(v1alpha1.IngressVisibilityClusterLocal)) > 0
}

func shouldReconcileHTTPServer(ing *v1alpha1.Ingress) bool {
// We will create a Ingress specific HTTPServer when
// 1. auto TLS is enabled as in this case users want us to fully handle the TLS/HTTP behavior,
// We will create an Ingress specific HTTPServer when
// 1. external-domain-tls is enabled as in this case users want us to fully handle the TLS/HTTP behavior,
// 2. HTTPOption is set to Redirected as we don't have default HTTP server supporting HTTP redirection.
return isIngressPublic(ing) && (ing.Spec.HTTPOption == v1alpha1.HTTPOptionRedirected || len(ing.GetIngressTLSForVisibility(v1alpha1.IngressVisibilityExternalIP)) > 0)
}
Expand Down
4 changes: 2 additions & 2 deletions pkg/reconciler/ingress/ingress_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -188,7 +188,7 @@ var (
gateways = map[v1alpha1.IngressVisibility]sets.Set[string]{
v1alpha1.IngressVisibilityExternalIP: sets.New[string]("knative-test-gateway", config.KnativeIngressGateway),
}
perIngressGatewayName = resources.GatewayName(ingressWithTLS("reconciling-ingress", ingressTLS), ingressService)
perIngressGatewayName = resources.GatewayName(ingressWithTLS("reconciling-ingress", ingressTLS), v1alpha1.IngressVisibilityExternalIP, ingressService)
)

var (
Expand Down Expand Up @@ -1161,7 +1161,7 @@ func TestReconcile_ExternalDomainTLS(t *testing.T) {
Key: "test-ns/reconciling-ingress",
CmpOpts: defaultCmpOptsList,
}, {
Name: "Reconcile with autoTLS but cluster local visibilty, mesh only",
Name: "Reconcile with external-domain-tls but cluster local visibility, mesh only",
SkipNamespaceValidation: true,
Objects: []runtime.Object{
ingressWithTLSClusterLocal("reconciling-ingress", ingressTLS),
Expand Down
29 changes: 17 additions & 12 deletions pkg/reconciler/ingress/resources/gateway.go
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,7 @@ const (
GatewayHTTPPort = 80
dns1123LabelMaxLength = 63 // Public for testing only.
dns1123LabelFmt = "[a-zA-Z0-9](?:[-a-zA-Z0-9]*[a-zA-Z0-9])?"
localGatewayPostfix = "-local"
)

var httpServerPortName = "http-server"
Expand Down Expand Up @@ -105,7 +106,8 @@ func SortServers(servers []*istiov1beta1.Server) []*istiov1beta1.Server {
}

// MakeIngressTLSGateways creates Gateways that have only TLS servers for a given Ingress.
func MakeIngressTLSGateways(ctx context.Context, ing *v1alpha1.Ingress, ingressTLS []v1alpha1.IngressTLS, originSecrets map[string]*corev1.Secret, svcLister corev1listers.ServiceLister) ([]*v1beta1.Gateway, error) {
func MakeIngressTLSGateways(ctx context.Context, ing *v1alpha1.Ingress, visibility v1alpha1.IngressVisibility,
ingressTLS []v1alpha1.IngressTLS, originSecrets map[string]*corev1.Secret, svcLister corev1listers.ServiceLister) ([]*v1beta1.Gateway, error) {
// No need to create Gateway if there is no related ingress TLS.
if len(ingressTLS) == 0 {
return []*v1beta1.Gateway{}, nil
Expand All @@ -116,17 +118,17 @@ func MakeIngressTLSGateways(ctx context.Context, ing *v1alpha1.Ingress, ingressT
}
gateways := make([]*v1beta1.Gateway, len(gatewayServices))
for i, gatewayService := range gatewayServices {
servers, err := MakeTLSServers(ing, ing.GetIngressTLSForVisibility(v1alpha1.IngressVisibilityExternalIP), gatewayService.Namespace, originSecrets)
servers, err := MakeTLSServers(ing, ingressTLS, gatewayService.Namespace, originSecrets)
if err != nil {
return nil, err
}
gateways[i] = makeIngressGateway(ing, gatewayService.Spec.Selector, servers, gatewayService)
gateways[i] = makeIngressGateway(ing, visibility, gatewayService.Spec.Selector, servers, gatewayService)
}
return gateways, nil
}

// MakeIngressGateways creates Gateways with given Servers for a given Ingress.
func MakeIngressGateways(ctx context.Context, ing *v1alpha1.Ingress, servers []*istiov1beta1.Server, svcLister corev1listers.ServiceLister) ([]*v1beta1.Gateway, error) {
// MakeExternalIngressGateways creates Gateways with given Servers for a given Ingress.
func MakeExternalIngressGateways(ctx context.Context, ing *v1alpha1.Ingress, servers []*istiov1beta1.Server, svcLister corev1listers.ServiceLister) ([]*v1beta1.Gateway, error) {
gatewayServices, err := getGatewayServices(ctx, svcLister)
if err != nil {
return nil, err
Expand All @@ -136,7 +138,7 @@ func MakeIngressGateways(ctx context.Context, ing *v1alpha1.Ingress, servers []*
if err != nil {
return nil, err
}
gateways[i] = makeIngressGateway(ing, gatewayService.Spec.Selector, servers, gatewayService)
gateways[i] = makeIngressGateway(ing, v1alpha1.IngressVisibilityExternalIP, gatewayService.Spec.Selector, servers, gatewayService)
}
return gateways, nil
}
Expand Down Expand Up @@ -244,14 +246,14 @@ func GatewayRef(gw *v1beta1.Gateway) tracker.Reference {
}
}

func makeIngressGateway(ing *v1alpha1.Ingress, selector map[string]string, servers []*istiov1beta1.Server, gatewayService *corev1.Service) *v1beta1.Gateway {
func makeIngressGateway(ing *v1alpha1.Ingress, visibility v1alpha1.IngressVisibility, selector map[string]string, servers []*istiov1beta1.Server, gatewayService *corev1.Service) *v1beta1.Gateway {
return &v1beta1.Gateway{
ObjectMeta: metav1.ObjectMeta{
Name: GatewayName(ing, gatewayService),
Name: GatewayName(ing, visibility, gatewayService),
Namespace: ing.GetNamespace(),
OwnerReferences: []metav1.OwnerReference{*kmeta.NewControllerRef(ing)},
Labels: map[string]string{
// We need this label to find out all of Gateways of a given Ingress.
// We need this label to find out all Gateways of a given Ingress.
networking.IngressLabelKey: ing.GetName(),
},
},
Expand Down Expand Up @@ -280,13 +282,16 @@ func getGatewayServices(ctx context.Context, svcLister corev1listers.ServiceList

// GatewayName create a name for the Gateway that is built based on the given Ingress and bonds to the
// given ingress gateway service.
func GatewayName(accessor kmeta.Accessor, gatewaySvc *corev1.Service) string {
func GatewayName(accessor kmeta.Accessor, visibility v1alpha1.IngressVisibility, gatewaySvc *corev1.Service) string {
prefix := accessor.GetName()
if !isDNS1123Label(prefix) {
prefix = fmt.Sprint(adler32.Checksum([]byte(prefix)))
}

gatewayServiceKey := fmt.Sprintf("%s/%s", gatewaySvc.Namespace, gatewaySvc.Name)
if visibility == v1alpha1.IngressVisibilityClusterLocal {
gatewayServiceKey += localGatewayPostfix
}
gatewayServiceKeyChecksum := fmt.Sprint(adler32.Checksum([]byte(gatewayServiceKey)))

// Ensure that the overall gateway name still is a DNS1123 label
Expand Down Expand Up @@ -368,10 +373,10 @@ func MakeHTTPServer(httpOption v1alpha1.HTTPOption, hosts []string) *istiov1beta
}

// GetNonWildcardIngressTLS gets Ingress TLS that do not reference wildcard certificates.
func GetNonWildcardIngressTLS(ingressTLS []v1alpha1.IngressTLS, nonWildcardSecrest map[string]*corev1.Secret) []v1alpha1.IngressTLS {
func GetNonWildcardIngressTLS(ingressTLS []v1alpha1.IngressTLS, nonWildcardSecrets map[string]*corev1.Secret) []v1alpha1.IngressTLS {
result := []v1alpha1.IngressTLS{}
for _, tls := range ingressTLS {
if _, ok := nonWildcardSecrest[secretKey(tls)]; ok {
if _, ok := nonWildcardSecrets[secretKey(tls)]; ok {
result = append(result, tls)
}
}
Expand Down
8 changes: 4 additions & 4 deletions pkg/reconciler/ingress/resources/gateway_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -785,7 +785,7 @@ func TestMakeIngressGateways(t *testing.T) {
},
})
t.Run(c.name, func(t *testing.T) {
got, err := MakeIngressGateways(ctx, c.ia, c.servers, svcLister)
got, err := MakeExternalIngressGateways(ctx, c.ia, c.servers, svcLister)
if (err != nil) != c.wantErr {
t.Fatalf("Test: %s; MakeIngressTLSGateways error = %v, WantErr %v", c.name, err, c.wantErr)
}
Expand Down Expand Up @@ -961,7 +961,7 @@ func TestMakeIngressTLSGateways(t *testing.T) {
},
})
t.Run(c.name, func(t *testing.T) {
got, err := MakeIngressTLSGateways(ctx, c.ia, c.ia.GetIngressTLSForVisibility(v1alpha1.IngressVisibilityExternalIP), c.originSecrets, svcLister)
got, err := MakeIngressTLSGateways(ctx, c.ia, v1alpha1.IngressVisibilityExternalIP, c.ia.GetIngressTLSForVisibility(v1alpha1.IngressVisibilityExternalIP), c.originSecrets, svcLister)
if (err != nil) != c.wantErr {
t.Fatalf("Test: %s; MakeIngressTLSGateways error = %v, WantErr %v", c.name, err, c.wantErr)
}
Expand Down Expand Up @@ -999,7 +999,7 @@ func TestGatewayName(t *testing.T) {
}

want := fmt.Sprintf("ingress-%d", adler32.Checksum([]byte("istio-system/gateway")))
got := GatewayName(ingress, svc)
got := GatewayName(ingress, "", svc)
if got != want {
t.Errorf("Unexpected gateway name. want %q, got %q", want, got)
}
Expand All @@ -1020,7 +1020,7 @@ func TestGatewayNameLongIngressName(t *testing.T) {
}

want := fmt.Sprintf("areallyverylongdomainnamethatexcd8923dee789a086a0ac4-%d", adler32.Checksum([]byte("istio-system/gateway")))
got := GatewayName(ingress, svc)
got := GatewayName(ingress, "", svc)
if got != want {
t.Errorf("Unexpected gateway name. want %q, got %q", want, got)
}
Expand Down
10 changes: 5 additions & 5 deletions pkg/reconciler/ingress/resources/secret.go
Original file line number Diff line number Diff line change
Expand Up @@ -33,11 +33,11 @@ import (
"knative.dev/pkg/tracker"
)

// GetSecrets gets the all of the secrets referenced by the given Ingress, and
// returns a map whose key is the a secret namespace/name key and value is pointer of the secret.
func GetSecrets(ing *v1alpha1.Ingress, secretLister corev1listers.SecretLister) (map[string]*corev1.Secret, error) {
// GetSecrets gets the all the secrets referenced by the given Ingress and visibility.
// Returns a map whose key is the secret namespace/name key and value is pointer of the secret.
func GetSecrets(ing *v1alpha1.Ingress, visibility v1alpha1.IngressVisibility, secretLister corev1listers.SecretLister) (map[string]*corev1.Secret, error) {
secrets := map[string]*corev1.Secret{}
for _, tls := range ing.GetIngressTLSForVisibility(v1alpha1.IngressVisibilityExternalIP) {
for _, tls := range ing.GetIngressTLSForVisibility(visibility) {
ref := secretKey(tls)
if _, ok := secrets[ref]; ok {
continue
Expand Down Expand Up @@ -72,7 +72,7 @@ func MakeSecrets(ctx context.Context, originSecrets map[string]*corev1.Secret, a
return secrets, nil
}

// MakeWildcardSecrets copies wildcard certificates from origin namespace to the namespace of gateway servicess so they could
// MakeWildcardSecrets copies wildcard certificates from origin namespace to the namespace of gateway services, so they can be
// consumed by Istio ingress.
func MakeWildcardSecrets(ctx context.Context, originWildcardCerts map[string]*corev1.Secret) ([]*corev1.Secret, error) {
nameNamespaces, err := GetIngressGatewaySvcNameNamespaces(ctx)
Expand Down
2 changes: 1 addition & 1 deletion pkg/reconciler/ingress/resources/secret_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -114,7 +114,7 @@ func TestGetSecrets(t *testing.T) {
for _, c := range cases {
createSecret(c.secret)
t.Run(c.name, func(t *testing.T) {
secrets, err := GetSecrets(c.ci, secretClient.Lister())
secrets, err := GetSecrets(c.ci, v1alpha1.IngressVisibilityExternalIP, secretClient.Lister())
if (err != nil) != c.wantErr {
t.Fatalf("Test: %s; GetSecrets error = %v, WantErr %v", c.name, err, c.wantErr)
}
Expand Down

0 comments on commit a9c85e4

Please sign in to comment.