Skip to content

Commit 3ec528d

Browse files
authored
Add translation for GKE Ssl Policy (#195)
* Add FrontendConfig to Resource Reader. * Add translation interface for FrontendConfig to GceGatewayIR * Convert sslPolicy into IR * Add translation interface for GceGatewayIR to GatewayExtension * Add Ssl Policy conversion. * Refactor ir_converter tests * Each test case will based on the same Ingress and Service template and make modification on the resources. * Add testing for frontendConfig->IR and IR->GatewayExtension
1 parent 7803824 commit 3ec528d

File tree

11 files changed

+476
-323
lines changed

11 files changed

+476
-323
lines changed

pkg/i2gw/intermediate/provider_gce.go

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,10 @@ package intermediate
1818

1919
type GceGatewayIR struct {
2020
EnableHTTPSRedirect bool
21+
SslPolicy *SslPolicyConfig
22+
}
23+
type SslPolicyConfig struct {
24+
Name string
2125
}
2226
type GceHTTPRouteIR struct{}
2327
type GceServiceIR struct {

pkg/i2gw/providers/gce/extensions/input_extensions.go

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,7 @@ import (
2121

2222
"github.com/kubernetes-sigs/ingress2gateway/pkg/i2gw/intermediate"
2323
backendconfigv1 "k8s.io/ingress-gce/pkg/apis/backendconfig/v1"
24+
frontendconfigv1beta1 "k8s.io/ingress-gce/pkg/apis/frontendconfig/v1beta1"
2425
)
2526

2627
func ValidateBeConfig(beConfig *backendconfigv1.BackendConfig) error {
@@ -52,3 +53,9 @@ func BuildIRSecurityPolicyConfig(beConfig *backendconfigv1.BackendConfig) *inter
5253
Name: beConfig.Spec.SecurityPolicy.Name,
5354
}
5455
}
56+
57+
func BuildIRSslPolicyConfig(feConfig *frontendconfigv1beta1.FrontendConfig) *intermediate.SslPolicyConfig {
58+
return &intermediate.SslPolicyConfig{
59+
Name: *feConfig.Spec.SslPolicy,
60+
}
61+
}

pkg/i2gw/providers/gce/extensions/output_extensions.go

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,7 @@ import (
2121
"github.com/kubernetes-sigs/ingress2gateway/pkg/i2gw/intermediate"
2222
)
2323

24-
func BuildBackendPolicySessionAffinityConfig(serviceIR intermediate.ProviderSpecificServiceIR) *gkegatewayv1.SessionAffinityConfig {
24+
func BuildGCPBackendPolicySessionAffinityConfig(serviceIR intermediate.ProviderSpecificServiceIR) *gkegatewayv1.SessionAffinityConfig {
2525
affinityType := serviceIR.Gce.SessionAffinity.AffinityType
2626
saConfig := gkegatewayv1.SessionAffinityConfig{
2727
Type: &affinityType,
@@ -32,7 +32,11 @@ func BuildBackendPolicySessionAffinityConfig(serviceIR intermediate.ProviderSpec
3232
return &saConfig
3333
}
3434

35-
func BuildBackendPolicySecurityPolicyConfig(serviceIR intermediate.ProviderSpecificServiceIR) *string {
35+
func BuildGCPBackendPolicySecurityPolicyConfig(serviceIR intermediate.ProviderSpecificServiceIR) *string {
3636
securityPolicy := serviceIR.Gce.SecurityPolicy.Name
3737
return &securityPolicy
3838
}
39+
40+
func BuildGCPGatewayPolicySecurityPolicyConfig(gatewayIR intermediate.ProviderSpecificGatewayIR) string {
41+
return gatewayIR.Gce.SslPolicy.Name
42+
}

pkg/i2gw/providers/gce/gateway_converter.go

Lines changed: 52 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -42,13 +42,58 @@ func (c *irToGatewayResourcesConverter) irToGateway(ir intermediate.IR) (i2gw.Ga
4242
if len(errs) != 0 {
4343
return i2gw.GatewayResources{}, errs
4444
}
45+
buildGceGatewayExtensions(ir, &gatewayResources)
4546
buildGceServiceExtensions(ir, &gatewayResources)
4647
return gatewayResources, nil
4748
}
4849

50+
func buildGceGatewayExtensions(ir intermediate.IR, gatewayResources *i2gw.GatewayResources) {
51+
for gwyKey, gatewayContext := range ir.Gateways {
52+
gwyPolicy := addGatewayPolicyIfConfigured(gwyKey, gatewayContext.ProviderSpecificIR)
53+
if gwyPolicy == nil {
54+
continue
55+
}
56+
obj, err := i2gw.CastToUnstructured(gwyPolicy)
57+
if err != nil {
58+
notify(notifications.ErrorNotification, "Failed to cast GCPGatewayPolicy to unstructured", gwyPolicy)
59+
continue
60+
}
61+
gatewayResources.GatewayExtensions = append(gatewayResources.GatewayExtensions, *obj)
62+
}
63+
}
64+
65+
func addGatewayPolicyIfConfigured(gatewayNamespacedName types.NamespacedName, gatewayIR intermediate.ProviderSpecificGatewayIR) *gkegatewayv1.GCPGatewayPolicy {
66+
if gatewayIR.Gce == nil {
67+
return nil
68+
}
69+
// If there is no specification related to GCPGatewayPolicy feature, return nil.
70+
if gatewayIR.Gce.SslPolicy == nil {
71+
return nil
72+
}
73+
gcpGatewayPolicy := gkegatewayv1.GCPGatewayPolicy{
74+
ObjectMeta: metav1.ObjectMeta{
75+
Namespace: gatewayNamespacedName.Namespace,
76+
Name: gatewayNamespacedName.Name,
77+
},
78+
Spec: gkegatewayv1.GCPGatewayPolicySpec{
79+
Default: &gkegatewayv1.GCPGatewayPolicyConfig{},
80+
TargetRef: gatewayv1alpha2.NamespacedPolicyTargetReference{
81+
Group: "gateway.networking.k8s.io",
82+
Kind: "Gateway",
83+
Name: gatewayv1.ObjectName(gatewayNamespacedName.Name),
84+
},
85+
},
86+
}
87+
gcpGatewayPolicy.SetGroupVersionKind(GCPGatewayPolicyGVK)
88+
if gatewayIR.Gce.SslPolicy != nil {
89+
gcpGatewayPolicy.Spec.Default.SslPolicy = extensions.BuildGCPGatewayPolicySecurityPolicyConfig(gatewayIR)
90+
}
91+
return &gcpGatewayPolicy
92+
}
93+
4994
func buildGceServiceExtensions(ir intermediate.IR, gatewayResources *i2gw.GatewayResources) {
5095
for svcKey, serviceIR := range ir.Services {
51-
bePolicy := addBackendPolicyIfConfigured(svcKey, serviceIR)
96+
bePolicy := addGCPBackendPolicyIfConfigured(svcKey, serviceIR)
5297
if bePolicy == nil {
5398
continue
5499
}
@@ -61,11 +106,11 @@ func buildGceServiceExtensions(ir intermediate.IR, gatewayResources *i2gw.Gatewa
61106
}
62107
}
63108

64-
func addBackendPolicyIfConfigured(serviceNamespacedName types.NamespacedName, serviceIR intermediate.ProviderSpecificServiceIR) *gkegatewayv1.GCPBackendPolicy {
109+
func addGCPBackendPolicyIfConfigured(serviceNamespacedName types.NamespacedName, serviceIR intermediate.ProviderSpecificServiceIR) *gkegatewayv1.GCPBackendPolicy {
65110
if serviceIR.Gce == nil {
66111
return nil
67112
}
68-
backendPolicy := gkegatewayv1.GCPBackendPolicy{
113+
gcpBackendPolicy := gkegatewayv1.GCPBackendPolicy{
69114
ObjectMeta: metav1.ObjectMeta{
70115
Namespace: serviceNamespacedName.Namespace,
71116
Name: serviceNamespacedName.Name,
@@ -79,14 +124,14 @@ func addBackendPolicyIfConfigured(serviceNamespacedName types.NamespacedName, se
79124
},
80125
},
81126
}
82-
backendPolicy.SetGroupVersionKind(GCPBackendPolicyGVK)
127+
gcpBackendPolicy.SetGroupVersionKind(GCPBackendPolicyGVK)
83128

84129
if serviceIR.Gce.SessionAffinity != nil {
85-
backendPolicy.Spec.Default.SessionAffinity = extensions.BuildBackendPolicySessionAffinityConfig(serviceIR)
130+
gcpBackendPolicy.Spec.Default.SessionAffinity = extensions.BuildGCPBackendPolicySessionAffinityConfig(serviceIR)
86131
}
87132
if serviceIR.Gce.SecurityPolicy != nil {
88-
backendPolicy.Spec.Default.SecurityPolicy = extensions.BuildBackendPolicySecurityPolicyConfig(serviceIR)
133+
gcpBackendPolicy.Spec.Default.SecurityPolicy = extensions.BuildGCPBackendPolicySecurityPolicyConfig(serviceIR)
89134
}
90135

91-
return &backendPolicy
136+
return &gcpBackendPolicy
92137
}

pkg/i2gw/providers/gce/gateway_converter_test.go

Lines changed: 64 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -36,9 +36,10 @@ import (
3636
)
3737

3838
const (
39-
testGatewayName = "test-gateway"
40-
testHTTPRouteName = "test-http-route"
41-
testSaBackendPolicyName = testServiceName
39+
testGatewayName = "test-gateway"
40+
testHTTPRouteName = "test-http-route"
41+
testSaGCPBackendPolicyName = testServiceName
42+
testSslGCPGatewayPolicyName = testGatewayName
4243
)
4344

4445
var (
@@ -96,7 +97,7 @@ var (
9697
},
9798
ObjectMeta: metav1.ObjectMeta{
9899
Namespace: testNamespace,
99-
Name: testSaBackendPolicyName,
100+
Name: testSaGCPBackendPolicyName,
100101
},
101102
Spec: gkegatewayv1.GCPBackendPolicySpec{
102103
Default: &gkegatewayv1.GCPBackendPolicyConfig{
@@ -120,7 +121,7 @@ var (
120121
},
121122
ObjectMeta: metav1.ObjectMeta{
122123
Namespace: testNamespace,
123-
Name: testSaBackendPolicyName,
124+
Name: testSaGCPBackendPolicyName,
124125
},
125126
Spec: gkegatewayv1.GCPBackendPolicySpec{
126127
Default: &gkegatewayv1.GCPBackendPolicyConfig{
@@ -143,7 +144,7 @@ var (
143144
},
144145
ObjectMeta: metav1.ObjectMeta{
145146
Namespace: testNamespace,
146-
Name: testSaBackendPolicyName,
147+
Name: testSaGCPBackendPolicyName,
147148
},
148149
Spec: gkegatewayv1.GCPBackendPolicySpec{
149150
Default: &gkegatewayv1.GCPBackendPolicyConfig{
@@ -156,6 +157,27 @@ var (
156157
},
157158
},
158159
}
160+
161+
testSslGCPGatewayPolicy = gkegatewayv1.GCPGatewayPolicy{
162+
TypeMeta: metav1.TypeMeta{
163+
APIVersion: "networking.gke.io/v1",
164+
Kind: "GCPGatewayPolicy",
165+
},
166+
ObjectMeta: metav1.ObjectMeta{
167+
Namespace: testNamespace,
168+
Name: testSslGCPGatewayPolicyName,
169+
},
170+
Spec: gkegatewayv1.GCPGatewayPolicySpec{
171+
Default: &gkegatewayv1.GCPGatewayPolicyConfig{
172+
SslPolicy: testSslPolicy,
173+
},
174+
TargetRef: v1alpha2.NamespacedPolicyTargetReference{
175+
Group: "gateway.networking.k8s.io",
176+
Kind: "Gateway",
177+
Name: gatewayv1.ObjectName(testGatewayName),
178+
},
179+
},
180+
}
159181
)
160182

161183
func Test_irToGateway(t *testing.T) {
@@ -171,6 +193,10 @@ func Test_irToGateway(t *testing.T) {
171193
if err != nil {
172194
t.Errorf("Failed to generate unstructured GCP Backend Policy with Security Policy feature: %v", err)
173195
}
196+
testSslGCPGatewayPolicyUnstructured, err := i2gw.CastToUnstructured(&testSslGCPGatewayPolicy)
197+
if err != nil {
198+
t.Errorf("Failed to generate unstructured GCP Gateway Policy with Ssl Policy feature: %v", err)
199+
}
174200

175201
testCases := []struct {
176202
name string
@@ -287,6 +313,38 @@ func Test_irToGateway(t *testing.T) {
287313
},
288314
expectedErrors: field.ErrorList{},
289315
},
316+
{
317+
name: "ingress with a Frontend Config specifying Ssl Policy",
318+
ir: intermediate.IR{
319+
Gateways: map[types.NamespacedName]intermediate.GatewayContext{
320+
{Namespace: testNamespace, Name: testGatewayName}: {
321+
Gateway: testGateway,
322+
ProviderSpecificIR: intermediate.ProviderSpecificGatewayIR{
323+
Gce: &intermediate.GceGatewayIR{
324+
SslPolicy: &intermediate.SslPolicyConfig{Name: testSslPolicy},
325+
},
326+
},
327+
},
328+
},
329+
HTTPRoutes: map[types.NamespacedName]intermediate.HTTPRouteContext{
330+
{Namespace: testNamespace, Name: testHTTPRouteName}: {
331+
HTTPRoute: testHTTPRoute,
332+
},
333+
},
334+
},
335+
expectedGatewayResources: i2gw.GatewayResources{
336+
Gateways: map[types.NamespacedName]gatewayv1.Gateway{
337+
{Namespace: testNamespace, Name: testGatewayName}: testGateway,
338+
},
339+
HTTPRoutes: map[types.NamespacedName]gatewayv1.HTTPRoute{
340+
{Namespace: testNamespace, Name: testHTTPRouteName}: testHTTPRoute,
341+
},
342+
GatewayExtensions: []unstructured.Unstructured{
343+
*testSslGCPGatewayPolicyUnstructured,
344+
},
345+
},
346+
expectedErrors: field.ErrorList{},
347+
},
290348
}
291349

292350
for _, tc := range testCases {

pkg/i2gw/providers/gce/gce.go

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,7 @@ import (
2525
"github.com/kubernetes-sigs/ingress2gateway/pkg/i2gw/notifications"
2626
"k8s.io/apimachinery/pkg/util/validation/field"
2727
backendconfigv1 "k8s.io/ingress-gce/pkg/apis/backendconfig/v1"
28+
frontendconfigv1beta1 "k8s.io/ingress-gce/pkg/apis/frontendconfig/v1beta1"
2829
)
2930

3031
const ProviderName = "gce"
@@ -42,12 +43,15 @@ type Provider struct {
4243
}
4344

4445
func NewProvider(conf *i2gw.ProviderConf) i2gw.Provider {
45-
// Add BackendConfig to Schema when reading in-cluster so these resources
46-
// can be recognized.
46+
// Add BackendConfig and FrontendConfig to Schema when reading in-cluster
47+
// so these resources can be recognized.
4748
if conf.Client != nil {
4849
if err := backendconfigv1.AddToScheme(conf.Client.Scheme()); err != nil {
4950
notify(notifications.ErrorNotification, "Failed to add v1 BackendConfig Scheme")
5051
}
52+
if err := frontendconfigv1beta1.AddToScheme(conf.Client.Scheme()); err != nil {
53+
notify(notifications.ErrorNotification, "Failed to add v1beta1 FrontendConfig Scheme")
54+
}
5155
}
5256
return &Provider{
5357
storage: newResourcesStorage(),

pkg/i2gw/providers/gce/ir_converter.go

Lines changed: 62 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,7 @@ import (
3232
"k8s.io/apimachinery/pkg/types"
3333
"k8s.io/apimachinery/pkg/util/validation/field"
3434
backendconfigv1 "k8s.io/ingress-gce/pkg/apis/backendconfig/v1"
35+
frontendconfigv1beta1 "k8s.io/ingress-gce/pkg/apis/frontendconfig/v1beta1"
3536
)
3637

3738
type contextKey int
@@ -82,10 +83,71 @@ func (c *resourcesToIRConverter) convertToIR(storage *storage) (intermediate.IR,
8283
if len(errs) > 0 {
8384
return intermediate.IR{}, errs
8485
}
86+
buildGceGatewayIR(c.ctx, storage, &ir)
8587
buildGceServiceIR(c.ctx, storage, &ir)
8688
return ir, errs
8789
}
8890

91+
func buildGceGatewayIR(ctx context.Context, storage *storage, ir *intermediate.IR) {
92+
if ir.Gateways == nil {
93+
ir.Gateways = make(map[types.NamespacedName]intermediate.GatewayContext)
94+
}
95+
96+
feConfigToGwys := getFrontendConfigMapping(ctx, storage)
97+
for feConfigKey, feConfig := range storage.FrontendConfigs {
98+
if feConfig == nil {
99+
continue
100+
}
101+
gceGatewayIR := feConfigToGceGatewayIR(feConfig)
102+
gateways := feConfigToGwys[feConfigKey]
103+
104+
for _, gwyKey := range gateways {
105+
gatewayContext := ir.Gateways[gwyKey]
106+
gatewayContext.ProviderSpecificIR.Gce = &gceGatewayIR
107+
ir.Gateways[gwyKey] = gatewayContext
108+
}
109+
}
110+
}
111+
112+
type gatewayNames []types.NamespacedName
113+
114+
func getFrontendConfigMapping(ctx context.Context, storage *storage) map[types.NamespacedName]gatewayNames {
115+
feConfigToGwys := make(map[types.NamespacedName]gatewayNames)
116+
117+
for _, ingress := range storage.Ingresses {
118+
gwyKey := types.NamespacedName{Namespace: ingress.Namespace, Name: common.GetIngressClass(*ingress)}
119+
// ing := types.NamespacedName{Namespace: ingress.Namespace, Name: ingress.Name}
120+
ctx = context.WithValue(ctx, serviceKey, ingress)
121+
122+
feConfigName, exists := getFrontendConfigAnnotation(ingress)
123+
if exists {
124+
feConfigKey := types.NamespacedName{Namespace: ingress.Namespace, Name: feConfigName}
125+
feConfigToGwys[feConfigKey] = append(feConfigToGwys[feConfigKey], gwyKey)
126+
continue
127+
}
128+
129+
}
130+
return feConfigToGwys
131+
}
132+
133+
// Get names of the FrontendConfig in the cluster based on the FrontendConfig
134+
// annotation on k8s Services.
135+
func getFrontendConfigAnnotation(ing *networkingv1.Ingress) (string, bool) {
136+
val, ok := ing.ObjectMeta.Annotations[frontendConfigKey]
137+
if !ok {
138+
return "", false
139+
}
140+
return val, true
141+
}
142+
143+
func feConfigToGceGatewayIR(feConfig *frontendconfigv1beta1.FrontendConfig) intermediate.GceGatewayIR {
144+
var gceGatewayIR intermediate.GceGatewayIR
145+
if feConfig.Spec.SslPolicy != nil {
146+
gceGatewayIR.SslPolicy = extensions.BuildIRSslPolicyConfig(feConfig)
147+
}
148+
return gceGatewayIR
149+
}
150+
89151
type serviceNames []types.NamespacedName
90152

91153
func buildGceServiceIR(ctx context.Context, storage *storage, ir *intermediate.IR) {

0 commit comments

Comments
 (0)