Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Support new directive for dos: app_protect_dos_arb_fqdn #2745

Merged
merged 1 commit into from
Aug 24, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -188,4 +188,5 @@ See the doc about [VirtualServer and VirtualServerRoute resources](/nginx-ingres
|`app-protect-reconnect-period-seconds` | Sets the `app_protect_reconnect_period_seconds` [global directive](/nginx-app-protect/configuration/#global-directives). | `5` | |
|``app-protect-dos-log-format`` | Sets the custom [log format](https://nginx.org/en/docs/http/ngx_http_log_module.html#log_format) for Dos Access log traffic. For convenience, it is possible to define the log format across multiple lines (each line separated by ``\n``). In that case, the Ingress Controller will replace every ``\n`` character with a space character. All ``'`` characters must be escaped. | `, vs_name_al=$app_protect_dos_vs_name, ip=$remote_addr, tls_fp=$app_protect_dos_tls_fp, outcome=$app_protect_dos_outcome, reason=$app_protect_dos_outcome_reason, policy_name=$app_protect_dos_policy_name, dos_version=$app_protect_dos_version, ip_tls=$remote_addr:$app_protect_dos_tls_fp,` | |
|``app-protect-dos-log-format-escaping`` | Sets the characters escaping for the variables of the stream log format. Supported values: ``json`` (JSON escaping), ``default`` (the default escaping) ``none`` (disables escaping). | ``default`` | |
|``app-protect-dos-arb-fqdn`` | Sets the ``app-protect-dos-arb-fqdn`` [directive](/nginx-app-protect-dos/directives-and-policy/learn-about-directives-and-policy/#arbitrator-fqdn-directive-app_protect_dos_arb_fqdn). | ``svc-appprotect-dos-arb`` | |
{{% /table %}}
1 change: 1 addition & 0 deletions internal/configs/config_params.go
Original file line number Diff line number Diff line change
Expand Up @@ -57,6 +57,7 @@ type ConfigParams struct {
AppProtectDosResource string
MainAppProtectDosLogFormat []string
MainAppProtectDosLogFormatEscaping string
MainAppProtectDosArbFqdn string
ProxyBuffering bool
ProxyBuffers string
ProxyBufferSize string
Expand Down
8 changes: 8 additions & 0 deletions internal/configs/configmaps.go
Original file line number Diff line number Diff line change
Expand Up @@ -524,6 +524,13 @@ func ParseConfigMap(cfgm *v1.ConfigMap, nginxPlus bool, hasAppProtect bool, hasA
cfgParams.MainAppProtectDosLogFormatEscaping = appProtectDosLogFormatEscaping
}
}

if appProtectDosArbFqdn, exists := cfgm.Data["app-protect-dos-arb-fqdn"]; exists {
appProtectDosArbFqdn = strings.TrimSpace(appProtectDosArbFqdn)
if appProtectDosArbFqdn != "" {
cfgParams.MainAppProtectDosArbFqdn = appProtectDosArbFqdn
}
}
}

return cfgParams
Expand Down Expand Up @@ -590,6 +597,7 @@ func GenerateNginxMainConfig(staticCfgParams *StaticConfigParams, config *Config
AppProtectReconnectPeriod: config.MainAppProtectReconnectPeriod,
AppProtectDosLogFormat: config.MainAppProtectDosLogFormat,
AppProtectDosLogFormatEscaping: config.MainAppProtectDosLogFormatEscaping,
AppProtectDosArbFqdn: config.MainAppProtectDosArbFqdn,
InternalRouteServer: staticCfgParams.EnableInternalRoutes,
InternalRouteServerName: staticCfgParams.InternalRouteServerName,
LatencyMetrics: staticCfgParams.EnableLatencyMetrics,
Expand Down
1 change: 1 addition & 0 deletions internal/configs/version1/config.go
Original file line number Diff line number Diff line change
Expand Up @@ -217,6 +217,7 @@ type MainConfig struct {
AppProtectDosLoadModule bool
AppProtectDosLogFormat []string
AppProtectDosLogFormatEscaping string
AppProtectDosArbFqdn string
InternalRouteServer bool
InternalRouteServerName string
LatencyMetrics bool
Expand Down
3 changes: 3 additions & 0 deletions internal/configs/version1/nginx-plus.tmpl
Original file line number Diff line number Diff line change
Expand Up @@ -70,6 +70,9 @@ http {
'outcome=$app_protect_dos_outcome, reason=$app_protect_dos_outcome_reason, '
'ip_tls=$remote_addr:$app_protect_dos_tls_fp, ';

{{- end}}
{{- if .AppProtectDosArbFqdn}}
app_protect_dos_arb_fqdn {{.AppProtectDosArbFqdn}};
{{- end}}
{{- end}}

Expand Down
13 changes: 13 additions & 0 deletions tests/data/dos/appprotect-dos-arb-svc.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
apiVersion: v1
kind: Service
metadata:
name: svc-appprotect-dos-arb
spec:
selector:
app: appprotect-dos-arb
ports:
- name: arb
port: 3000
protocol: TCP
targetPort: 3000
clusterIP: None
30 changes: 30 additions & 0 deletions tests/data/dos/appprotect-dos-arb.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
apiVersion: apps/v1
kind: Deployment
metadata:
name: appprotect-dos-arb
spec:
replicas: 1
selector:
matchLabels:
app: appprotect-dos-arb
template:
metadata:
labels:
app: appprotect-dos-arb
spec:
containers:
- name: appprotect-dos-arb
image: docker-registry.nginx.com/nap-dos/app_protect_dos_arb:1.1.0
imagePullPolicy: IfNotPresent
resources:
limits:
memory: "128Mi"
cpu: "500m"
ports:
- containerPort: 3000
securityContext:
allowPrivilegeEscalation: false
runAsUser: 1001
capabilities:
drop:
- ALL
4 changes: 4 additions & 0 deletions tests/data/dos/arbitrator_ns.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
apiVersion: v1
kind: Namespace
metadata:
name: arbitrator
13 changes: 13 additions & 0 deletions tests/data/dos/nginx-config-arb-dif-ns.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
kind: ConfigMap
apiVersion: v1
metadata:
name: nginx-config
namespace: nginx-ingress
data:
real-ip-header: "X-Forwarded-For"
real-ip-recursive: "True"
set-real-ip-from: "0.0.0.0/0"
worker-connections: "30000"
worker-rlimit-nofile: "65535"
worker-rlimit-core: "500M"
app-protect-dos-arb-fqdn: "svc-appprotect-dos-arb.arbitrator.svc.cluster.local"
45 changes: 45 additions & 0 deletions tests/suite/dos_utils.py
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
from kubernetes.client import CoreV1Api
from kubernetes.stream import stream
from suite.resources_utils import get_file_contents, wait_before_test


Expand Down Expand Up @@ -29,3 +31,46 @@ def find_in_log(kube_apis, log_location, syslog_pod, namespace, time, value):
retry += 1
wait_before_test(10)
print(f"{value} Not in log, retrying... #{retry}")


def admd_s_content_to_dic(admd_s_contents):
arr = []
for line in admd_s_contents.splitlines():
arr.append(line)

admd_s_dic = {}
for line in arr:
tmp = line.split(":")
admd_s_dic[tmp[0].split("/")[-1]] = tmp[1]
return admd_s_dic


def check_learning_status_with_admd_s(kube_apis, syslog_pod, namespace, time):
retry = 0
learning_sas = 0.0
learning_signature = 0.0
while (learning_sas < 75 or learning_signature != 100) and retry <= time / 15:
retry += 1
admd_contents = get_admd_s_contents(kube_apis.v1, syslog_pod, namespace, 15)
admd_s_dic = admd_s_content_to_dic(admd_contents)
learn = admd_s_dic["name.info.learning"].replace("[", "").replace("]", "").split(",")
learning_sas = float(learn[0])
learning_signature = float(learn[3])
print(f"learning_sas: {learning_sas}, learning_signature: {learning_signature}")


def get_admd_s_contents(v1: CoreV1Api, pod_name, pod_namespace, time):
command = ["admd", "-s", "vs."]
resp = stream(
v1.connect_get_namespaced_pod_exec,
pod_name,
pod_namespace,
command=command,
stderr=True,
stdin=False,
stdout=True,
tty=False,
_request_timeout=time,
)
admd_contents = str(resp)
return admd_contents
2 changes: 2 additions & 0 deletions tests/suite/ic_fixtures.py
Original file line number Diff line number Diff line change
Expand Up @@ -275,6 +275,8 @@ def crd_ingress_controller_with_dos(
kube_apis.v1,
kube_apis.apps_v1_api,
namespace,
f"{DEPLOYMENTS}/deployment/appprotect-dos-arb.yaml",
f"{DEPLOYMENTS}/service/appprotect-dos-arb-svc.yaml",
)

print("------------------------- Create IC -----------------------------------")
Expand Down
31 changes: 20 additions & 11 deletions tests/suite/resources_utils.py
Original file line number Diff line number Diff line change
Expand Up @@ -1126,17 +1126,21 @@ def delete_ingress_controller(apps_v1_api: AppsV1Api, name, dep_type, namespace)
delete_daemon_set(apps_v1_api, name, namespace)


def create_dos_arbitrator(v1: CoreV1Api, apps_v1_api: AppsV1Api, namespace) -> str:
def create_dos_arbitrator(
v1: CoreV1Api, apps_v1_api: AppsV1Api, namespace, deployment_yaml_manifest, svc_yaml_manifest
) -> str:
"""
Create dos arbitrator according to the params.

:param v1: CoreV1Api
:param apps_v1_api: AppsV1Api
:param namespace: namespace name
:param deployment_yaml_manifest: arbitrator deployment yaml file
:param svc_yaml_manifest: arbitrator svc yaml file
:return: str
"""
yaml_manifest = f"{DEPLOYMENTS}/deployment/appprotect-dos-arb.yaml"
with open(yaml_manifest) as f:

with open(deployment_yaml_manifest) as f:
dep = yaml.safe_load(f)

name = create_deployment(apps_v1_api, namespace, dep)
Expand All @@ -1151,7 +1155,7 @@ def create_dos_arbitrator(v1: CoreV1Api, apps_v1_api: AppsV1Api, namespace) -> s
svc_name = create_service_from_yaml(
v1,
namespace,
f"{DEPLOYMENTS}/service/appprotect-dos-arb-svc.yaml",
svc_yaml_manifest,
)
print(f"Dos arbitrator svc was created with name '{svc_name}'")
return name
Expand Down Expand Up @@ -1192,7 +1196,7 @@ def create_ns_and_sa_from_yaml(v1: CoreV1Api, yaml_manifest) -> str:
return res["namespace"]


def create_items_from_yaml(kube_apis, yaml_manifest, namespace) -> None:
def create_items_from_yaml(kube_apis, yaml_manifest, namespace) -> {}:
"""
Apply yaml manifest with multiple items.

Expand All @@ -1201,22 +1205,27 @@ def create_items_from_yaml(kube_apis, yaml_manifest, namespace) -> None:
:param namespace:
:return:
"""
res = {}
print("Load yaml:")
with open(yaml_manifest) as f:
docs = yaml.safe_load_all(f)
for doc in docs:
if doc["kind"] == "Secret":
create_secret(kube_apis.v1, namespace, doc)
res["Secret"] = create_secret(kube_apis.v1, namespace, doc)
elif doc["kind"] == "ConfigMap":
create_configmap(kube_apis.v1, namespace, doc)
res["ConfigMap"] = create_configmap(kube_apis.v1, namespace, doc)
elif doc["kind"] == "Ingress":
create_ingress(kube_apis.networking_v1, namespace, doc)
res["Ingress"] = create_ingress(kube_apis.networking_v1, namespace, doc)
elif doc["kind"] == "Service":
create_service(kube_apis.v1, namespace, doc)
res["Service"] = create_service(kube_apis.v1, namespace, doc)
elif doc["kind"] == "Deployment":
create_deployment(kube_apis.apps_v1_api, namespace, doc)
res["Deployment"] = create_deployment(kube_apis.apps_v1_api, namespace, doc)
elif doc["kind"] == "DaemonSet":
create_daemon_set(kube_apis.apps_v1_api, namespace, doc)
res["DaemonSet"] = create_daemon_set(kube_apis.apps_v1_api, namespace, doc)
elif doc["kind"] == "Namespace":
res["Namespace"] = create_namespace(kube_apis.v1, doc)

return res


def create_ingress_with_ap_annotations(
Expand Down