Skip to content

Commit

Permalink
Add translation for GKE Ssl Policy (#195)
Browse files Browse the repository at this point in the history
* 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
  • Loading branch information
sawsa307 authored Sep 30, 2024
1 parent 7803824 commit 3ec528d
Show file tree
Hide file tree
Showing 11 changed files with 476 additions and 323 deletions.
4 changes: 4 additions & 0 deletions pkg/i2gw/intermediate/provider_gce.go
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,10 @@ package intermediate

type GceGatewayIR struct {
EnableHTTPSRedirect bool
SslPolicy *SslPolicyConfig
}
type SslPolicyConfig struct {
Name string
}
type GceHTTPRouteIR struct{}
type GceServiceIR struct {
Expand Down
7 changes: 7 additions & 0 deletions pkg/i2gw/providers/gce/extensions/input_extensions.go
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@ import (

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

func ValidateBeConfig(beConfig *backendconfigv1.BackendConfig) error {
Expand Down Expand Up @@ -52,3 +53,9 @@ func BuildIRSecurityPolicyConfig(beConfig *backendconfigv1.BackendConfig) *inter
Name: beConfig.Spec.SecurityPolicy.Name,
}
}

func BuildIRSslPolicyConfig(feConfig *frontendconfigv1beta1.FrontendConfig) *intermediate.SslPolicyConfig {
return &intermediate.SslPolicyConfig{
Name: *feConfig.Spec.SslPolicy,
}
}
8 changes: 6 additions & 2 deletions pkg/i2gw/providers/gce/extensions/output_extensions.go
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@ import (
"github.com/kubernetes-sigs/ingress2gateway/pkg/i2gw/intermediate"
)

func BuildBackendPolicySessionAffinityConfig(serviceIR intermediate.ProviderSpecificServiceIR) *gkegatewayv1.SessionAffinityConfig {
func BuildGCPBackendPolicySessionAffinityConfig(serviceIR intermediate.ProviderSpecificServiceIR) *gkegatewayv1.SessionAffinityConfig {
affinityType := serviceIR.Gce.SessionAffinity.AffinityType
saConfig := gkegatewayv1.SessionAffinityConfig{
Type: &affinityType,
Expand All @@ -32,7 +32,11 @@ func BuildBackendPolicySessionAffinityConfig(serviceIR intermediate.ProviderSpec
return &saConfig
}

func BuildBackendPolicySecurityPolicyConfig(serviceIR intermediate.ProviderSpecificServiceIR) *string {
func BuildGCPBackendPolicySecurityPolicyConfig(serviceIR intermediate.ProviderSpecificServiceIR) *string {
securityPolicy := serviceIR.Gce.SecurityPolicy.Name
return &securityPolicy
}

func BuildGCPGatewayPolicySecurityPolicyConfig(gatewayIR intermediate.ProviderSpecificGatewayIR) string {
return gatewayIR.Gce.SslPolicy.Name
}
59 changes: 52 additions & 7 deletions pkg/i2gw/providers/gce/gateway_converter.go
Original file line number Diff line number Diff line change
Expand Up @@ -42,13 +42,58 @@ func (c *irToGatewayResourcesConverter) irToGateway(ir intermediate.IR) (i2gw.Ga
if len(errs) != 0 {
return i2gw.GatewayResources{}, errs
}
buildGceGatewayExtensions(ir, &gatewayResources)
buildGceServiceExtensions(ir, &gatewayResources)
return gatewayResources, nil
}

func buildGceGatewayExtensions(ir intermediate.IR, gatewayResources *i2gw.GatewayResources) {
for gwyKey, gatewayContext := range ir.Gateways {
gwyPolicy := addGatewayPolicyIfConfigured(gwyKey, gatewayContext.ProviderSpecificIR)
if gwyPolicy == nil {
continue
}
obj, err := i2gw.CastToUnstructured(gwyPolicy)
if err != nil {
notify(notifications.ErrorNotification, "Failed to cast GCPGatewayPolicy to unstructured", gwyPolicy)
continue
}
gatewayResources.GatewayExtensions = append(gatewayResources.GatewayExtensions, *obj)
}
}

func addGatewayPolicyIfConfigured(gatewayNamespacedName types.NamespacedName, gatewayIR intermediate.ProviderSpecificGatewayIR) *gkegatewayv1.GCPGatewayPolicy {
if gatewayIR.Gce == nil {
return nil
}
// If there is no specification related to GCPGatewayPolicy feature, return nil.
if gatewayIR.Gce.SslPolicy == nil {
return nil
}
gcpGatewayPolicy := gkegatewayv1.GCPGatewayPolicy{
ObjectMeta: metav1.ObjectMeta{
Namespace: gatewayNamespacedName.Namespace,
Name: gatewayNamespacedName.Name,
},
Spec: gkegatewayv1.GCPGatewayPolicySpec{
Default: &gkegatewayv1.GCPGatewayPolicyConfig{},
TargetRef: gatewayv1alpha2.NamespacedPolicyTargetReference{
Group: "gateway.networking.k8s.io",
Kind: "Gateway",
Name: gatewayv1.ObjectName(gatewayNamespacedName.Name),
},
},
}
gcpGatewayPolicy.SetGroupVersionKind(GCPGatewayPolicyGVK)
if gatewayIR.Gce.SslPolicy != nil {
gcpGatewayPolicy.Spec.Default.SslPolicy = extensions.BuildGCPGatewayPolicySecurityPolicyConfig(gatewayIR)
}
return &gcpGatewayPolicy
}

func buildGceServiceExtensions(ir intermediate.IR, gatewayResources *i2gw.GatewayResources) {
for svcKey, serviceIR := range ir.Services {
bePolicy := addBackendPolicyIfConfigured(svcKey, serviceIR)
bePolicy := addGCPBackendPolicyIfConfigured(svcKey, serviceIR)
if bePolicy == nil {
continue
}
Expand All @@ -61,11 +106,11 @@ func buildGceServiceExtensions(ir intermediate.IR, gatewayResources *i2gw.Gatewa
}
}

func addBackendPolicyIfConfigured(serviceNamespacedName types.NamespacedName, serviceIR intermediate.ProviderSpecificServiceIR) *gkegatewayv1.GCPBackendPolicy {
func addGCPBackendPolicyIfConfigured(serviceNamespacedName types.NamespacedName, serviceIR intermediate.ProviderSpecificServiceIR) *gkegatewayv1.GCPBackendPolicy {
if serviceIR.Gce == nil {
return nil
}
backendPolicy := gkegatewayv1.GCPBackendPolicy{
gcpBackendPolicy := gkegatewayv1.GCPBackendPolicy{
ObjectMeta: metav1.ObjectMeta{
Namespace: serviceNamespacedName.Namespace,
Name: serviceNamespacedName.Name,
Expand All @@ -79,14 +124,14 @@ func addBackendPolicyIfConfigured(serviceNamespacedName types.NamespacedName, se
},
},
}
backendPolicy.SetGroupVersionKind(GCPBackendPolicyGVK)
gcpBackendPolicy.SetGroupVersionKind(GCPBackendPolicyGVK)

if serviceIR.Gce.SessionAffinity != nil {
backendPolicy.Spec.Default.SessionAffinity = extensions.BuildBackendPolicySessionAffinityConfig(serviceIR)
gcpBackendPolicy.Spec.Default.SessionAffinity = extensions.BuildGCPBackendPolicySessionAffinityConfig(serviceIR)
}
if serviceIR.Gce.SecurityPolicy != nil {
backendPolicy.Spec.Default.SecurityPolicy = extensions.BuildBackendPolicySecurityPolicyConfig(serviceIR)
gcpBackendPolicy.Spec.Default.SecurityPolicy = extensions.BuildGCPBackendPolicySecurityPolicyConfig(serviceIR)
}

return &backendPolicy
return &gcpBackendPolicy
}
70 changes: 64 additions & 6 deletions pkg/i2gw/providers/gce/gateway_converter_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -36,9 +36,10 @@ import (
)

const (
testGatewayName = "test-gateway"
testHTTPRouteName = "test-http-route"
testSaBackendPolicyName = testServiceName
testGatewayName = "test-gateway"
testHTTPRouteName = "test-http-route"
testSaGCPBackendPolicyName = testServiceName
testSslGCPGatewayPolicyName = testGatewayName
)

var (
Expand Down Expand Up @@ -96,7 +97,7 @@ var (
},
ObjectMeta: metav1.ObjectMeta{
Namespace: testNamespace,
Name: testSaBackendPolicyName,
Name: testSaGCPBackendPolicyName,
},
Spec: gkegatewayv1.GCPBackendPolicySpec{
Default: &gkegatewayv1.GCPBackendPolicyConfig{
Expand All @@ -120,7 +121,7 @@ var (
},
ObjectMeta: metav1.ObjectMeta{
Namespace: testNamespace,
Name: testSaBackendPolicyName,
Name: testSaGCPBackendPolicyName,
},
Spec: gkegatewayv1.GCPBackendPolicySpec{
Default: &gkegatewayv1.GCPBackendPolicyConfig{
Expand All @@ -143,7 +144,7 @@ var (
},
ObjectMeta: metav1.ObjectMeta{
Namespace: testNamespace,
Name: testSaBackendPolicyName,
Name: testSaGCPBackendPolicyName,
},
Spec: gkegatewayv1.GCPBackendPolicySpec{
Default: &gkegatewayv1.GCPBackendPolicyConfig{
Expand All @@ -156,6 +157,27 @@ var (
},
},
}

testSslGCPGatewayPolicy = gkegatewayv1.GCPGatewayPolicy{
TypeMeta: metav1.TypeMeta{
APIVersion: "networking.gke.io/v1",
Kind: "GCPGatewayPolicy",
},
ObjectMeta: metav1.ObjectMeta{
Namespace: testNamespace,
Name: testSslGCPGatewayPolicyName,
},
Spec: gkegatewayv1.GCPGatewayPolicySpec{
Default: &gkegatewayv1.GCPGatewayPolicyConfig{
SslPolicy: testSslPolicy,
},
TargetRef: v1alpha2.NamespacedPolicyTargetReference{
Group: "gateway.networking.k8s.io",
Kind: "Gateway",
Name: gatewayv1.ObjectName(testGatewayName),
},
},
}
)

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

testCases := []struct {
name string
Expand Down Expand Up @@ -287,6 +313,38 @@ func Test_irToGateway(t *testing.T) {
},
expectedErrors: field.ErrorList{},
},
{
name: "ingress with a Frontend Config specifying Ssl Policy",
ir: intermediate.IR{
Gateways: map[types.NamespacedName]intermediate.GatewayContext{
{Namespace: testNamespace, Name: testGatewayName}: {
Gateway: testGateway,
ProviderSpecificIR: intermediate.ProviderSpecificGatewayIR{
Gce: &intermediate.GceGatewayIR{
SslPolicy: &intermediate.SslPolicyConfig{Name: testSslPolicy},
},
},
},
},
HTTPRoutes: map[types.NamespacedName]intermediate.HTTPRouteContext{
{Namespace: testNamespace, Name: testHTTPRouteName}: {
HTTPRoute: testHTTPRoute,
},
},
},
expectedGatewayResources: i2gw.GatewayResources{
Gateways: map[types.NamespacedName]gatewayv1.Gateway{
{Namespace: testNamespace, Name: testGatewayName}: testGateway,
},
HTTPRoutes: map[types.NamespacedName]gatewayv1.HTTPRoute{
{Namespace: testNamespace, Name: testHTTPRouteName}: testHTTPRoute,
},
GatewayExtensions: []unstructured.Unstructured{
*testSslGCPGatewayPolicyUnstructured,
},
},
expectedErrors: field.ErrorList{},
},
}

for _, tc := range testCases {
Expand Down
8 changes: 6 additions & 2 deletions pkg/i2gw/providers/gce/gce.go
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@ import (
"github.com/kubernetes-sigs/ingress2gateway/pkg/i2gw/notifications"
"k8s.io/apimachinery/pkg/util/validation/field"
backendconfigv1 "k8s.io/ingress-gce/pkg/apis/backendconfig/v1"
frontendconfigv1beta1 "k8s.io/ingress-gce/pkg/apis/frontendconfig/v1beta1"
)

const ProviderName = "gce"
Expand All @@ -42,12 +43,15 @@ type Provider struct {
}

func NewProvider(conf *i2gw.ProviderConf) i2gw.Provider {
// Add BackendConfig to Schema when reading in-cluster so these resources
// can be recognized.
// Add BackendConfig and FrontendConfig to Schema when reading in-cluster
// so these resources can be recognized.
if conf.Client != nil {
if err := backendconfigv1.AddToScheme(conf.Client.Scheme()); err != nil {
notify(notifications.ErrorNotification, "Failed to add v1 BackendConfig Scheme")
}
if err := frontendconfigv1beta1.AddToScheme(conf.Client.Scheme()); err != nil {
notify(notifications.ErrorNotification, "Failed to add v1beta1 FrontendConfig Scheme")
}
}
return &Provider{
storage: newResourcesStorage(),
Expand Down
62 changes: 62 additions & 0 deletions pkg/i2gw/providers/gce/ir_converter.go
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,7 @@ import (
"k8s.io/apimachinery/pkg/types"
"k8s.io/apimachinery/pkg/util/validation/field"
backendconfigv1 "k8s.io/ingress-gce/pkg/apis/backendconfig/v1"
frontendconfigv1beta1 "k8s.io/ingress-gce/pkg/apis/frontendconfig/v1beta1"
)

type contextKey int
Expand Down Expand Up @@ -82,10 +83,71 @@ func (c *resourcesToIRConverter) convertToIR(storage *storage) (intermediate.IR,
if len(errs) > 0 {
return intermediate.IR{}, errs
}
buildGceGatewayIR(c.ctx, storage, &ir)
buildGceServiceIR(c.ctx, storage, &ir)
return ir, errs
}

func buildGceGatewayIR(ctx context.Context, storage *storage, ir *intermediate.IR) {
if ir.Gateways == nil {
ir.Gateways = make(map[types.NamespacedName]intermediate.GatewayContext)
}

feConfigToGwys := getFrontendConfigMapping(ctx, storage)
for feConfigKey, feConfig := range storage.FrontendConfigs {
if feConfig == nil {
continue
}
gceGatewayIR := feConfigToGceGatewayIR(feConfig)
gateways := feConfigToGwys[feConfigKey]

for _, gwyKey := range gateways {
gatewayContext := ir.Gateways[gwyKey]
gatewayContext.ProviderSpecificIR.Gce = &gceGatewayIR
ir.Gateways[gwyKey] = gatewayContext
}
}
}

type gatewayNames []types.NamespacedName

func getFrontendConfigMapping(ctx context.Context, storage *storage) map[types.NamespacedName]gatewayNames {
feConfigToGwys := make(map[types.NamespacedName]gatewayNames)

for _, ingress := range storage.Ingresses {
gwyKey := types.NamespacedName{Namespace: ingress.Namespace, Name: common.GetIngressClass(*ingress)}
// ing := types.NamespacedName{Namespace: ingress.Namespace, Name: ingress.Name}
ctx = context.WithValue(ctx, serviceKey, ingress)

feConfigName, exists := getFrontendConfigAnnotation(ingress)
if exists {
feConfigKey := types.NamespacedName{Namespace: ingress.Namespace, Name: feConfigName}
feConfigToGwys[feConfigKey] = append(feConfigToGwys[feConfigKey], gwyKey)
continue
}

}
return feConfigToGwys
}

// Get names of the FrontendConfig in the cluster based on the FrontendConfig
// annotation on k8s Services.
func getFrontendConfigAnnotation(ing *networkingv1.Ingress) (string, bool) {
val, ok := ing.ObjectMeta.Annotations[frontendConfigKey]
if !ok {
return "", false
}
return val, true
}

func feConfigToGceGatewayIR(feConfig *frontendconfigv1beta1.FrontendConfig) intermediate.GceGatewayIR {
var gceGatewayIR intermediate.GceGatewayIR
if feConfig.Spec.SslPolicy != nil {
gceGatewayIR.SslPolicy = extensions.BuildIRSslPolicyConfig(feConfig)
}
return gceGatewayIR
}

type serviceNames []types.NamespacedName

func buildGceServiceIR(ctx context.Context, storage *storage, ir *intermediate.IR) {
Expand Down
Loading

0 comments on commit 3ec528d

Please sign in to comment.