Skip to content

Commit 21524ac

Browse files
committed
fix: cert watch for default https-listener
1 parent 10884b1 commit 21524ac

File tree

2 files changed

+154
-5
lines changed

2 files changed

+154
-5
lines changed

internal/controller/httpproxy_controller.go

Lines changed: 57 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1036,17 +1036,72 @@ func (r *HTTPProxyReconciler) buildCertificateStatuses(
10361036
}
10371037
statuses := make([]networkingv1alpha.HostnameStatus, 0, httpsListenerCount)
10381038

1039+
wildcardSuffix := "." + r.Config.Gateway.TargetDomain
1040+
10391041
for _, l := range gateway.Spec.Listeners {
10401042
if l.Protocol != gatewayv1.HTTPSProtocolType || l.Hostname == nil {
10411043
continue
10421044
}
10431045

1046+
hs := networkingv1alpha.HostnameStatus{Hostname: string(*l.Hostname)}
1047+
1048+
hostname := string(*l.Hostname)
1049+
hostnameUnderWildcard := strings.HasSuffix(hostname, wildcardSuffix) || hostname == r.Config.Gateway.TargetDomain
1050+
useSharedTLS := hostnameUnderWildcard && r.Config.Gateway.HasDefaultListenerTLSSecret()
1051+
1052+
if useSharedTLS {
1053+
secret := &v1.Secret{}
1054+
secretKey := client.ObjectKey{
1055+
Namespace: downstreamNamespaceName,
1056+
Name: r.Config.Gateway.DefaultListenerTLSSecretName,
1057+
}
1058+
if err := downstreamClient.Get(ctx, secretKey, secret); err != nil {
1059+
if apierrors.IsNotFound(err) {
1060+
apimeta.SetStatusCondition(&hs.Conditions, metav1.Condition{
1061+
Type: networkingv1alpha.HostnameConditionCertificateReady,
1062+
Status: metav1.ConditionFalse,
1063+
Reason: networkingv1alpha.CertificateReadyReasonPending,
1064+
Message: "Shared TLS secret not found in downstream cluster",
1065+
ObservedGeneration: httpProxy.Generation,
1066+
})
1067+
} else {
1068+
apimeta.SetStatusCondition(&hs.Conditions, metav1.Condition{
1069+
Type: networkingv1alpha.HostnameConditionCertificateReady,
1070+
Status: metav1.ConditionUnknown,
1071+
Reason: networkingv1alpha.CertificateReadyReasonPending,
1072+
Message: fmt.Sprintf("Failed to get shared TLS secret: %v", err),
1073+
ObservedGeneration: httpProxy.Generation,
1074+
})
1075+
}
1076+
statuses = append(statuses, hs)
1077+
continue
1078+
}
1079+
1080+
if len(secret.Data["tls.crt"]) > 0 && len(secret.Data["tls.key"]) > 0 {
1081+
apimeta.SetStatusCondition(&hs.Conditions, metav1.Condition{
1082+
Type: networkingv1alpha.HostnameConditionCertificateReady,
1083+
Status: metav1.ConditionTrue,
1084+
Reason: networkingv1alpha.CertificateReadyReasonCertificateIssued,
1085+
Message: "Shared wildcard TLS certificate is ready",
1086+
ObservedGeneration: httpProxy.Generation,
1087+
})
1088+
} else {
1089+
apimeta.SetStatusCondition(&hs.Conditions, metav1.Condition{
1090+
Type: networkingv1alpha.HostnameConditionCertificateReady,
1091+
Status: metav1.ConditionFalse,
1092+
Reason: networkingv1alpha.CertificateReadyReasonPending,
1093+
Message: "Shared TLS secret is missing tls.crt or tls.key data",
1094+
ObservedGeneration: httpProxy.Generation,
1095+
})
1096+
}
1097+
statuses = append(statuses, hs)
1098+
continue
1099+
}
1100+
10441101
certName := resourcename.GetValidDNS1123Name(fmt.Sprintf("%s-%s", gateway.Name, l.Name))
10451102
certificate := newUnstructuredForGVK(certificateGVK)
10461103
certKey := client.ObjectKey{Namespace: downstreamNamespaceName, Name: certName}
10471104

1048-
hs := networkingv1alpha.HostnameStatus{Hostname: string(*l.Hostname)}
1049-
10501105
if err := downstreamClient.Get(ctx, certKey, certificate); err != nil {
10511106
if apierrors.IsNotFound(err) {
10521107
apimeta.SetStatusCondition(&hs.Conditions, metav1.Condition{

internal/controller/httpproxy_controller_test.go

Lines changed: 97 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -2081,14 +2081,53 @@ func TestBuildCertificateStatuses(t *testing.T) {
20812081
return cert
20822082
}
20832083

2084+
sharedTLSConfig := config.NetworkServicesOperator{
2085+
Gateway: config.GatewayConfig{
2086+
TargetDomain: "example.com",
2087+
DefaultListenerTLSSecretName: "wildcard-tls",
2088+
},
2089+
}
2090+
2091+
gatewayWithWildcardHostname := &gatewayv1.Gateway{
2092+
ObjectMeta: metav1.ObjectMeta{Name: "my-proxy", Namespace: "test-ns"},
2093+
Spec: gatewayv1.GatewaySpec{
2094+
Listeners: []gatewayv1.Listener{
2095+
{
2096+
Name: "default-https",
2097+
Protocol: gatewayv1.HTTPSProtocolType,
2098+
Hostname: ptr.To(gatewayv1.Hostname("app.example.com")),
2099+
},
2100+
},
2101+
},
2102+
}
2103+
2104+
makeSharedTLSSecret := func(hasTLSData bool) *corev1.Secret {
2105+
s := &corev1.Secret{
2106+
ObjectMeta: metav1.ObjectMeta{
2107+
Namespace: downstreamNamespaceName,
2108+
Name: "wildcard-tls",
2109+
},
2110+
}
2111+
if hasTLSData {
2112+
s.Data = map[string][]byte{
2113+
"tls.crt": []byte("cert-data"),
2114+
"tls.key": []byte("key-data"),
2115+
}
2116+
}
2117+
return s
2118+
}
2119+
20842120
tests := []struct {
20852121
name string
2122+
config *config.NetworkServicesOperator
2123+
gateway *gatewayv1.Gateway
20862124
downstreamCluster bool
20872125
downstreamObjects []client.Object
20882126
wantNil bool
20892127
wantLen int
20902128
wantReason string
20912129
wantStatus metav1.ConditionStatus
2130+
wantMessage string
20922131
}{
20932132
{
20942133
name: "DownstreamCluster nil returns nil",
@@ -2098,7 +2137,7 @@ func TestBuildCertificateStatuses(t *testing.T) {
20982137
{
20992138
name: "certificate not found returns Pending",
21002139
downstreamCluster: true,
2101-
downstreamObjects: []client.Object{}, // no certificate
2140+
downstreamObjects: []client.Object{},
21022141
wantNil: false,
21032142
wantLen: 1,
21042143
wantReason: networkingv1alpha.CertificateReadyReasonPending,
@@ -2131,6 +2170,48 @@ func TestBuildCertificateStatuses(t *testing.T) {
21312170
wantReason: networkingv1alpha.CertificateReadyReasonProvisioningFailed,
21322171
wantStatus: metav1.ConditionFalse,
21332172
},
2173+
{
2174+
name: "shared TLS secret found and valid returns CertificateIssued",
2175+
config: &sharedTLSConfig,
2176+
gateway: gatewayWithWildcardHostname,
2177+
downstreamCluster: true,
2178+
downstreamObjects: []client.Object{makeSharedTLSSecret(true)},
2179+
wantLen: 1,
2180+
wantReason: networkingv1alpha.CertificateReadyReasonCertificateIssued,
2181+
wantStatus: metav1.ConditionTrue,
2182+
wantMessage: "Shared wildcard TLS certificate is ready",
2183+
},
2184+
{
2185+
name: "shared TLS secret not found returns Pending",
2186+
config: &sharedTLSConfig,
2187+
gateway: gatewayWithWildcardHostname,
2188+
downstreamCluster: true,
2189+
downstreamObjects: []client.Object{},
2190+
wantLen: 1,
2191+
wantReason: networkingv1alpha.CertificateReadyReasonPending,
2192+
wantStatus: metav1.ConditionFalse,
2193+
wantMessage: "Shared TLS secret not found in downstream cluster",
2194+
},
2195+
{
2196+
name: "shared TLS secret missing tls data returns Pending",
2197+
config: &sharedTLSConfig,
2198+
gateway: gatewayWithWildcardHostname,
2199+
downstreamCluster: true,
2200+
downstreamObjects: []client.Object{makeSharedTLSSecret(false)},
2201+
wantLen: 1,
2202+
wantReason: networkingv1alpha.CertificateReadyReasonPending,
2203+
wantStatus: metav1.ConditionFalse,
2204+
wantMessage: "Shared TLS secret is missing tls.crt or tls.key data",
2205+
},
2206+
{
2207+
name: "custom hostname still checks certificate even with shared TLS enabled",
2208+
config: &sharedTLSConfig,
2209+
downstreamCluster: true,
2210+
downstreamObjects: []client.Object{},
2211+
wantLen: 1,
2212+
wantReason: networkingv1alpha.CertificateReadyReasonPending,
2213+
wantStatus: metav1.ConditionFalse,
2214+
},
21342215
}
21352216

21362217
for _, tt := range tests {
@@ -2157,13 +2238,23 @@ func TestBuildCertificateStatuses(t *testing.T) {
21572238
downstreamCluster = &clusterWithClient{c: downstreamClient, scheme: scheme}
21582239
}
21592240

2241+
cfg := config.NetworkServicesOperator{}
2242+
if tt.config != nil {
2243+
cfg = *tt.config
2244+
}
2245+
2246+
gw := gatewayWithHTTPS
2247+
if tt.gateway != nil {
2248+
gw = tt.gateway
2249+
}
2250+
21602251
r := &HTTPProxyReconciler{
2161-
Config: config.NetworkServicesOperator{},
2252+
Config: cfg,
21622253
DownstreamCluster: downstreamCluster,
21632254
}
21642255

21652256
ctx := context.Background()
2166-
got := r.buildCertificateStatuses(ctx, upstreamClient, "local", gatewayWithHTTPS, httpProxy)
2257+
got := r.buildCertificateStatuses(ctx, upstreamClient, "local", gw, httpProxy)
21672258

21682259
if tt.wantNil {
21692260
assert.Nil(t, got)
@@ -2176,6 +2267,9 @@ func TestBuildCertificateStatuses(t *testing.T) {
21762267
require.NotNil(t, cond)
21772268
assert.Equal(t, tt.wantStatus, cond.Status)
21782269
assert.Equal(t, tt.wantReason, cond.Reason)
2270+
if tt.wantMessage != "" {
2271+
assert.Equal(t, tt.wantMessage, cond.Message)
2272+
}
21792273
}
21802274
})
21812275
}

0 commit comments

Comments
 (0)