Skip to content

Commit a32e419

Browse files
committed
add support to provide TLS for Gateway
1 parent e1e2e73 commit a32e419

File tree

14 files changed

+1390
-682
lines changed

14 files changed

+1390
-682
lines changed

internal/controller/manager.go

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -139,9 +139,10 @@ func StartManager(cfg config.Config) error {
139139
GenericValidator: genericValidator,
140140
PolicyValidator: policyManager,
141141
},
142-
EventRecorder: recorder,
143-
MustExtractGVK: mustExtractGVK,
144-
PlusSecrets: plusSecrets,
142+
EventRecorder: recorder,
143+
MustExtractGVK: mustExtractGVK,
144+
PlusSecrets: plusSecrets,
145+
ExperimentalFeatures: cfg.ExperimentalFeatures,
145146
})
146147

147148
var handlerCollector handlerMetricsCollector = collectors.NewControllerNoopCollector()

internal/controller/nginx/config/base_http_config.go

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@ var baseHTTPTemplate = gotemplate.Must(gotemplate.New("baseHttp").Parse(baseHTTP
1212

1313
type httpConfig struct {
1414
DNSResolver *dataplane.DNSResolverConfig
15+
GatewaySecretID dataplane.SSLKeyPairID
1516
Includes []shared.Include
1617
NginxReadinessProbePort int32
1718
IPFamily shared.IPFamily
@@ -27,6 +28,7 @@ func executeBaseHTTPConfig(conf dataplane.Configuration) []executeResult {
2728
NginxReadinessProbePort: conf.BaseHTTPConfig.NginxReadinessProbePort,
2829
IPFamily: getIPFamily(conf.BaseHTTPConfig),
2930
DNSResolver: conf.BaseHTTPConfig.DNSResolver,
31+
GatewaySecretID: conf.BaseHTTPConfig.GatewaySecretID,
3032
}
3133

3234
results := make([]executeResult, 0, len(includes)+1)

internal/controller/nginx/config/base_http_config_template.go

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -48,6 +48,12 @@ server {
4848
}
4949
}
5050
51+
{{- if $.GatewaySecretID }}
52+
# Gateway Certificate
53+
proxy_ssl_certificate /etc/nginx/secrets/{{ $.GatewaySecretID }}.pem;
54+
proxy_ssl_certificate_key /etc/nginx/secrets/{{ $.GatewaySecretID }}.pem;
55+
{{- end }}
56+
5157
{{ range $i := .Includes -}}
5258
include {{ $i.Name }};
5359
{{ end -}}

internal/controller/nginx/config/base_http_config_test.go

Lines changed: 46 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -284,3 +284,49 @@ func TestExecuteBaseHttp_DNSResolver(t *testing.T) {
284284
})
285285
}
286286
}
287+
288+
func TestExecuteBaseHttp_GatewaySecretID(t *testing.T) {
289+
t.Parallel()
290+
291+
tests := []struct {
292+
name string
293+
expectedConfig string
294+
conf dataplane.Configuration
295+
}{
296+
{
297+
name: "with GatewaySecretID",
298+
conf: dataplane.Configuration{
299+
BaseHTTPConfig: dataplane.BaseHTTPConfig{
300+
GatewaySecretID: "client-secret",
301+
},
302+
},
303+
expectedConfig: "proxy_ssl_certificate /etc/nginx/secrets/client-secret.pem;" +
304+
"\nproxy_ssl_certificate_key /etc/nginx/secrets/client-secret.pem;",
305+
},
306+
{
307+
name: "without GatewaySecretID",
308+
conf: dataplane.Configuration{
309+
BaseHTTPConfig: dataplane.BaseHTTPConfig{
310+
GatewaySecretID: "",
311+
},
312+
},
313+
expectedConfig: "",
314+
},
315+
}
316+
317+
for _, test := range tests {
318+
t.Run(test.name, func(t *testing.T) {
319+
t.Parallel()
320+
g := NewWithT(t)
321+
322+
res := executeBaseHTTPConfig(test.conf)
323+
g.Expect(res).To(HaveLen(1))
324+
325+
httpConfig := string(res[0].data)
326+
327+
if test.expectedConfig != "" {
328+
g.Expect(httpConfig).To(ContainSubstring(test.expectedConfig))
329+
}
330+
})
331+
}
332+
}

