Skip to content

Commit

Permalink
add support for readonlyrootfilesystem test for wafv5 (#6708)
Browse files Browse the repository at this point in the history
  • Loading branch information
vepatel authored Oct 31, 2024
1 parent 41d4920 commit b078841
Show file tree
Hide file tree
Showing 3 changed files with 294 additions and 42 deletions.
27 changes: 19 additions & 8 deletions tests/suite/fixtures/ic_fixtures.py
Original file line number Diff line number Diff line change
Expand Up @@ -289,14 +289,25 @@ def crd_ingress_controller_with_waf_v5(
ap_uds_crd_name,
f"{CRDS}/appprotect.f5.com_apusersigs.yaml",
)
name = create_ingress_controller_wafv5(
kube_apis.v1,
kube_apis.apps_v1_api,
cli_arguments,
namespace,
"regcred",
request.param.get("extra_args", None),
)
if request.param["type"] == "rorfs": # WAFv5 with readOnlyRootFileSystem
name = create_ingress_controller_wafv5(
kube_apis.v1,
kube_apis.apps_v1_api,
cli_arguments,
namespace,
"regcred",
request.param.get("extra_args", None),
True,
)
else:
name = create_ingress_controller_wafv5(
kube_apis.v1,
kube_apis.apps_v1_api,
cli_arguments,
namespace,
"regcred",
request.param.get("extra_args", None),
)
try:
with open(f"{dir}/wafv5.tgz", "rb") as f:
file_content = f.read()
Expand Down
163 changes: 163 additions & 0 deletions tests/suite/test_app_protect_wafv5_integration_rorfs.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,163 @@
import pytest
import requests
from settings import TEST_DATA
from suite.utils.policy_resources_utils import create_policy_from_yaml, delete_policy
from suite.utils.resources_utils import wait_before_test
from suite.utils.vs_vsr_resources_utils import (
create_virtual_server_from_yaml,
delete_virtual_server,
patch_v_s_route_from_yaml,
patch_virtual_server_from_yaml,
)


@pytest.fixture(scope="class")
def waf_setup(kube_apis, test_namespace) -> None:
waf = f"{TEST_DATA}/ap-waf-v5/policies/waf.yaml"
create_policy_from_yaml(kube_apis.custom_objects, waf, test_namespace)
wait_before_test()


@pytest.mark.skip_for_nginx_oss
@pytest.mark.appprotect_waf_v5
@pytest.mark.parametrize(
"crd_ingress_controller_with_waf_v5, virtual_server_setup",
[
(
{
"type": "rorfs",
"extra_args": [
f"-enable-app-protect",
],
},
{
"example": "ap-waf-v5",
"app_type": "simple",
},
),
],
indirect=True,
)
class TestAppProtectWAFv5IntegrationVSrorfs:
def restore_default_vs(self, kube_apis, virtual_server_setup) -> None:
"""
Restore VirtualServer without policy spec
"""
std_vs_src = f"{TEST_DATA}/ap-waf-v5/standard/virtual-server.yaml"
delete_virtual_server(kube_apis.custom_objects, virtual_server_setup.vs_name, virtual_server_setup.namespace)
create_virtual_server_from_yaml(kube_apis.custom_objects, std_vs_src, virtual_server_setup.namespace)
wait_before_test()

@pytest.mark.parametrize(
"vs_src",
[f"{TEST_DATA}/ap-waf-v5/virtual-server-waf-spec.yaml"],
)
def test_ap_waf_v5_policy_block_vs(
self,
kube_apis,
ingress_controller_prerequisites,
crd_ingress_controller_with_waf_v5,
test_namespace,
virtual_server_setup,
waf_setup,
vs_src,
):
patch_virtual_server_from_yaml(
kube_apis.custom_objects,
virtual_server_setup.vs_name,
vs_src,
virtual_server_setup.namespace,
)

print("----------------------- Send request with embedded malicious script----------------------")
count = 0
response = requests.get(
virtual_server_setup.backend_1_url + "</script>",
headers={"host": virtual_server_setup.vs_host},
)
while count < 5 and "Request Rejected" not in response.text:
response = requests.get(
virtual_server_setup.backend_1_url + "</script>",
headers={"host": virtual_server_setup.vs_host},
)
wait_before_test()
count += 1
self.restore_default_vs(kube_apis, virtual_server_setup)
assert response.status_code == 200
assert "The requested URL was rejected. Please consult with your administrator." in response.text


@pytest.mark.skip_for_nginx_oss
@pytest.mark.appprotect_waf_v5
@pytest.mark.parametrize(
"crd_ingress_controller_with_waf_v5, v_s_route_setup",
[
(
{
"type": "rorfs",
"extra_args": [
f"-enable-app-protect",
],
},
{
"example": "virtual-server-route",
},
)
],
indirect=True,
)
class TestAppProtectWAFv5IntegrationVSRrorfs:

def restore_default_vsr(self, kube_apis, v_s_route_setup) -> None:
"""
Function to revert vsr deployments to standard state
"""
patch_src_m = f"{TEST_DATA}/virtual-server-route/route-multiple.yaml"
patch_v_s_route_from_yaml(
kube_apis.custom_objects,
v_s_route_setup.route_m.name,
patch_src_m,
v_s_route_setup.route_m.namespace,
)
wait_before_test()

def test_ap_waf_v5_policy_block_vsr(
self,
kube_apis,
ingress_controller_prerequisites,
crd_ingress_controller_with_waf_v5,
test_namespace,
v_s_route_setup,
):
req_url = f"http://{v_s_route_setup.public_endpoint.public_ip}:{v_s_route_setup.public_endpoint.port}"
waf_subroute_vsr_src = f"{TEST_DATA}/ap-waf-v5/virtual-server-route-waf-subroute.yaml"
pol = create_policy_from_yaml(
kube_apis.custom_objects,
f"{TEST_DATA}/ap-waf-v5/policies/waf.yaml",
v_s_route_setup.route_m.namespace,
)
wait_before_test()
patch_v_s_route_from_yaml(
kube_apis.custom_objects,
v_s_route_setup.route_m.name,
waf_subroute_vsr_src,
v_s_route_setup.route_m.namespace,
)
wait_before_test()
print("----------------------- Send request with embedded malicious script----------------------")
count = 0
response = requests.get(
f'{req_url}{v_s_route_setup.route_m.paths[0]}+"</script>"',
headers={"host": v_s_route_setup.vs_host},
)
while count < 5 and "Request Rejected" not in response.text:
response = requests.get(
f'{req_url}{v_s_route_setup.route_m.paths[0]}+"</script>"',
headers={"host": v_s_route_setup.vs_host},
)
wait_before_test()
count += 1
self.restore_default_vsr(kube_apis, v_s_route_setup)
delete_policy(kube_apis.custom_objects, pol, v_s_route_setup.route_m.namespace)
assert response.status_code == 200
assert "The requested URL was rejected. Please consult with your administrator." in response.text
146 changes: 112 additions & 34 deletions tests/suite/utils/resources_utils.py
Original file line number Diff line number Diff line change
Expand Up @@ -1206,7 +1206,7 @@ def create_ingress_controller(v1: CoreV1Api, apps_v1_api: AppsV1Api, cli_argumen


def create_ingress_controller_wafv5(
v1: CoreV1Api, apps_v1_api: AppsV1Api, cli_arguments, namespace, reg_secret, args=None
v1: CoreV1Api, apps_v1_api: AppsV1Api, cli_arguments, namespace, reg_secret, args=None, rorfs=False
) -> str:
"""
Create an Ingress Controller according to the params.
Expand All @@ -1225,6 +1225,9 @@ def create_ingress_controller_wafv5(
dep["spec"]["replicas"] = int(cli_arguments["replicas"])
dep["spec"]["template"]["spec"]["containers"][0]["image"] = cli_arguments["image"]
dep["spec"]["template"]["spec"]["containers"][0]["imagePullPolicy"] = cli_arguments["image-pull-policy"]
if "readOnlyRootFilesystem" not in dep["spec"]["template"]["spec"]["containers"][0]["securityContext"]:
dep["spec"]["template"]["spec"]["containers"][0]["securityContext"]["readOnlyRootFilesystem"] = rorfs

template_spec = dep["spec"]["template"]["spec"]
if "imagePullSecrets" not in template_spec:
template_spec["imagePullSecrets"] = []
Expand All @@ -1233,43 +1236,109 @@ def create_ingress_controller_wafv5(
if "volumes" not in template_spec:
template_spec["volumes"] = []

template_spec["volumes"].extend(
[
{
"name": "app-protect-bd-config",
"emptyDir": {},
},
{
"name": "app-protect-config",
"emptyDir": {},
},
{
"name": "app-protect-bundles",
"emptyDir": {},
},
]
)
if rorfs and "initContainers" not in template_spec:
template_spec["initContainers"] = []
template_spec["initContainers"].extend(
[
{
"name": "init-nginx-ingress",
"image": cli_arguments["image"],
"imagePullPolicy": "IfNotPresent",
"command": ["cp", "-vdR", "/etc/nginx/.", "/mnt/etc"],
"securityContext": {
"allowPrivilegeEscalation": False,
"readOnlyRootFilesystem": True,
"runAsUser": 101, # nginx
"runAsNonRoot": True,
"capabilities": {"drop": ["ALL"]},
},
"volumeMounts": [{"mountPath": "/mnt/etc", "name": "nginx-etc"}],
}
]
)

if rorfs:
template_spec["volumes"].extend(
[
{
"name": "app-protect-bd-config",
"emptyDir": {},
},
{
"name": "app-protect-config",
"emptyDir": {},
},
{
"name": "app-protect-bundles",
"emptyDir": {},
},
{"name": "nginx-etc", "emptyDir": {}},
{"name": "nginx-log", "emptyDir": {}},
{"name": "nginx-cache", "emptyDir": {}},
{"name": "nginx-lib", "emptyDir": {}},
]
)
else:
template_spec["volumes"].extend(
[
{
"name": "app-protect-bd-config",
"emptyDir": {},
},
{
"name": "app-protect-config",
"emptyDir": {},
},
{
"name": "app-protect-bundles",
"emptyDir": {},
},
]
)

container = dep["spec"]["template"]["spec"]["containers"][0]
if "volumeMounts" not in container:
container["volumeMounts"] = []

container["volumeMounts"].extend(
[
{
"name": "app-protect-bd-config",
"mountPath": "/opt/app_protect/bd_config",
},
{
"name": "app-protect-config",
"mountPath": "/opt/app_protect/config",
},
{
"name": "app-protect-bundles",
"mountPath": "/etc/app_protect/bundles",
},
]
)
if rorfs:
container["volumeMounts"].extend(
[
{
"name": "app-protect-bd-config",
"mountPath": "/opt/app_protect/bd_config",
},
{
"name": "app-protect-config",
"mountPath": "/opt/app_protect/config",
},
{
"name": "app-protect-bundles",
"mountPath": "/etc/app_protect/bundles",
},
{"name": "nginx-etc", "mountPath": "/etc/nginx"},
{"name": "nginx-log", "mountPath": "/var/log/nginx"},
{"name": "nginx-cache", "mountPath": "/var/cache/nginx"},
{"name": "nginx-lib", "mountPath": "/var/lib/nginx"},
]
)
else:
container["volumeMounts"].extend(
[
{
"name": "app-protect-bd-config",
"mountPath": "/opt/app_protect/bd_config",
},
{
"name": "app-protect-config",
"mountPath": "/opt/app_protect/config",
},
{
"name": "app-protect-bundles",
"mountPath": "/etc/app_protect/bundles",
},
]
)

dep["spec"]["template"]["spec"]["containers"][0]["args"].extend(
[
f"-default-server-tls-secret=$(POD_NAMESPACE)/default-server-secret",
Expand All @@ -1281,7 +1350,11 @@ def create_ingress_controller_wafv5(
"name": "waf-config-mgr",
"image": f"{NGX_REG}/nap/waf-config-mgr:{WAF_V5_VERSION}",
"imagePullPolicy": "IfNotPresent",
"securityContext": {"allowPrivilegeEscalation": False, "capabilities": {"drop": ["all"]}},
"securityContext": {
"allowPrivilegeEscalation": False,
"capabilities": {"drop": ["all"]},
"readOnlyRootFilesystem": rorfs,
},
"volumeMounts": [
{
"name": "app-protect-bd-config",
Expand All @@ -1301,6 +1374,11 @@ def create_ingress_controller_wafv5(
"name": "waf-enforcer",
"image": f"{NGX_REG}/nap/waf-enforcer:{WAF_V5_VERSION}",
"imagePullPolicy": "IfNotPresent",
"securityContext": {
"allowPrivilegeEscalation": False,
"capabilities": {"drop": ["all"]},
"readOnlyRootFilesystem": rorfs,
},
"env": [{"name": "ENFORCER_PORT", "value": "50000"}],
"volumeMounts": [
{
Expand Down

0 comments on commit b078841

Please sign in to comment.