Skip to content

Commit 646fab0

Browse files
authored
Merge pull request #14 from puertomontt/backend-tls
backend tls
2 parents 9d49265 + 5134295 commit 646fab0

12 files changed

Lines changed: 620 additions & 23 deletions

File tree

pkg/i2gw/implementations/kgateway/README.md

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -84,6 +84,12 @@ The command should generate Gateway API and Kgateway resources.
8484
- `nginx.ingress.kubernetes.io/auth-type`: Must be set to `"basic"` to enable basic authentication. Maps to `TrafficPolicy.spec.basicAuth`.
8585
- `nginx.ingress.kubernetes.io/auth-secret`: Specifies the secret containing basic auth credentials in `namespace/name` format (or just `name` if in the same namespace). Maps to `TrafficPolicy.spec.basicAuth.secretRef.name`.
8686

87+
### Backend TLS
88+
89+
- `nginx.ingress.kubernetes.io/proxy-ssl-secret`: Maps to `BackendConfigPolicy.spec.tls.secretRef`
90+
- `nginx.ingress.kubernetes.io/proxy-ssl-verify`: Maps to `BackendConfigPolicy.spec.tls.insecureSkipVerify` (inverted: `"on"` = `false`, `"off"` = `true`)
91+
- `nginx.ingress.kubernetes.io/proxy-ssl-name`: Maps to `BackendConfigPolicy.spec.tls.sni` (automatically enables SNI)
92+
8793
### Access Logging
8894

