|
| 1 | +--- |
| 2 | +# We use sentence case and present imperative tone |
| 3 | +title: "Add a read-only filesystem for Kubernetes " |
| 4 | +# Weights are assigned in increments of 100: determines sorting order |
| 5 | +weight: 700 |
| 6 | +# Creates a table of contents and sidebar, useful for large documents |
| 7 | +toc: true |
| 8 | +# Types have a 1:1 relationship with Hugo archetypes, so you shouldn't need to change this |
| 9 | +nd-content-type: how-to |
| 10 | +# Intended for internal catalogue and search, case sensitive: |
| 11 | +# Agent, N4Azure, NIC, NIM, NGF, NAP-DOS, NAP-WAF, NGINX One, NGINX+, Solutions, Unit |
| 12 | +nd-product: NAP-WAF |
| 13 | +--- |
| 14 | + |
| 15 | +This page describes how to add a read-only filesystem when deploying F5 WAF for NGINX when using Kubernetes. |
| 16 | + |
| 17 | +It restricts the root filesystem to read-only mode, improving security by limiting potential write access in case of compromise. |
| 18 | + |
| 19 | +## Before you begin |
| 20 | + |
| 21 | +To complete this guide, you will need the following prerequisites: |
| 22 | + |
| 23 | +- A Kubernetes cluster that supports read-only root file systems |
| 24 | +- The cluster must have access to the NGINX and F5 WAF configuration files |
| 25 | + |
| 26 | +You may need to identify any extra paths that need to be writable by F5 WAF for NGINX during runtime: this document assumes you are using the default paths. |
| 27 | + |
| 28 | +## Enable readOnlyRootFilesystem and configure writable paths |
| 29 | + |
| 30 | +The first step is to add the `readOnlyRootFilesystem` value (as true) to your Kubernetes pod security context as follows: |
| 31 | + |
| 32 | +```yaml |
| 33 | +containers: |
| 34 | + - name: nginx |
| 35 | + ... |
| 36 | + securityContext: |
| 37 | + readOnlyRootFilesystem: true |
| 38 | + - name: waf-enforcer |
| 39 | + ... |
| 40 | + securityContext: |
| 41 | + readOnlyRootFilesystem: true |
| 42 | + - name: waf-config-mgr |
| 43 | + ... |
| 44 | + securityContext: |
| 45 | + readOnlyRootFilesystem: true |
| 46 | +``` |
| 47 | +
|
| 48 | +With a read-only root file system, you will likely still require write access for certain directories, such as logs and temporary files. You can add these directories by mounting them as writable volumes in your Kubernetes deployment. |
| 49 | +
|
| 50 | +In the following example, `/tmp` and `/var/log/nginx` are writable directories, essential for NGINX and F5 WAF operations. |
| 51 | + |
| 52 | +```yaml |
| 53 | +containers: |
| 54 | + - name: nginx |
| 55 | + ... |
| 56 | + volumeMounts: |
| 57 | + - name: app-protect-bd-config |
| 58 | + mountPath: /opt/app_protect/bd_config |
| 59 | + - name: app-protect-config |
| 60 | + mountPath: /opt/app_protect/config |
| 61 | + - name: tmp-volume |
| 62 | + mountPath: /tmp |
| 63 | + - name: nginx-log |
| 64 | + mountPath: /var/log/nginx |
| 65 | + - name: app-protect-bundles |
| 66 | + mountPath: /etc/app_protect/bundles |
| 67 | +... |
| 68 | +
|
| 69 | +volumes: |
| 70 | + - name: app-protect-bd-config |
| 71 | + emptyDir: {} |
| 72 | + - name: app-protect-config |
| 73 | + emptyDir: {} |
| 74 | + - name: nginx-log |
| 75 | + emptyDir: {} |
| 76 | + - name: tmp-volume |
| 77 | + emptyDir: {} |
| 78 | + - name: app-protect-bundles |
| 79 | + persistentVolumeClaim: |
| 80 | + claimName: nap5-bundles-pvc |
| 81 | +``` |
| 82 | + |
| 83 | +A full example could look like the following: |
| 84 | + |
| 85 | +```yaml |
| 86 | +apiVersion: apps/v1 |
| 87 | +kind: Deployment |
| 88 | +metadata: |
| 89 | + name: nap5-deployment |
| 90 | +spec: |
| 91 | + selector: |
| 92 | + matchLabels: |
| 93 | + app: nap5 |
| 94 | + replicas: 2 |
| 95 | + template: |
| 96 | + metadata: |
| 97 | + labels: |
| 98 | + app: nap5 |
| 99 | + spec: |
| 100 | + imagePullSecrets: |
| 101 | + - name: regcred |
| 102 | + containers: |
| 103 | + - name: nginx |
| 104 | + image: <your-private-registry>/nginx-app-protect-5:<your-tag> |
| 105 | + imagePullPolicy: IfNotPresent |
| 106 | + securityContext: |
| 107 | + readOnlyRootFilesystem: true |
| 108 | + volumeMounts: |
| 109 | + - name: app-protect-bd-config |
| 110 | + mountPath: /opt/app_protect/bd_config |
| 111 | + - name: app-protect-config |
| 112 | + mountPath: /opt/app_protect/config |
| 113 | + - name: tmp-volume |
| 114 | + mountPath: /tmp |
| 115 | + - name: nginx-log |
| 116 | + mountPath: /var/log/nginx |
| 117 | + - name: app-protect-bundles |
| 118 | + mountPath: /etc/app_protect/bundles |
| 119 | + - name: waf-enforcer |
| 120 | + image: private-registry.nginx.com/nap/waf-enforcer:<version-tag> |
| 121 | + imagePullPolicy: IfNotPresent |
| 122 | + securityContext: |
| 123 | + readOnlyRootFilesystem: true |
| 124 | + env: |
| 125 | + - name: ENFORCER_PORT |
| 126 | + value: "50000" |
| 127 | + volumeMounts: |
| 128 | + - name: app-protect-bd-config |
| 129 | + mountPath: /opt/app_protect/bd_config |
| 130 | + - name: waf-config-mgr |
| 131 | + image: private-registry.nginx.com/nap/waf-config-mgr:<version-tag> |
| 132 | + imagePullPolicy: IfNotPresent |
| 133 | + securityContext: |
| 134 | + allowPrivilegeEscalation: false |
| 135 | + readOnlyRootFilesystem: true |
| 136 | + capabilities: |
| 137 | + drop: |
| 138 | + - all |
| 139 | + volumeMounts: |
| 140 | + - name: app-protect-bd-config |
| 141 | + mountPath: /opt/app_protect/bd_config |
| 142 | + - name: app-protect-config |
| 143 | + mountPath: /opt/app_protect/config |
| 144 | + - name: app-protect-bundles |
| 145 | + mountPath: /etc/app_protect/bundles |
| 146 | + volumes: |
| 147 | + - name: app-protect-bd-config |
| 148 | + emptyDir: {} |
| 149 | + - name: app-protect-config |
| 150 | + emptyDir: {} |
| 151 | + - name: nginx-log |
| 152 | + emptyDir: {} |
| 153 | + - name: tmp-volume |
| 154 | + emptyDir: {} |
| 155 | + - name: app-protect-bundles |
| 156 | + persistentVolumeClaim: |
| 157 | + claimName: nap5-bundles-pvc |
| 158 | +``` |
| 159 | + |
| 160 | +## Update NGINX configuration with writable paths |
| 161 | + |
| 162 | +Once you have created writable paths in your Kubernetes cluster, you should update your NGINX configuration to use these paths. |
| 163 | + |
| 164 | +The following are fields in _nginx.conf_ you should update, which correspond to writable volumes configured during the last step: |
| 165 | + |
| 166 | +```nginx |
| 167 | +user nginx; |
| 168 | +worker_processes auto; |
| 169 | +
|
| 170 | +# F5 WAF for NGINX |
| 171 | +load_module modules/ngx_http_app_protect_module.so; |
| 172 | +
|
| 173 | +error_log /var/log/nginx/error.log debug; |
| 174 | +pid /tmp/nginx.pid; |
| 175 | +
|
| 176 | +events { |
| 177 | + worker_connections 1024; |
| 178 | +} |
| 179 | +
|
| 180 | +http { |
| 181 | + include /etc/nginx/mime.types; |
| 182 | + default_type application/octet-stream; |
| 183 | +
|
| 184 | + log_format main '$remote_addr - $remote_user [$time_local] "$request" ' |
| 185 | + '$status $body_bytes_sent "$http_referer" ' |
| 186 | + '"$http_user_agent" "$http_x_forwarded_for"'; |
| 187 | +
|
| 188 | + access_log /var/log/nginx/access.log; |
| 189 | +
|
| 190 | + # Temporary directories for kubernetes "readonlyfilesystem" |
| 191 | + client_body_temp_path /tmp/nginx-client-body; |
| 192 | + proxy_temp_path /tmp/nginx-proxy; |
| 193 | + fastcgi_temp_path /tmp/nginx-fastcgi; |
| 194 | + uwsgi_temp_path /tmp/nginx-uwsgi; |
| 195 | + scgi_temp_path /tmp/nginx-scgi; |
| 196 | +
|
| 197 | + sendfile on; |
| 198 | + #tcp_nopush on; |
| 199 | +
|
| 200 | + keepalive_timeout 65; |
| 201 | +
|
| 202 | + #gzip on; |
| 203 | +
|
| 204 | + # F5 WAF for NGINX |
| 205 | + app_protect_enforcer_address 127.0.0.1:50000; |
| 206 | +
|
| 207 | + include /etc/nginx/conf.d/*.conf; |
| 208 | +} |
| 209 | +``` |
0 commit comments