Skip to content

Commit cb63d52

Browse files
authored
Merge pull request #18 from puertomontt/sslredirect
ssl redirect
2 parents 292a968 + 2262f55 commit cb63d52

10 files changed

Lines changed: 417 additions & 0 deletions

File tree

pkg/i2gw/implementations/kgateway/README.md

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -59,6 +59,8 @@ The command should generate Gateway API and Kgateway resources.
5959
- `nginx.ingress.kubernetes.io/limit-burst-multiplier`
6060
- `nginx.ingress.kubernetes.io/proxy-send-timeout`
6161
- `nginx.ingress.kubernetes.io/proxy-read-timeout`
62+
- `nginx.ingress.kubernetes.io/ssl-redirect`: When set to `"true"`, adds a `RequestRedirect` filter to HTTPRoute rules that redirects HTTP to HTTPS with a 301 status code.
63+
- `nginx.ingress.kubernetes.io/force-ssl-redirect`: When set to `"true"`, adds a `RequestRedirect` filter to HTTPRoute rules that redirects HTTP to HTTPS with a 301 status code. Treated identically to `ssl-redirect`.
6264

6365
### Backend Behavior
6466

@@ -111,6 +113,7 @@ Examples:
111113
- Body size annotations control `spec.buffer.maxRequestSize`
112114
- Rate limit annotations control `spec.rateLimit.local.tokenBucket`
113115
- Timeout annotations control `spec.timeouts.request` or `streamIdle`
116+
- SSL redirect annotations add `RequestRedirect` filters to HTTPRoute rules
114117

115118
## BackendConfigPolicy Projection
116119

pkg/i2gw/implementations/kgateway/emitter.go

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -180,6 +180,9 @@ func (e *Emitter) Emit(ir *intermediate.IR) ([]client.Object, error) {
180180
touched = true
181181
}
182182