internal/controller/state/change_processor.go

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -63,6 +63,8 @@ type ChangeProcessorConfig struct {
6363
GatewayCtlrName string
6464
// GatewayClassName is the name of the GatewayClass resource.
6565
GatewayClassName string
66+
// ExperimentalFeatures indicates whether experimental features are enabled.
67+
ExperimentalFeatures bool
6668
}
6769

6870
// ChangeProcessorImpl is an implementation of ChangeProcessor.
@@ -275,6 +277,7 @@ func (c *ChangeProcessorImpl) Process() *graph.Graph {
275277
c.cfg.PlusSecrets,
276278
c.cfg.Validators,
277279
c.cfg.Logger,
280+
c.cfg.ExperimentalFeatures,
278281
)
279282

280283
return c.latestGraph

internal/controller/state/conditions/conditions.go

Lines changed: 48 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -146,6 +146,14 @@ const (
146146
// parametersRef resource is invalid.
147147
GatewayReasonParamsRefInvalid v1.GatewayConditionReason = "ParametersRefInvalid"
148148

149+
// GatewayReasonSecretRefInvalid is used with the "GatewayResolvedRefs" condition when the
150+
// secretRef resource is invalid.
151+
GatewayReasonSecretRefInvalid v1.GatewayConditionReason = "SecretRefInvalid"
152+
153+
// GatewayReasonSecretRefNotPermitted is used with the "GatewayResolvedRefs" condition when the
154+
// secretRef resource is not permitted by any ReferenceGrant.
155+
GatewayReasonSecretRefNotPermitted v1.GatewayConditionReason = "SecretRefNotPermitted"
156+
149157
// PolicyReasonAncestorLimitReached is used with the "PolicyAccepted" condition when a policy
150158
// cannot be applied because the ancestor status list has reached the maximum size of 16.
151159
PolicyReasonAncestorLimitReached v1.PolicyConditionReason = "AncestorLimitReached"
@@ -292,6 +300,27 @@ func NewGatewayClassUnsupportedVersion(recommendedVersion string) []Condition {
292300
}
293301
}
294302

303+
// NewGatewaySecretRefNotPermitted returns Condition that indicates that the Gateway references a TLS secret that is not
304+
// permitted by any ReferenceGrant.
305+
func NewGatewaySecretRefNotPermitted(msg string) Condition {
306+
return Condition{
307+
Type: string(GatewayReasonResolvedRefs),
308+
Status: metav1.ConditionFalse,
309+
Reason: string(GatewayReasonSecretRefNotPermitted),
310+
Message: msg,
311+
}
312+
}
313+
314+
// NewGatewaySecretRefInvalid returns Condition that indicates that the Gateway references a TLS secret that is invalid.
315+
func NewGatewaySecretRefInvalid(msg string) Condition {
316+
return Condition{
317+
Type: string(GatewayReasonResolvedRefs),
318+
Status: metav1.ConditionFalse,
319+
Reason: string(GatewayReasonSecretRefInvalid),
320+
Message: msg,
321+
}
322+
}
323+
295324
// NewGatewayClassConflict returns a Condition that indicates that the GatewayClass is not accepted
296325
// due to a conflict with another GatewayClass.
297326
func NewGatewayClassConflict() Condition {
@@ -846,6 +875,25 @@ func NewGatewayInvalid(msg string) []Condition {
846875
}
847876
}
848877

