Skip to content

Commit

Permalink
Added WAF Support
Browse files Browse the repository at this point in the history
  • Loading branch information
Inbaraj-S committed Aug 7, 2023
1 parent 63eafa8 commit 130dc2b
Show file tree
Hide file tree
Showing 101 changed files with 11,199 additions and 51 deletions.
47 changes: 26 additions & 21 deletions pkg/controllers/ingressclass/ingressclass.go
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,7 @@ import (
"github.com/oracle/oci-native-ingress-controller/api/v1beta1"
"github.com/oracle/oci-native-ingress-controller/pkg/loadbalancer"
"github.com/oracle/oci-native-ingress-controller/pkg/util"
"github.com/oracle/oci-native-ingress-controller/pkg/waf"

"github.com/oracle/oci-go-sdk/v65/common"
ociloadbalancer "github.com/oracle/oci-go-sdk/v65/loadbalancer"
Expand All @@ -60,20 +61,12 @@ type Controller struct {
client kubernetes.Interface
cache ctrcache.Cache

lbClient *loadbalancer.LoadBalancerClient
lbClient *loadbalancer.LoadBalancerClient
wafClient *waf.Client
}

// NewController creates a new Controller.
func NewController(
defaultCompartmentId string,
defaultSubnetId string,
controllerClass string,
informer networkinginformers.IngressClassInformer,
client kubernetes.Interface,
lbClient *loadbalancer.LoadBalancerClient,
ctrcache ctrcache.Cache,

) *Controller {
func NewController(defaultCompartmentId string, defaultSubnetId string, controllerClass string, informer networkinginformers.IngressClassInformer, client kubernetes.Interface, lbClient *loadbalancer.LoadBalancerClient, wafClient *waf.Client, ctrcache ctrcache.Cache) *Controller {

c := &Controller{
defaultCompartmentId: defaultCompartmentId,
Expand All @@ -83,6 +76,7 @@ func NewController(
lister: informer.Lister(),
client: client,
lbClient: lbClient,
wafClient: wafClient,
cache: ctrcache,
queue: workqueue.NewRateLimitingQueue(workqueue.NewItemExponentialFailureRateLimiter(10*time.Second, 5*time.Minute)),
}
Expand Down Expand Up @@ -283,25 +277,36 @@ func (c *Controller) ensureLoadBalancer(ic *networkingv1.IngressClass) error {

if *lb.Id != util.GetIngressClassLoadBalancerId(ic) {
klog.InfoS("Adding load balancer id to ingress class", "lbId", *lb.Id, "ingressClass", klog.KObj(ic))

patchBytes := []byte(fmt.Sprintf(`{"metadata":{"annotations":{"%s":"%s"}}}`, util.IngressClassLoadBalancerIdAnnotation, *lb.Id))

err := retry.RetryOnConflict(retry.DefaultBackoff, func() error {
_, err := c.client.NetworkingV1().IngressClasses().Patch(context.TODO(), ic.Name, types.StrategicMergePatchType, patchBytes, metav1.PatchOptions{})
return err
})

if apierrors.IsConflict(err) {
return errors.Wrapf(err, "updateMaxRetries(%d) limit was reached while attempting to add load balancer id annotation", retry.DefaultBackoff.Steps)
patchError, done := util.PatchIngressClassWithAnnotation(c.client, ic, util.IngressClassLoadBalancerIdAnnotation, *lb.Id)
if done {
return patchError
}
}

// Add Web Application Firewall to LB
if c.wafClient != nil {
err = c.setupWebApplicationFirewall(ic, icp, lb)
if err != nil {
return err
}
}

klog.V(4).InfoS("checking if updates are required for load balancer", "ingressClass", klog.KObj(ic))
return nil
}

func (c *Controller) setupWebApplicationFirewall(ic *networkingv1.IngressClass, icp *v1beta1.IngressClassParameters, lb *ociloadbalancer.LoadBalancer) error {
firewall, err, err2, done := c.wafClient.GetFireWallId(c.client, ic, icp, lb, c.defaultCompartmentId)
if done {
return err2
}
// update to ingressclass
if err == nil && firewall.GetId() != nil {
patchError, done := util.PatchIngressClassWithAnnotation(c.client, ic, util.IngressClassFireWallIdAnnotation, *firewall.GetId())
if done {
return patchError
}
}
return nil
}

Expand Down
3 changes: 1 addition & 2 deletions pkg/controllers/ingressclass/ingressclass_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -129,8 +129,7 @@ func inits(ctx context.Context, ingressClassList *networkingv1.IngressClassList)
}

ingressClassInformer, client := setUp(ctx, ingressClassList)
c := NewController("", "",
"oci.oraclecloud.com/native-ingress-controller", ingressClassInformer, client, loadBalancerClient, nil)
c := NewController("", "", "oci.oraclecloud.com/native-ingress-controller", ingressClassInformer, client, loadBalancerClient, nil, nil)
return c
}

Expand Down
29 changes: 3 additions & 26 deletions pkg/controllers/routingpolicy/routingpolicy.go
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,6 @@
* * Licensed under the Universal Permissive License v 1.0 as shown at https://oss.oracle.com/licenses/upl/
*
*/

package routingpolicy

import (
Expand Down Expand Up @@ -162,24 +161,9 @@ func (c *Controller) ensureRoutingRules(ingressClass *networkingv1.IngressClass)
listenerPaths := map[string][]*listenerPath{}
desiredRoutingPolicies := sets.NewString()

for _, ingress := range ingresses {
for _, rule := range ingress.Spec.Rules {
for _, path := range rule.HTTP.Paths {
serviceName, servicePort, err := util.PathToServiceAndPort(ingress.Namespace, path, c.serviceLister)
if err != nil {
return err
}

listenerName := util.GenerateListenerName(servicePort)
listenerPaths[listenerName] = append(listenerPaths[listenerName], &listenerPath{
IngressName: ingress.Name,
Host: rule.Host,
Path: &path,
BackendSetName: util.GenerateBackendSetName(ingress.Namespace, serviceName, servicePort),
})
desiredRoutingPolicies.Insert(listenerName)
}
}
err = processRoutingPolicy(ingresses, c.serviceLister, listenerPaths, desiredRoutingPolicies)
if err != nil {
return err
}

lbID := util.GetIngressClassLoadBalancerId(ingressClass)
Expand Down Expand Up @@ -263,13 +247,6 @@ func (c *Controller) ensureRoutingRules(ingressClass *networkingv1.IngressClass)
return nil
}

type listenerPath struct {
IngressName string
Host string
BackendSetName string
Path *networkingv1.HTTPIngressPath
}

// handleErr checks if an error happened and makes sure we will retry later.
func (c *Controller) handleErr(err error, key interface{}) {
if err == nil {
Expand Down
88 changes: 88 additions & 0 deletions pkg/controllers/routingpolicy/routingpolicy_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,8 @@ import (
"github.com/oracle/oci-native-ingress-controller/pkg/util"
corev1 "k8s.io/api/core/v1"
networkingv1 "k8s.io/api/networking/v1"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"k8s.io/apimachinery/pkg/util/sets"
"k8s.io/client-go/informers"
networkinginformers "k8s.io/client-go/informers/networking/v1"
fakeclientset "k8s.io/client-go/kubernetes/fake"
Expand All @@ -30,6 +32,92 @@ func TestEnsureRoutingRules(t *testing.T) {
err := c.ensureRoutingRules(&ingressClassList.Items[0])
Expect(err == nil).Should(Equal(true))
}
func TestProcessRoutingPolicy(t *testing.T) {
RegisterTestingT(t)
ctx, cancel := context.WithCancel(context.Background())
defer cancel()
ingressClassList := util.GetIngressClassList()
c := inits(ctx, ingressClassList, "routePath.yaml")

listenerPaths := map[string][]*listenerPath{}
desiredRoutingPolicies := sets.NewString()

var ingresses []*networkingv1.Ingress

var rules []networkingv1.IngressRule

var httpIngressPath []networkingv1.HTTPIngressPath
prefix := networkingv1.PathTypePrefix
backend1 := networkingv1.IngressServiceBackend{
Name: "nsacs-healthcheck-ui",
Port: networkingv1.ServiceBackendPort{
Number: 8000,
},
}
backend2 := networkingv1.IngressServiceBackend{
Name: "nsacs-auth-service",
Port: networkingv1.ServiceBackendPort{
Number: 3005,
},
}
backend3 := networkingv1.IngressServiceBackend{
Name: "nsacs-healthcheck-data",
Port: networkingv1.ServiceBackendPort{
Number: 3010,
},
}
path1 := networkingv1.HTTPIngressPath{
Path: "/ui",
PathType: &prefix,
Backend: networkingv1.IngressBackend{
Service: &backend1,
Resource: nil,
},
}
path2 := networkingv1.HTTPIngressPath{
Path: "/auth",
PathType: &prefix,
Backend: networkingv1.IngressBackend{
Service: &backend2,
Resource: nil,
},
}
path3 := networkingv1.HTTPIngressPath{
Path: "/data",
PathType: &prefix,
Backend: networkingv1.IngressBackend{
Service: &backend3,
Resource: nil,
},
}
httpIngressPath = append(httpIngressPath, path1)
httpIngressPath = append(httpIngressPath, path2)
httpIngressPath = append(httpIngressPath, path3)
rule := networkingv1.IngressRule{
Host: "",
IngressRuleValue: networkingv1.IngressRuleValue{
HTTP: &networkingv1.HTTPIngressRuleValue{
Paths: httpIngressPath,
},
},
}
rules = append(rules, rule)

ingress := networkingv1.Ingress{
TypeMeta: metav1.TypeMeta{},
ObjectMeta: metav1.ObjectMeta{},
Spec: networkingv1.IngressSpec{
Rules: rules,
},
Status: networkingv1.IngressStatus{},
}
ingresses = append(ingresses, &ingress)

err := processRoutingPolicy(ingresses, c.serviceLister, listenerPaths, desiredRoutingPolicies)
Expect(err == nil).Should(Equal(true))
Expect(len(listenerPaths)).Should(Equal(3))
Expect(len(desiredRoutingPolicies)).Should(Equal(3))
}

func TestRunPusher(t *testing.T) {
RegisterTestingT(t)
Expand Down
32 changes: 32 additions & 0 deletions pkg/controllers/routingpolicy/util.go
Original file line number Diff line number Diff line change
Expand Up @@ -13,9 +13,19 @@ import (
"fmt"
"strings"

"github.com/oracle/oci-native-ingress-controller/pkg/util"
networkingv1 "k8s.io/api/networking/v1"
"k8s.io/apimachinery/pkg/util/sets"
corelisters "k8s.io/client-go/listers/core/v1"
)

type listenerPath struct {
IngressName string
Host string
BackendSetName string
Path *networkingv1.HTTPIngressPath
}

type ByPath []*listenerPath

func (pathArray ByPath) Len() int { return len(pathArray) }
Expand Down Expand Up @@ -61,3 +71,25 @@ func PathToRoutePolicyCondition(host string, path networkingv1.HTTPIngressPath)

return fmt.Sprintf("all(%s , %s)", conditions[0], conditions[1])
}

func processRoutingPolicy(ingresses []*networkingv1.Ingress, serviceLister corelisters.ServiceLister, listenerPaths map[string][]*listenerPath, desiredRoutingPolicies sets.String) error {
for _, ingress := range ingresses {
for _, rule := range ingress.Spec.Rules {
for _, path := range rule.HTTP.Paths {
serviceName, servicePort, err := util.PathToServiceAndPort(ingress.Namespace, path, serviceLister)
if err != nil {
return err
}
listenerName := util.GenerateListenerName(servicePort)
listenerPaths[listenerName] = append(listenerPaths[listenerName], &listenerPath{
IngressName: ingress.Name,
Host: rule.Host,
Path: &path,
BackendSetName: util.GenerateBackendSetName(ingress.Namespace, serviceName, servicePort),
})
desiredRoutingPolicies.Insert(listenerName)
}
}
}
return nil
}
35 changes: 35 additions & 0 deletions pkg/oci/client/waf.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
package client

import (
"context"

"github.com/oracle/oci-go-sdk/v65/waf"
)

type WafInterface interface {
GetWebAppFirewall(ctx context.Context, request waf.GetWebAppFirewallRequest) (response waf.GetWebAppFirewallResponse, err error)
CreateWebAppFirewall(ctx context.Context, request waf.CreateWebAppFirewallRequest) (response waf.CreateWebAppFirewallResponse, err error)
DeleteWebAppFirewall(ctx context.Context, request waf.DeleteWebAppFirewallRequest) (response waf.DeleteWebAppFirewallResponse, err error)
}

type WAFClient struct {
wafClient *waf.WafClient
}

func NewWafClient(wafClient *waf.WafClient) WAFClient {
return WAFClient{
wafClient: wafClient,
}
}

func (W WAFClient) GetWebAppFirewall(ctx context.Context, request waf.GetWebAppFirewallRequest) (response waf.GetWebAppFirewallResponse, err error) {
return W.wafClient.GetWebAppFirewall(ctx, request)
}

func (W WAFClient) CreateWebAppFirewall(ctx context.Context, request waf.CreateWebAppFirewallRequest) (response waf.CreateWebAppFirewallResponse, err error) {
return W.wafClient.CreateWebAppFirewall(ctx, request)
}

func (W WAFClient) DeleteWebAppFirewall(ctx context.Context, request waf.DeleteWebAppFirewallRequest) (response waf.DeleteWebAppFirewallResponse, err error) {
return W.wafClient.DeleteWebAppFirewall(ctx, request)
}
10 changes: 10 additions & 0 deletions pkg/server/server.go
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ import (
ctrcache "sigs.k8s.io/controller-runtime/pkg/cache"
"sigs.k8s.io/controller-runtime/pkg/webhook"

ociwaf "github.com/oracle/oci-go-sdk/v65/waf"
"k8s.io/client-go/kubernetes"

"github.com/oracle/oci-go-sdk/v65/certificates"
Expand All @@ -34,6 +35,7 @@ import (
"github.com/oracle/oci-native-ingress-controller/pkg/metric"
. "github.com/oracle/oci-native-ingress-controller/pkg/oci/client"
"github.com/oracle/oci-native-ingress-controller/pkg/types"
w "github.com/oracle/oci-native-ingress-controller/pkg/waf"
"github.com/prometheus/client_golang/prometheus"

v1 "k8s.io/client-go/informers/core/v1"
Expand Down Expand Up @@ -88,10 +90,17 @@ func SetUpControllers(opts types.IngressOpts, ingressClassInformer networkinginf
klog.Fatalf("unable to construct oci certificate management client: %v", err)
}

ociWafClient, err := ociwaf.NewWafClientWithConfigurationProvider(configProvider)
if err != nil {
klog.Fatalf("unable to construct oci web application firewall client: %v", err)
}

lbClient := loadbalancer.New(&ociLBClient)

certificatesClient := certificate.New(&ociCertificatesMgmtClient, NewCertificateClient(&ociCertificatesClient))

wafClient := w.New(&ociWafClient)

ingressController := ingress.NewController(
opts.ControllerClass,
opts.CompartmentId,
Expand Down Expand Up @@ -131,6 +140,7 @@ func SetUpControllers(opts types.IngressOpts, ingressClassInformer networkinginf
ingressClassInformer,
client,
lbClient,
wafClient,
c,
)

Expand Down
Loading

0 comments on commit 130dc2b

Please sign in to comment.