From d64365df2b7c803b303fdd998156c36f3d0e7910 Mon Sep 17 00:00:00 2001 From: Arbaaz Khan Date: Fri, 5 Jan 2024 12:55:24 +0530 Subject: [PATCH] Add support for HTML profile in Policy CR and VS CR (#3221) --- config/apis/cis/v1/types.go | 2 ++ docs/RELEASE-NOTES.rst | 2 ++ .../customResource/CustomResource.md | 1 + .../Policy/policy-with-html-profile.yaml | 13 +++++++++++++ .../VirtualServer/htmlProfile/README.md | 14 ++++++++++++++ .../htmlProfile/vs-with-htmlProfile.yaml | 15 +++++++++++++++ .../incubator/customresourcedefinitions.yml | 6 ++++++ pkg/controller/backend.go | 5 +++++ pkg/controller/resourceConfig.go | 5 +++++ pkg/controller/types.go | 2 ++ pkg/controller/worker_test.go | 4 ++++ 11 files changed, 69 insertions(+) create mode 100644 docs/config_examples/customResource/Policy/policy-with-html-profile.yaml create mode 100644 docs/config_examples/customResource/VirtualServer/htmlProfile/README.md create mode 100644 docs/config_examples/customResource/VirtualServer/htmlProfile/vs-with-htmlProfile.yaml diff --git a/config/apis/cis/v1/types.go b/config/apis/cis/v1/types.go index a7ea8f7bc..91eafd0e9 100644 --- a/config/apis/cis/v1/types.go +++ b/config/apis/cis/v1/types.go @@ -55,6 +55,7 @@ type VirtualServerSpec struct { AllowSourceRange []string `json:"allowSourceRange,omitempty"` HttpMrfRoutingEnabled *bool `json:"httpMrfRoutingEnabled,omitempty"` Partition string `json:"partition,omitempty"` + HTMLProfile string `json:"htmlProfile,omitempty"` } // ServiceAddress Service IP address definition (BIG-IP virtual-address). @@ -406,6 +407,7 @@ type ProfileSpec struct { SSLProfiles SSLProfiles `json:"sslProfiles,omitempty"` AnalyticsProfiles AnalyticsProfiles `json:"analyticsProfiles,omitempty"` ProfileWebSocket string `json:"profileWebSocket,omitempty"` + HTMLProfile string `json:"htmlProfile,omitempty"` } type ProfileVSSpec struct { diff --git a/docs/RELEASE-NOTES.rst b/docs/RELEASE-NOTES.rst index 0856ab8a3..523afa3bc 100644 --- a/docs/RELEASE-NOTES.rst +++ b/docs/RELEASE-NOTES.rst @@ -7,6 +7,8 @@ Added Functionality ``````````````````` **What's new:** * Improved Operator support for OpenShift 4.14 + * CRD + * Support for HTML profile in Policy CR and VirtualServer CR. See `Example ` Bug Fixes ```````````` diff --git a/docs/config_examples/customResource/CustomResource.md b/docs/config_examples/customResource/CustomResource.md index 7f65b718b..337addc88 100644 --- a/docs/config_examples/customResource/CustomResource.md +++ b/docs/config_examples/customResource/CustomResource.md @@ -65,6 +65,7 @@ This page is created to document the behaviour of CIS in CRD Mode. | allowVlans | List of Vlans | Optional | NA | list of Vlan objects to allow traffic from | | hostGroup | String | Optional | NA | Label to group virtualservers with different host names into one in BIG-IP. | | persistenceProfile | String | Optional | cookie | CIS uses the AS3 default persistence profile. VirtualServer CRD resource takes precedence over Policy CRD. Allowed values are existing BIG-IP Persistence profiles. | +| htmlProfile | String | Optional | NA | Pathname of existing BIG-IP HTML profile. VirtualServer CRD resource takes precedence over Policy CRD. Allowed values are existing BIG-IP HTML profiles. | | dos | String | Optional | NA | Pathname of existing BIG-IP DoS policy. | | botDefense | String | Optional | NA | Pathname of existing BIG-IP botDefense policy. | | profileMultiplex | String | Optional | NA | CIS uses the AS3 default profileMultiplex profile. Allowed values are existing BIG-IP profileMultiplex profiles. | diff --git a/docs/config_examples/customResource/Policy/policy-with-html-profile.yaml b/docs/config_examples/customResource/Policy/policy-with-html-profile.yaml new file mode 100644 index 000000000..0b1d43d2a --- /dev/null +++ b/docs/config_examples/customResource/Policy/policy-with-html-profile.yaml @@ -0,0 +1,13 @@ +apiVersion: cis.f5.com/v1 +kind: Policy +metadata: + labels: + f5cr: "true" + name: cr-policy1 + namespace: test +spec: + iRules: {} + l3Policies: {} + l7Policies: {} + profiles: + htmlProfile: /Common/html \ No newline at end of file diff --git a/docs/config_examples/customResource/VirtualServer/htmlProfile/README.md b/docs/config_examples/customResource/VirtualServer/htmlProfile/README.md new file mode 100644 index 000000000..4970be09c --- /dev/null +++ b/docs/config_examples/customResource/VirtualServer/htmlProfile/README.md @@ -0,0 +1,14 @@ +# Virtual Server with Persistence Profile + +This section demonstrates the option to configure HTML Profile in virtual server. + +Option which can use to refer HTML Profile: + +``` +#Example +htmlProfile: /Common/html +``` + +## vs-with-htmlProfile.yaml + +By deploying this yaml file in your cluster, CIS will create a Virtual Server containing HTML Profile on BIG-IP. diff --git a/docs/config_examples/customResource/VirtualServer/htmlProfile/vs-with-htmlProfile.yaml b/docs/config_examples/customResource/VirtualServer/htmlProfile/vs-with-htmlProfile.yaml new file mode 100644 index 000000000..dc8388071 --- /dev/null +++ b/docs/config_examples/customResource/VirtualServer/htmlProfile/vs-with-htmlProfile.yaml @@ -0,0 +1,15 @@ +apiVersion: "cis.f5.com/v1" +kind: VirtualServer +metadata: + name: my-new-virtual-server + labels: + f5cr: "true" +spec: + host: cafe.example.com + virtualServerAddress: "172.16.3.4" + # htmlProfile can be used to modify HTML content sent in responses from the back-end servers + htmlProfile: /Common/html + pools: + - path: /coffee + service: svc-1 + servicePort: 80 diff --git a/docs/config_examples/customResourceDefinitions/incubator/customresourcedefinitions.yml b/docs/config_examples/customResourceDefinitions/incubator/customresourcedefinitions.yml index 0feefad24..b180882b1 100644 --- a/docs/config_examples/customResourceDefinitions/incubator/customresourcedefinitions.yml +++ b/docs/config_examples/customResourceDefinitions/incubator/customresourcedefinitions.yml @@ -50,6 +50,9 @@ spec: persistenceProfile: type: string pattern: '^\/?[a-zA-Z]+([-A-z0-9_+]+\/)*([-A-z0-9_.:]+\/?)*$' + htmlProfile: + type: string + pattern: '^\/[a-zA-Z]+([A-z0-9-_+]+\/)+([-A-z0-9_.:]+\/?)*$' profiles: type: object properties: @@ -1049,6 +1052,9 @@ spec: http: type: string pattern: '^\/[a-zA-Z]+([A-z0-9-_+]+\/)+([-A-z0-9_.:]+\/?)*$' + htmlProfile: + type: string + pattern: '^\/[a-zA-Z]+([A-z0-9-_+]+\/)+([-A-z0-9_.:]+\/?)*$' autoLastHop: type: string enum: [ default, auto, disable ] diff --git a/pkg/controller/backend.go b/pkg/controller/backend.go index 098eae713..b12ac6e03 100644 --- a/pkg/controller/backend.go +++ b/pkg/controller/backend.go @@ -974,6 +974,11 @@ func createServiceDecl(cfg *ResourceConfig, sharedApp as3Application, tenant str BigIP: cfg.Virtual.ProfileBotDefense, } } + if len(cfg.Virtual.HTMLProfile) > 0 { + svc.ProfileHTML = &as3ResourcePointer{ + BigIP: cfg.Virtual.HTMLProfile, + } + } if cfg.MetaData.Protocol == "https" { if len(cfg.Virtual.HTTP2.Client) > 0 || len(cfg.Virtual.HTTP2.Server) > 0 { diff --git a/pkg/controller/resourceConfig.go b/pkg/controller/resourceConfig.go index ee9641b9a..ace0c35ee 100644 --- a/pkg/controller/resourceConfig.go +++ b/pkg/controller/resourceConfig.go @@ -697,6 +697,10 @@ func (ctlr *Controller) prepareRSConfigFromVirtualServer( rsCfg.Virtual.PersistenceProfile = vs.Spec.PersistenceProfile } + if vs.Spec.HTMLProfile != "" { + rsCfg.Virtual.HTMLProfile = vs.Spec.HTMLProfile + } + if len(vs.Spec.Profiles.TCP.Client) > 0 || len(vs.Spec.Profiles.TCP.Server) > 0 { rsCfg.Virtual.TCP.Client = vs.Spec.Profiles.TCP.Client rsCfg.Virtual.TCP.Server = vs.Spec.Profiles.TCP.Server @@ -2183,6 +2187,7 @@ func (ctlr *Controller) handleVSResourceConfigForPolicy( rsCfg.Virtual.WAF = plc.Spec.L7Policies.WAF rsCfg.Virtual.Firewall = plc.Spec.L3Policies.FirewallPolicy rsCfg.Virtual.PersistenceProfile = plc.Spec.Profiles.PersistenceProfile + rsCfg.Virtual.HTMLProfile = plc.Spec.Profiles.HTMLProfile if ctlr.PoolMemberType == Cluster { rsCfg.Virtual.MultiPoolPersistence.Method = plc.Spec.PoolSettings.MultiPoolPersistence.Method rsCfg.Virtual.MultiPoolPersistence.TimeOut = plc.Spec.PoolSettings.MultiPoolPersistence.TimeOut diff --git a/pkg/controller/types.go b/pkg/controller/types.go index 7c7322673..0371fabfd 100644 --- a/pkg/controller/types.go +++ b/pkg/controller/types.go @@ -243,6 +243,7 @@ type ( AutoLastHop string `json:"lastHop,omitempty"` AnalyticsProfiles AnalyticsProfiles `json:"analyticsProfiles,omitempty"` MultiPoolPersistence MultiPoolPersistence `json:"multiPoolPersistence,omitempty"` + HTMLProfile string `json:"htmlProfile,omitempty"` } MultiPoolPersistence struct { Method string `json:"method,omitempty"` @@ -1022,6 +1023,7 @@ type ( IpIntelligencePolicy as3MultiTypeParam `json:"ipIntelligencePolicy,omitempty"` HttpAnalyticsProfile *as3ResourcePointer `json:"profileAnalytics,omitempty"` ProfileWebSocket as3MultiTypeParam `json:"profileWebSocket,omitempty"` + ProfileHTML as3MultiTypeParam `json:"profileHTML,omitempty"` } // as3ServiceAddress maps to VirtualAddress in AS3 Resources diff --git a/pkg/controller/worker_test.go b/pkg/controller/worker_test.go index 943a3bad8..3235e614e 100644 --- a/pkg/controller/worker_test.go +++ b/pkg/controller/worker_test.go @@ -1126,6 +1126,7 @@ var _ = Describe("Worker Tests", func() { }, ProfileL4: "/Common/security-fastL4", PersistenceProfile: "source-address", + HTMLProfile: "/Common/html", LogProfiles: []string{"/Common/local-dos"}, }, }, @@ -1597,6 +1598,7 @@ var _ = Describe("Worker Tests", func() { WAF: "/Common/WAF", IRules: []string{"/Common/SampleIRule"}, PersistenceProfile: "source-address", + HTMLProfile: "/Common/htmlProfile", AllowVLANs: []string{"/Common/devtraffic"}, Profiles: cisapiv1.ProfileVSSpec{ TCP: cisapiv1.ProfileTCP{ @@ -1747,6 +1749,8 @@ var _ = Describe("Worker Tests", func() { Expect(len(mockCtlr.resources.ltmConfig[mockCtlr.Partition].ResourceMap[rsname].Virtual.IRules)).To(Equal(4), "irules not propely attached") //check websocket profile Expect(mockCtlr.resources.ltmConfig[mockCtlr.Partition].ResourceMap[rsname].Virtual.ProfileWebSocket).To(Equal("/Common/websocket")) + //check websocket profile + Expect(mockCtlr.resources.ltmConfig[mockCtlr.Partition].ResourceMap[rsname].Virtual.HTMLProfile).To(Equal("/Common/htmlProfile")) for _, rule := range mockCtlr.resources.ltmConfig[mockCtlr.Partition].ResourceMap[rsname].Policies[0].Rules { if rule.Name == "vs_test_com_foo_svc1_80_default_test_com" { Expect(len(rule.Actions)).To(Equal(3))