878+
// NewGatewayUnsupportedValue returns Conditions that indicate that a field of the Gateway has an unsupported value.
879+
// Unsupported means that the value is not supported by the implementation or invalid.
880+
func NewGatewayUnsupportedValue(msg string) []Condition {
881+
return []Condition{
882+
{
883+
Type: string(v1.GatewayConditionAccepted),
884+
Status: metav1.ConditionFalse,
885+
Reason: string(GatewayReasonUnsupportedValue),
886+
Message: msg,
887+
},
888+
{
889+
Type: string(v1.GatewayConditionProgrammed),
890+
Status: metav1.ConditionFalse,
891+
Reason: string(GatewayReasonUnsupportedValue),
892+
Message: msg,
893+
},
894+
}
895+
}
896+
849897
// NewGatewayUnsupportedAddress returns a Condition that indicates the Gateway is not accepted because it
850898
// contains an address type that is not supported.
851899
func NewGatewayUnsupportedAddress(msg string) Condition {

internal/controller/state/dataplane/configuration.go

Lines changed: 33 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -81,9 +81,10 @@ func BuildConfiguration(
8181
gateway,
8282
serviceResolver,
8383
g.ReferencedServices,
84-
baseHTTPConfig.IPFamily),
84+
baseHTTPConfig.IPFamily,
85+
),
8586
BackendGroups: backendGroups,
86-
SSLKeyPairs: buildSSLKeyPairs(g.ReferencedSecrets, gateway.Listeners),
87+
SSLKeyPairs: buildSSLKeyPairs(g.ReferencedSecrets, gateway),
8788
CertBundles: buildCertBundles(
8889
buildRefCertificateBundles(g.ReferencedSecrets, g.ReferencedCaCertConfigMaps),
8990
backendGroups,
@@ -248,14 +249,14 @@ func buildStreamUpstreams(
248249
}
249250

250251
// buildSSLKeyPairs builds the SSLKeyPairs from the Secrets. It will only include Secrets that are referenced by
251-
// valid listeners, so that we don't include unused Secrets in the configuration of the data plane.
252+
// valid gateway and its listeners, so that we don't include unused Secrets in the configuration of the data plane.
252253
func buildSSLKeyPairs(
253254
secrets map[types.NamespacedName]*graph.Secret,
254-
listeners []*graph.Listener,
255+
gateway *graph.Gateway,
255256
) map[SSLKeyPairID]SSLKeyPair {
256257
keyPairs := make(map[SSLKeyPairID]SSLKeyPair)
257258

258-
for _, l := range listeners {
259+
for _, l := range gateway.Listeners {
259260
if l.Valid && l.ResolvedSecret != nil {
260261
id := generateSSLKeyPairID(*l.ResolvedSecret)
261262
secret := secrets[*l.ResolvedSecret]
@@ -268,6 +269,15 @@ func buildSSLKeyPairs(
268269
}
269270
}
270271

272+
if gateway.Valid && gateway.SecretRef != nil {
273+
id := generateSSLKeyPairID(*gateway.SecretRef)
274+
secret := secrets[*gateway.SecretRef]
275+
keyPairs[id] = SSLKeyPair{
276+
Cert: secret.CertBundle.Cert.TLSCert,
277+
Key: secret.CertBundle.Cert.TLSPrivateKey,
278+
}
279+
}
280+
271281
return keyPairs
272282
}
273283

@@ -1054,6 +1064,10 @@ func buildBaseHTTPConfig(
10541064
NginxReadinessProbePort: DefaultNginxReadinessProbePort,
10551065
}
10561066

1067+
if gateway.Valid && gateway.SecretRef != nil {
1068+
baseConfig.GatewaySecretID = generateSSLKeyPairID(*gateway.SecretRef)
1069+
}
1070+
10571071
// safe to access EffectiveNginxProxy since we only call this function when the Gateway is not nil.
10581072
np := gateway.EffectiveNginxProxy
10591073
if np == nil {
@@ -1077,8 +1091,20 @@ func buildBaseHTTPConfig(
10771091
}
10781092
}
10791093

1094+
if port := getNginxReadinessProbePort(np); port != 0 {
1095+
baseConfig.NginxReadinessProbePort = port
1096+
}
1097+
10801098
baseConfig.RewriteClientIPSettings = buildRewriteClientIPConfig(np.RewriteClientIP)
10811099

1100+
baseConfig.DNSResolver = buildDNSResolverConfig(np.DNSResolver)
1101+
1102+
return baseConfig
1103+
}
1104+
1105+
func getNginxReadinessProbePort(np *graph.EffectiveNginxProxy) int32 {
1106+
var port int32
1107+
10821108
if np.Kubernetes != nil {
10831109
var containerSpec *ngfAPIv1alpha2.ContainerSpec
10841110
if np.Kubernetes.Deployment != nil {
@@ -1087,13 +1113,10 @@ func buildBaseHTTPConfig(
10871113
containerSpec = &np.Kubernetes.DaemonSet.Container
10881114
}
10891115
if containerSpec != nil && containerSpec.ReadinessProbe != nil && containerSpec.ReadinessProbe.Port != nil {
1090-
baseConfig.NginxReadinessProbePort = *containerSpec.ReadinessProbe.Port
1116+
port = *containerSpec.ReadinessProbe.Port
10911117
}
10921118
}
1093-
1094-
baseConfig.DNSResolver = buildDNSResolverConfig(np.DNSResolver)
1095-
1096-
return baseConfig
1119+
return port
10971120
}
10981121

10991122
// buildBaseStreamConfig generates the base stream context config that should be applied to all stream servers.

0 commit comments

Comments
 (0)