8995
- `nginx.ingress.kubernetes.io/enable-access-log`: If enabled, will create an HTTPListenerPolicy that will configure a basic policy for envoy access logging. Maps to `HTTPListenerPolicy.spec.accessLog[].fileSink`. This can be further customized as needed, see [docs](https://kgateway.dev/docs/envoy/2.0.x/security/access-logging/).
Lines changed: 139 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,139 @@
1+
/*
2+
Copyright 2023 The Kubernetes Authors.
3+
4+
Licensed under the Apache License, Version 2.0 (the "License");
5+
you may not use this file except in compliance with the License.
6+
You may obtain a copy of the License at
7+
8+
http://www.apache.org/licenses/LICENSE-2.0
9+
10+
Unless required by applicable law or agreed to in writing, software
11+
distributed under the License is distributed on an "AS IS" BASIS,
12+
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
See the License for the specific language governing permissions and
14+
limitations under the License.
15+
*/
16+
17+
package kgateway
18+
19+
import (
20+
"strings"
21+
22+
"github.com/kgateway-dev/ingress2gateway/pkg/i2gw/intermediate"
23+
"github.com/kgateway-dev/kgateway/v2/api/v1alpha1/kgateway"
24+
"github.com/kgateway-dev/kgateway/v2/api/v1alpha1/shared"
25+
corev1 "k8s.io/api/core/v1"
26+
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
27+
"k8s.io/apimachinery/pkg/types"
28+
"k8s.io/utils/ptr"
29+
gwv1 "sigs.k8s.io/gateway-api/apis/v1"
30+
)
31+
32+
// applyBackendTLSPolicy projects the BackendTLS IR policy into one or more
33+
// Kgateway BackendConfigPolicies.
34+
//
35+
// Semantics:
36+
// - We create at most one BackendConfigPolicy per Service.
37+
// - That policy's Spec.TLS is configured with client certificates, CA certificates,
38+
// SNI hostname, and verification settings from the Policy.BackendTLS.
39+
// - TargetRefs are populated with all core Service backends that this Policy covers
40+
// (based on RuleBackendSources).
41+
func applyBackendTLSPolicy(
42+
pol intermediate.Policy,
43+
httpRouteKey types.NamespacedName,
44+
httpRouteCtx intermediate.HTTPRouteContext,
45+
backendCfg map[types.NamespacedName]*kgateway.BackendConfigPolicy,
46+
) bool {
47+
if pol.BackendTLS == nil {
48+
return false
49+
}
50+
51+
backendTLS := pol.BackendTLS
52+
53+
// Parse secret name (format: "namespace/secretName" or just "secretName")
54+
// Note: LocalObjectReference doesn't support namespace, so the secret
55+
// must be in the same namespace as the BackendConfigPolicy
56+
secretName := backendTLS.SecretName
57+
if parts := strings.SplitN(backendTLS.SecretName, "/", 2); len(parts) == 2 {
58+
// If namespace is specified but different from policy namespace, use just the secret name
59+
// and assume it's in the same namespace as the policy
60+
secretName = parts[1]
61+
}
62+
63+
for _, idx := range pol.RuleBackendSources {
64+
if idx.Rule >= len(httpRouteCtx.Spec.Rules) {
65+
continue
66+
}
67+
rule := httpRouteCtx.Spec.Rules[idx.Rule]
68+
if idx.Backend >= len(rule.BackendRefs) {
69+
continue
70+
}
71+
72+
br := rule.BackendRefs[idx.Backend]
73+
74+
if br.BackendRef.Group != nil && *br.BackendRef.Group != "" {
75+
continue
76+
}
77+
if br.BackendRef.Kind != nil && *br.BackendRef.Kind != "Service" {
78+
continue
79+
}
80+
81+
svcName := string(br.BackendRef.Name)
82+
if svcName == "" {
83+
continue
84+
}
85+
86+
svcKey := types.NamespacedName{
87+
Namespace: httpRouteKey.Namespace,
88+
Name: svcName,
89+
}
90+
91+
// Create or reuse BackendConfigPolicy per Service
92+
bcp, exists := backendCfg[svcKey]
93+
if !exists {
94+
// Use a generic name that works for all backend config features
95+
policyName := svcName + "-backend-config"
96+
bcp = &kgateway.BackendConfigPolicy{
97+
ObjectMeta: metav1.ObjectMeta{
98+
Name: policyName,
99+
Namespace: httpRouteKey.Namespace,
100+
},
101+
Spec: kgateway.BackendConfigPolicySpec{
102+
TargetRefs: []shared.LocalPolicyTargetReference{
103+
{
104+
Group: "",
105+
Kind: "Service",
106+
Name: gwv1.ObjectName(svcName),
107+
},
108+
},
109+
},
110+
}
111+
bcp.SetGroupVersionKind(BackendConfigPolicyGVK)
112+
backendCfg[svcKey] = bcp
113+
}
114+
115+
// Configure TLS settings
116+
if bcp.Spec.TLS == nil {
117+
bcp.Spec.TLS = &kgateway.TLS{}
118+
}
119+
120+
// Set SNI hostname if specified
121+
if backendTLS.Hostname != "" {
122+
bcp.Spec.TLS.Sni = ptr.To(backendTLS.Hostname)
123+
}
124+
125+
// Set verification: InsecureSkipVerify is false when verify is on, true when verify is off
126+
if !backendTLS.Verify {
127+
bcp.Spec.TLS.InsecureSkipVerify = ptr.To(true)
128+
} else if secretName != "" {
129+
// Set secret reference (contains tls.crt, tls.key, and optionally ca.crt)
130+
bcp.Spec.TLS.SecretRef = &corev1.LocalObjectReference{
131+
Name: secretName,
132+
}
133+
// Note: LocalObjectReference doesn't support namespace, so the secret
134+
// must be in the same namespace as the BackendConfigPolicy
135+
}
136+
}
137+
138+
return true
139+
}

pkg/i2gw/implementations/kgateway/emitter.go

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -141,6 +141,15 @@ func (e *Emitter) Emit(ir *intermediate.IR) ([]client.Object, error) {
141141
backendCfg,
142142
)
143143

144+
// Apply backend TLS via BackendConfigPolicy.
145+
// Note: "touched" is not updated here, as this does not affect TrafficPolicy.
146+
applyBackendTLSPolicy(
147+
pol,
148+
httpRouteKey,
149+
httpRouteContext,
150+
backendCfg,
151+
)
152+
144153
// Apply enable-access-log via HTTPListenerPolicy.
145154
applyAccessLogPolicy(
146155
pol,

pkg/i2gw/implementations/kgateway/emitter_integration_test.go

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -215,6 +215,15 @@ func TestKgatewayIngressNginxIntegration_Golden(t *testing.T) {
215215
"pkg", "i2gw", "implementations", "kgateway", "testing", "testdata", "output", "load_balance.yaml",
216216
),
217217
},
218+
{
219+
name: "backend_tls",
220+
inputRel: filepath.Join(
221+
"pkg", "i2gw", "implementations", "kgateway", "testing", "testdata", "input", "backend_tls.yaml",
222+
),
223+
goldenRel: filepath.Join(
224+
"pkg", "i2gw", "implementations", "kgateway", "testing", "testdata", "output", "backend_tls.yaml",
225+
),
226+
},
218227
{
219228
name: "external_auth",
220229
inputRel: filepath.Join(
Lines changed: 52 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,52 @@
1+
---
2+
apiVersion: networking.k8s.io/v1
3+
kind: Ingress
4+
metadata:
5+
annotations:
6+
ingress2gateway.kubernetes.io/implementation: kgateway
7+
nginx.ingress.kubernetes.io/backend-protocol: HTTPS
8+
nginx.ingress.kubernetes.io/proxy-ssl-secret: default/base-certificate-tls
9+
nginx.ingress.kubernetes.io/proxy-ssl-server-name: "on"
10+
nginx.ingress.kubernetes.io/proxy-ssl-name: "tls.example.com"
11+
nginx.ingress.kubernetes.io/proxy-ssl-verify: "on"
12+
name: ingress-backendtls
13+
namespace: default
14+
spec:
15+
ingressClassName: nginx
16+
rules:
17+
- host: tls.example.org
18+
http:
19+
paths:
20+
- backend:
21+
service:
22+
name: httpbin2
23+
port:
24+
number: 80
25+
path: /
26+
pathType: Prefix
27+
---
28+
apiVersion: networking.k8s.io/v1
29+
kind: Ingress
30+
metadata:
31+
annotations:
32+
ingress2gateway.kubernetes.io/implementation: kgateway
33+
nginx.ingress.kubernetes.io/backend-protocol: HTTPS
34+
nginx.ingress.kubernetes.io/proxy-ssl-secret: default/base-certificate-tls
35+
nginx.ingress.kubernetes.io/proxy-ssl-server-name: "on"
36+
nginx.ingress.kubernetes.io/proxy-ssl-name: "tls.example.com"
37+
nginx.ingress.kubernetes.io/proxy-ssl-verify: "off"
38+
name: ingress-backendtls-verify-off
39+
namespace: default
40+
spec:
41+
ingressClassName: nginx
42+
rules:
43+
- host: insecure-tls.example.org
44+
http:
45+
paths:
46+
- backend:
47+
service:
48+
name: httpbin-insecure
49+
port:
50+
number: 80
51+
path: /
52+
pathType: Prefix

pkg/i2gw/implementations/kgateway/testing/testdata/input/golden.yaml

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -109,3 +109,29 @@ spec:
109109
number: 80
110110
path: /
111111
pathType: Prefix
112+
---
113+
apiVersion: networking.k8s.io/v1
114+
kind: Ingress
115+
metadata:
116+
annotations:
117+
ingress2gateway.kubernetes.io/implementation: kgateway
118+
nginx.ingress.kubernetes.io/backend-protocol: HTTPS
119+
nginx.ingress.kubernetes.io/proxy-ssl-secret: default/base-certificate-tls
120+
nginx.ingress.kubernetes.io/proxy-ssl-server-name: "on"
121+
nginx.ingress.kubernetes.io/proxy-ssl-name: "tls.example.com"
122+
nginx.ingress.kubernetes.io/proxy-ssl-verify: "on"
123+
name: ingress-backendtls
124+
namespace: default
125+
spec:
126+
ingressClassName: nginx
127+
rules:
128+
- host: tls.example.org
129+
http:
130+
paths:
131+
- backend:
132+
service:
133+
name: httpbin2
134+
port:
135+
number: 80
136+
path: /
137+
pathType: Prefix
Lines changed: 98 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,98 @@
1+
apiVersion: gateway.networking.k8s.io/v1
2+
kind: Gateway
3+
metadata:
4+
annotations:
5+
gateway.networking.k8s.io/generator: ingress2gateway-dev
6+
name: nginx
7+
namespace: default
8+
spec:
9+
gatewayClassName: kgateway
10+
listeners:
11+
- hostname: insecure-tls.example.org
12+
name: insecure-tls-example-org-http
13+
port: 80
14+
protocol: HTTP
15+
- hostname: tls.example.org
16+
name: tls-example-org-http
17+
port: 80
18+
protocol: HTTP
19+
status: {}
20+
---
21+
apiVersion: gateway.networking.k8s.io/v1
22+
kind: HTTPRoute
23+
metadata:
24+
annotations:
25+
gateway.networking.k8s.io/generator: ingress2gateway-dev
26+
name: ingress-backendtls-tls-example-org
27+
namespace: default
28+
spec:
29+
hostnames:
30+
- tls.example.org
31+
parentRefs:
32+
- name: nginx
33+
rules:
34+
- backendRefs:
35+
- name: httpbin2
36+
port: 80
37+
matches:
38+
- path:
39+
type: PathPrefix
40+
value: /
41+
status:
42+
parents: []
43+
---
44+
apiVersion: gateway.networking.k8s.io/v1
45+
kind: HTTPRoute
46+
metadata:
47+
annotations:
48+
gateway.networking.k8s.io/generator: ingress2gateway-dev
49+
name: ingress-backendtls-verify-off-insecure-tls-example-org
50+
namespace: default
51+
spec:
52+
hostnames:
53+
- insecure-tls.example.org
54+
parentRefs:
55+
- name: nginx
56+
rules:
57+
- backendRefs:
58+
- name: httpbin-insecure
59+
port: 80
60+
matches:
61+
- path:
62+
type: PathPrefix
63+
value: /
64+
status:
65+
parents: []
66+
---
67+
apiVersion: gateway.kgateway.dev/v1alpha1
68+
kind: BackendConfigPolicy
69+
metadata:
70+
name: httpbin-insecure-backend-config
71+
namespace: default
72+
spec:
73+
targetRefs:
74+
- group: ""
75+
kind: Service
76+
name: httpbin-insecure
77+
tls:
78+
insecureSkipVerify: true
79+
sni: tls.example.com
80+
status:
81+
ancestors: null
82+
---
83+
apiVersion: gateway.kgateway.dev/v1alpha1
84+
kind: BackendConfigPolicy
85+
metadata:
86+
name: httpbin2-backend-config
87+
namespace: default
88+
spec:
89+
targetRefs:
90+
- group: ""
91+
kind: Service
92+
name: httpbin2
93+
tls:
94+
secretRef:
95+
name: base-certificate-tls
96+
sni: tls.example.com
97+
status:
98+
ancestors: null

0 commit comments

Comments
 (0)