183+
// Apply SSL redirect via RequestRedirect filter on HTTPRoute rules.
184+
applySSLRedirectPolicy(pol, httpRouteKey, &httpRouteContext, coverage)
185+
183186
if !touched {
184187
// No TrafficPolicy fields set for this policy; skip coverage wiring.
185188
continue

pkg/i2gw/implementations/kgateway/emitter_integration_test.go

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -242,6 +242,15 @@ func TestKgatewayIngressNginxIntegration_Golden(t *testing.T) {
242242
"pkg", "i2gw", "implementations", "kgateway", "testing", "testdata", "output", "service_upstream.yaml",
243243
),
244244
},
245+
{
246+
name: "ssl_redirect",
247+
inputRel: filepath.Join(
248+
"pkg", "i2gw", "implementations", "kgateway", "testing", "testdata", "input", "ssl_redirect.yaml",
249+
),
250+
goldenRel: filepath.Join(
251+
"pkg", "i2gw", "implementations", "kgateway", "testing", "testdata", "output", "ssl_redirect.yaml",
252+
),
253+
},
245254
{
246255
name: "basic_auth",
247256
inputRel: filepath.Join(
Lines changed: 78 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,78 @@
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+
"github.com/kgateway-dev/ingress2gateway/pkg/i2gw/intermediate"
21+
"k8s.io/apimachinery/pkg/types"
22+
"k8s.io/utils/ptr"
23+
gwv1 "sigs.k8s.io/gateway-api/apis/v1"
24+
)
25+
26+
// applySSLRedirectPolicy applies SSL redirect by adding a RequestRedirect filter
27+
// to HTTPRoute rules when SSLRedirect is enabled in the policy.
28+
//
29+
// Semantics:
30+
// - If SSLRedirect is enabled, add a RequestRedirect filter to rule-level Filters
31+
// - The filter redirects HTTP to HTTPS with a 301 status code
32+
// - The filter is applied to all rules covered by the policy
33+
func applySSLRedirectPolicy(
34+
pol intermediate.Policy,
35+
httpRouteKey types.NamespacedName,
36+
httpRouteContext *intermediate.HTTPRouteContext,
37+
coverage []intermediate.PolicyIndex,
38+
) {
39+
if pol.SSLRedirect == nil || !*pol.SSLRedirect {
40+
return
41+
}
42+
43+
// Get unique rule indices from coverage
44+
ruleSet := make(map[int]struct{})
45+
for _, idx := range coverage {
46+
ruleSet[idx.Rule] = struct{}{}
47+
}
48+
49+
// Add RequestRedirect filter to each covered rule
50+
for ruleIdx := range ruleSet {
51+
if ruleIdx >= len(httpRouteContext.Spec.Rules) {
52+
continue
53+
}
54+
55+
// Check if RequestRedirect filter already exists
56+
hasRedirect := false
57+
for _, filter := range httpRouteContext.Spec.Rules[ruleIdx].Filters {
58+
if filter.Type == gwv1.HTTPRouteFilterRequestRedirect {
59+
hasRedirect = true
60+
break
61+
}
62+
}
63+
64+
if !hasRedirect {
65+
// Add RequestRedirect filter to redirect HTTP to HTTPS
66+
httpRouteContext.Spec.Rules[ruleIdx].Filters = append(
67+
httpRouteContext.Spec.Rules[ruleIdx].Filters,
68+
gwv1.HTTPRouteFilter{
69+
Type: gwv1.HTTPRouteFilterRequestRedirect,
70+
RequestRedirect: &gwv1.HTTPRequestRedirectFilter{
71+
Scheme: ptr.To("https"),
72+
StatusCode: ptr.To(301),
73+
},
74+
},
75+
)
76+
}
77+
}
78+
}
Lines changed: 72 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,72 @@
1+
apiVersion: networking.k8s.io/v1
2+
kind: Ingress
3+
metadata:
4+
annotations:
5+
ingress2gateway.kubernetes.io/implementation: kgateway
6+
nginx.ingress.kubernetes.io/ssl-redirect: "true"
7+
name: ingress-ssl-redirect
8+
namespace: default
9+
spec:
10+
ingressClassName: nginx
11+
rules:
12+
- host: redirect.example
13+
http:
14+
paths:
15+
- backend:
16+
service:
17+
name: myservice
18+
port:
19+
number: 80
20+
path: /
21+
pathType: Prefix
22+
---
23+
apiVersion: networking.k8s.io/v1
24+
kind: Ingress
25+
metadata:
26+
annotations:
27+
ingress2gateway.kubernetes.io/implementation: kgateway
28+
nginx.ingress.kubernetes.io/ssl-redirect: "true"
29+
name: ingress-ssl-redirect-multiple-paths
30+
namespace: default
31+
spec:
32+
ingressClassName: nginx
33+
rules:
34+
- host: redirect.example
35+
http:
36+
paths:
37+
- backend:
38+
service:
39+
name: myservice
40+
port:
41+
number: 80
42+
path: /api
43+
pathType: Prefix
44+
- backend:
45+
service:
46+
name: myservice
47+
port:
48+
number: 80
49+
path: /web
50+
pathType: Prefix
51+
---
52+
apiVersion: networking.k8s.io/v1
53+
kind: Ingress
54+
metadata:
55+
annotations:
56+
ingress2gateway.kubernetes.io/implementation: kgateway
57+
nginx.ingress.kubernetes.io/force-ssl-redirect: "true"
58+
name: ingress-force-ssl-redirect
59+
namespace: default
60+
spec:
61+
ingressClassName: nginx
62+
rules:
63+
- host: force-redirect.example
64+
http:
65+
paths:
66+
- backend:
67+
service:
68+
name: myservice2
69+
port:
70+
number: 80
71+
path: /
72+
pathType: Prefix
Lines changed: 99 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,99 @@
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: force-redirect.example
12+
name: force-redirect-example-http
13+
port: 80
14+
protocol: HTTP
15+
- hostname: redirect.example
16+
name: redirect-example-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-force-ssl-redirect-force-redirect-example
27+
namespace: default
28+
spec:
29+
hostnames:
30+
- force-redirect.example
31+
parentRefs:
32+
- name: nginx
33+
rules:
34+
- backendRefs:
35+
- name: myservice2
36+
port: 80
37+
filters:
38+
- requestRedirect:
39+
scheme: https
40+
statusCode: 301
41+
type: RequestRedirect
42+
matches:
43+
- path:
44+
type: PathPrefix
45+
value: /
46+
status:
47+
parents: []
48+
---
49+
apiVersion: gateway.networking.k8s.io/v1
50+
kind: HTTPRoute
51+
metadata:
52+
annotations:
53+
gateway.networking.k8s.io/generator: ingress2gateway-dev
54+
name: ingress-ssl-redirect-redirect-example
55+
namespace: default
56+
spec:
57+
hostnames:
58+
- redirect.example
59+
parentRefs:
60+
- name: nginx
61+
rules:
62+
- backendRefs:
63+
- name: myservice
64+
port: 80
65+
filters:
66+
- requestRedirect:
67+
scheme: https
68+
statusCode: 301
69+
type: RequestRedirect
70+
matches:
71+
- path:
72+
type: PathPrefix
73+
value: /
74+
- backendRefs:
75+
- name: myservice
76+
port: 80
77+
filters:
78+
- requestRedirect:
79+
scheme: https
80+
statusCode: 301
81+
type: RequestRedirect
82+
matches:
83+
- path:
84+
type: PathPrefix
85+
value: /api
86+
- backendRefs:
87+
- name: myservice
88+
port: 80
89+
filters:
90+
- requestRedirect:
91+
scheme: https
92+
statusCode: 301
93+
type: RequestRedirect
94+
matches:
95+
- path:
96+
type: PathPrefix
97+
value: /web
98+
status:
99+
parents: []

pkg/i2gw/intermediate/provider_ingressnginx.go

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -164,6 +164,11 @@ type Policy struct {
164164
// BackendTLS defines the backend TLS policy.
165165
BackendTLS *BackendTLSPolicy
166166

167+
// SSLRedirect indicates whether SSL redirect is enabled, corresponding to
168+
// nginx.ingress.kubernetes.io/ssl-redirect. When true, requests should be
169+
// redirected to HTTPS.
170+
SSLRedirect *bool
171+
167172
// RuleBackendSources lists the (rule, backend) pairs within a merged HTTPRoute
168173
// that this policy applies to.
169174
//

pkg/i2gw/providers/ingressnginx/README.md

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -127,6 +127,16 @@ The ingress-nginx provider currently supports translating the following annotati
127127

128128
---
129129

130+
### SSL Redirect
131+
132+
- `nginx.ingress.kubernetes.io/ssl-redirect`: When set to `"true"`, enables SSL redirect for HTTP requests. For the Kgateway implementation, this maps to a `RequestRedirect` filter on HTTPRoute rules that redirects HTTP to HTTPS with a 301 status code.
133+
134+
- `nginx.ingress.kubernetes.io/force-ssl-redirect`: When set to `"true"`, enables SSL redirect for HTTP requests. This annotation is treated exactly the same as `ssl-redirect`. For the Kgateway implementation, this maps to a `RequestRedirect` filter on HTTPRoute rules that redirects HTTP to HTTPS with a 301 status code.
135+
136+
**Note:** Both annotations are supported and treated identically. If either annotation is set to `"true"` (case-insensitive), SSL redirect will be enabled. The redirect filter is added at the rule level in the HTTPRoute, redirecting all HTTP traffic to HTTPS.
137+
138+
---
139+
130140
## Provider Limitations
131141

132142
- Currently, kgateway is the only supported implementation-specific emitter.

pkg/i2gw/providers/ingressnginx/converter.go

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -51,6 +51,7 @@ func newResourcesToIRConverter() *resourcesToIRConverter {
5151
loadBalancingFeature,
5252
backendTLSFeature,
5353
serviceUpstreamFeature,
54+
sslRedirectFeature,
5455
},
5556
}
5657
}

0 commit comments

Comments
 (0)