Skip to content

Commit

Permalink
AP: enable FQDN as syslog destination
Browse files Browse the repository at this point in the history
  • Loading branch information
Rafal Wegrzycki committed Nov 16, 2021
1 parent c2d8783 commit 9987ee2
Show file tree
Hide file tree
Showing 10 changed files with 34 additions and 43 deletions.
20 changes: 10 additions & 10 deletions docs/content/configuration/policy-resource.md
Original file line number Diff line number Diff line change
Expand Up @@ -371,20 +371,20 @@ waf:
securityLog:
enable: true
apLogConf: "default/logconf"
logDest: "syslog:server=127.0.0.1:514"
logDest: "syslog:server=syslog-svc.default:514"
```

> Note: The feature is implemented using the NGINX Plus [NGINX App Protect Module](https://docs.nginx.com/nginx-app-protect/configuration/).
{{% table %}}
|Field | Description | Type | Required |
| ---| ---| ---| --- |
|``enable`` | Enables NGINX App Protect. | ``bool`` | Yes |
|``apPolicy`` | The [App Protect policy](/nginx-ingress-controller/app-protect/configuration/#app-protect-policies) of the WAF. Accepts an optional namespace. | ``string`` | No |
|``securityLog.enable`` | Enables security log. | ``bool`` | No |
|``securityLog.apLogConf`` | The [App Protect log conf](/nginx-ingress-controller/app-protect/configuration/#app-protect-logs) resource. Accepts an optional namespace. | ``string`` | No |
|``securityLog.logDest`` | The log destination for the security log. Accepted variables are ``syslog:server=<ip-address &#124; localhost>:<port>``, ``stderr``, ``<absolute path to file>``. Default is ``"syslog:server=127.0.0.1:514"``. | ``string`` | No |
{{% /table %}}
{{% table %}}
|Field | Description | Type | Required |
| ---| ---| ---| --- |
|``enable`` | Enables NGINX App Protect. | ``bool`` | Yes |
|``apPolicy`` | The [App Protect policy](/nginx-ingress-controller/app-protect/configuration/#app-protect-policies) of the WAF. Accepts an optional namespace. | ``string`` | No |
|``securityLog.enable`` | Enables security log. | ``bool`` | No |
|``securityLog.apLogConf`` | The [App Protect log conf](/nginx-ingress-controller/app-protect/configuration/#app-protect-logs) resource. Accepts an optional namespace. | ``string`` | No |
|``securityLog.logDest`` | The log destination for the security log. Accepted variables are ``syslog:server=<ip-address &#124; localhost; fqdn>:<port>``, ``stderr``, ``<absolute path to file>``. Default is ``"syslog:server=127.0.0.1:514"``. | ``string`` | No |
{{% /table %}}

#### WAF Merging Behavior

Expand Down
7 changes: 0 additions & 7 deletions examples/appprotect/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -40,13 +40,6 @@ $ kubectl create -f cafe.yaml
$ kubectl create -f ap-apple-uds.yaml
```
4. Create an Ingress Resource:

Update the `appprotect.f5.com/app-protect-security-log-destination` annotation from `cafe-ingress.yaml` with the ClusterIP of the syslog service. For example, if the IP is `10.101.21.110`:
```yaml
. . .
appprotect.f5.com/app-protect-security-log-destination: "syslog:server=10.101.21.110:514"
```
Create the Ingress Resource:
```
$ kubectl create -f cafe-ingress.yaml
```
Expand Down
2 changes: 1 addition & 1 deletion examples/appprotect/cafe-ingress.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ metadata:
appprotect.f5.com/app-protect-enable: "True"
appprotect.f5.com/app-protect-security-log-enable: "True"
appprotect.f5.com/app-protect-security-log: "default/logconf"
appprotect.f5.com/app-protect-security-log-destination: "syslog:server=127.0.0.1:514"
appprotect.f5.com/app-protect-security-log-destination: "syslog:server=syslog-svc.default:514"
spec:
tls:
- hosts:
Expand Down
7 changes: 0 additions & 7 deletions examples/custom-resources/waf/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -36,13 +36,6 @@ $ kubectl apply -f webapp.yaml

## Step 3 - Deploy the WAF Policy

1. Update the `logDest` field from `waf.yaml` with the ClusterIP of the syslog service. For example, if the IP is `10.101.21.110`:
```yaml
waf:
...
logDest: "syslog:server=10.101.21.110:514"
```

1. Create the WAF policy
```
$ kubectl apply -f waf.yaml
Expand Down
2 changes: 1 addition & 1 deletion examples/custom-resources/waf/waf.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -9,4 +9,4 @@ spec:
securityLog:
enable: true
apLogConf: "default/logconf"
logDest: "syslog:server=127.0.0.1:514"
logDest: "syslog:server=syslog-svc.default:514"
11 changes: 8 additions & 3 deletions internal/k8s/appprotect/app_protect_resources.go
Original file line number Diff line number Diff line change
Expand Up @@ -73,13 +73,14 @@ func validateAppProtectLogConf(logConf *unstructured.Unstructured) error {
}

var (
logDstEx = regexp.MustCompile(`(?:syslog:server=((?:\d{1,3}\.){3}\d{1,3}|localhost):\d{1,5})|stderr|(?:\/[\S]+)+`)
logDstEx = regexp.MustCompile(`(?:syslog:server=((?:\d{1,3}\.){3}\d{1,3}|localhost|[a-zA-Z0-9._-]+):\d{1,5})|stderr|(?:\/[\S]+)+`)
logDstFileEx = regexp.MustCompile(`(?:\/[\S]+)+`)
logDstFQDNEx = regexp.MustCompile(`(?:[a-zA-Z0-9_-]+\.)+[a-zA-Z0-9_-]+`)
)

// ValidateAppProtectLogDestination validates destination for log configuration
func ValidateAppProtectLogDestination(dstAntn string) error {
errormsg := "Error parsing App Protect Log config: Destination must follow format: syslog:server=<ip-address | localhost>:<port> or stderr or absolute path to file"
errormsg := "Error parsing App Protect Log config: Destination must follow format: syslog:server=<ip-address | localhost>:<port> or fqdn or stderr or absolute path to file"
if !logDstEx.MatchString(dstAntn) {
return fmt.Errorf("%s Log Destination did not follow format", errormsg)
}
Expand All @@ -105,8 +106,12 @@ func ValidateAppProtectLogDestination(dstAntn string) error {
return nil
}

if logDstFQDNEx.MatchString(ipstr) {
return nil
}

if net.ParseIP(ipstr) == nil {
return fmt.Errorf("Error parsing host: %v is not a valid ip address", ipstr)
return fmt.Errorf("Error parsing host: %v is not a valid ip address or host name", ipstr)
}

return nil
Expand Down
4 changes: 2 additions & 2 deletions internal/k8s/appprotect/app_protect_resources_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -315,13 +315,13 @@ func TestValidateAppProtectLogConf(t *testing.T) {

func TestValidateAppProtectLogDestinationAnnotation(t *testing.T) {
// Positive test cases
posDstAntns := []string{"stderr", "syslog:server=localhost:9000", "syslog:server=10.1.1.2:9000", "/var/log/ap.log"}
posDstAntns := []string{"stderr", "syslog:server=localhost:9000", "syslog:server=10.1.1.2:9000", "/var/log/ap.log", "syslog:server=my-syslog-server.my-namespace:515"}

// Negative test cases item, expected error message
negDstAntns := [][]string{
{"stdout", "Log Destination did not follow format"},
{"syslog:server=localhost:99999", "not a valid port number"},
{"syslog:server=999.99.99.99:5678", "is not a valid ip address"},
{"syslog:server=mysyslog-server:999", "not a valid ip address"},
}

for _, tCase := range posDstAntns {
Expand Down
6 changes: 3 additions & 3 deletions tests/suite/test_app_protect_grpc.py
Original file line number Diff line number Diff line change
Expand Up @@ -82,11 +82,11 @@ def backend_setup(request, kube_apis, ingress_controller_endpoint, ingress_contr
print("------------------------- Deploy Syslog -----------------------------")
src_syslog_yaml = f"{TEST_DATA}/appprotect/syslog.yaml"
create_items_from_yaml(kube_apis, src_syslog_yaml, test_namespace)
syslog_ep = get_service_endpoint(kube_apis, "syslog-svc", test_namespace)
print(syslog_ep)
syslog_dst = f"syslog-svc.{test_namespace}"
print(syslog_dst)
print("------------------------- Deploy ingress -----------------------------")
src_ing_yaml = f"{TEST_DATA}/appprotect/grpc/ingress.yaml"
create_ingress_with_ap_annotations(kube_apis, src_ing_yaml, test_namespace, policy, "True", "True", f"{syslog_ep}:514")
create_ingress_with_ap_annotations(kube_apis, src_ing_yaml, test_namespace, policy, "True", "True", f"{syslog_dst}:514")
ingress_host = get_first_ingress_host_from_yaml(src_ing_yaml)
wait_before_test(40)
except Exception as ex:
Expand Down
14 changes: 7 additions & 7 deletions tests/suite/test_app_protect_integration.py
Original file line number Diff line number Diff line change
Expand Up @@ -328,13 +328,13 @@ def test_ap_sec_logs_on(

create_items_from_yaml(kube_apis, src_syslog_yaml, test_namespace)

syslog_ep = get_service_endpoint(kube_apis, "syslog-svc", test_namespace)
syslog_dst = f"syslog-svc.{test_namespace}"

# items[-1] because syslog pod is last one to spin-up
syslog_pod = kube_apis.v1.list_namespaced_pod(test_namespace).items[-1].metadata.name

create_ingress_with_ap_annotations(
kube_apis, src_ing_yaml, test_namespace, ap_policy, "True", "True", f"{syslog_ep}:514"
kube_apis, src_ing_yaml, test_namespace, ap_policy, "True", "True", f"{syslog_dst}:514"
)
ingress_host = get_first_ingress_host_from_yaml(src_ing_yaml)

Expand Down Expand Up @@ -401,13 +401,13 @@ def test_ap_pod_startup(
src_syslog_yaml = f"{TEST_DATA}/appprotect/syslog.yaml"
create_items_from_yaml(kube_apis, src_syslog_yaml, test_namespace)

syslog_ep = get_service_endpoint(kube_apis, "syslog-svc", test_namespace)
syslog_dst = f"syslog-svc.{test_namespace}"

# items[-1] because syslog pod is last one to spin-up
syslog_pod = kube_apis.v1.list_namespaced_pod(test_namespace).items[-1].metadata.name

create_ingress_with_ap_annotations(
kube_apis, src_ing_yaml, test_namespace, ap_policy, "True", "True", f"{syslog_ep}:514"
kube_apis, src_ing_yaml, test_namespace, ap_policy, "True", "True", f"{syslog_dst}:514"
)
ingress_host = get_first_ingress_host_from_yaml(src_ing_yaml)
print("--------- AppProtect module is enabled with correct policy ---------")
Expand Down Expand Up @@ -439,8 +439,8 @@ def test_ap_multi_sec_logs(
create_items_from_yaml(kube_apis, src_syslog_yaml, test_namespace)
create_items_from_yaml(kube_apis, src_syslog2_yaml, test_namespace)

syslog_ep = get_service_endpoint(kube_apis, "syslog-svc", test_namespace)
syslog2_ep = get_service_endpoint(kube_apis, "syslog2-svc", test_namespace)
syslog_dst = f"syslog-svc.{test_namespace}"
syslog2_dst = f"syslog2-svc.{test_namespace}"

syslog_pod = kube_apis.v1.list_namespaced_pod(test_namespace).items[-2].metadata.name
syslog2_pod = kube_apis.v1.list_namespaced_pod(test_namespace).items[-1].metadata.name
Expand All @@ -461,7 +461,7 @@ def test_ap_multi_sec_logs(

doc["metadata"]["annotations"][
"appprotect.f5.com/app-protect-security-log-destination"
] = f"syslog:server={syslog_ep}:514,syslog:server={syslog2_ep}:514"
] = f"syslog:server={syslog_dst}:514,syslog:server={syslog2_dst}:514"

create_ingress(kube_apis.networking_v1, test_namespace, doc)

Expand Down
4 changes: 2 additions & 2 deletions tests/suite/test_app_protect_waf_policies.py
Original file line number Diff line number Diff line change
Expand Up @@ -325,7 +325,7 @@ def test_ap_waf_policy_logs(
src_syslog_yaml = f"{TEST_DATA}/ap-waf/syslog.yaml"
log_loc = f"/var/log/messages"
create_items_from_yaml(kube_apis, src_syslog_yaml, test_namespace)
syslog_ep = get_service_endpoint(kube_apis, "syslog-svc", test_namespace)
syslog_dst = f"syslog-svc.{test_namespace}"
syslog_pod = kube_apis.v1.list_namespaced_pod(test_namespace).items[-1].metadata.name
print(f"Create waf policy")
create_ap_waf_policy_from_yaml(
Expand All @@ -337,7 +337,7 @@ def test_ap_waf_policy_logs(
True,
ap_pol_name,
log_name,
f"syslog:server={syslog_ep}:514",
f"syslog:server={syslog_dst}:514",
)
wait_before_test()
print(f"Patch vs with policy: {waf_spec_vs_src}")
Expand Down

0 comments on commit 9987ee2

Please sign in to comment.