Image: mikirisec/mikiri-waf-filter-nginx. Claim mount: /mikiri-waf-filter-nginx. Service ports: 80, 443, 5672.
The image includes Nginx, Memcached, RabbitMQ, MLA and the API Firewall. The first start prepares the claim and the container exits. Point the Filter at API before the next start. Create the protected site in WMC after the Filter is running, as described in Configuring Filter as a reverse proxy. The public Ingress in front of this Service is Kubernetes Ingress. The namespace and the first-start rule are in Kubernetes.
first-launch.kubectl apply -n mikiri-waf -f - <<'EOF'
apiVersion: v1
kind: PersistentVolumeClaim
metadata:
name: mikiri-waf-filter-nginx
spec:
accessModes:
- ReadWriteOnce
resources:
requests:
storage: 10Gi
---
apiVersion: v1
kind: Pod
metadata:
name: mikiri-waf-filter-nginx-first
spec:
restartPolicy: Never
initContainers:
- name: first-launch
image: mikirisec/mikiri-waf-filter-nginx:latest
command: ["touch", "/mikiri-waf-filter-nginx/first-launch"]
volumeMounts:
- name: data
mountPath: /mikiri-waf-filter-nginx
containers:
- name: filter
image: mikirisec/mikiri-waf-filter-nginx:latest
volumeMounts:
- name: data
mountPath: /mikiri-waf-filter-nginx
volumes:
- name: data
persistentVolumeClaim:
claimName: mikiri-waf-filter-nginx
EOF
kubectl wait -n mikiri-waf --for='jsonpath={.status.phase}=Succeeded' pod/mikiri-waf-filter-nginx-first --timeout=180s
kubectl delete pod mikiri-waf-filter-nginx-first -n mikiri-waf --wait=true
The entrypoint writes load_module lines, worker_processes auto and include mikiri-waf/filter/global/waf.conf; inside the http block of nginx.conf, copies it to the claim and stores the RabbitMQ credentials in rabbitmq_password. On a later start the same include is added if it is missing. The RabbitMQ user name in waf.conf is USER. The user is created again on every start.
mikiri-waf/filter/global/waf.conf. The first start copies it from /etc/nginx/mikiri-waf/filter/global/waf.conf. The edit Pod does not run that copy, so the command below copies the image file when the claim does not have it yet. The generated lines are commented: # waf_product_key <YOUR_KEY>; and # waf_api_url http://api.example.com:8080;. The next command removes the comments, writes the license key and sets the API Service. A proxy in front of API is the waf_api_proxy line in integration with API. Leave that line unchanged when API is reached directly. A commented waf_sys_proxy line is not changed by the sed below. The command that sets it is in Editing a file in the container.kubectl apply -n mikiri-waf -f - <<'EOF'
apiVersion: v1
kind: Pod
metadata:
name: mikiri-waf-filter-nginx-edit
spec:
restartPolicy: Never
containers:
- name: edit
image: mikirisec/mikiri-waf-filter-nginx:latest
command: ["sleep", "3600"]
volumeMounts:
- name: data
mountPath: /mikiri-waf-filter-nginx
volumes:
- name: data
persistentVolumeClaim:
claimName: mikiri-waf-filter-nginx
EOF
kubectl wait -n mikiri-waf --for=condition=ready pod/mikiri-waf-filter-nginx-edit --timeout=180s
kubectl exec -n mikiri-waf mikiri-waf-filter-nginx-edit -- bash -c 'd=/mikiri-waf-filter-nginx/mikiri-waf/filter/global; mkdir -p "$d"; test -f "$d/waf.conf" || cp /etc/nginx/mikiri-waf/filter/global/waf.conf "$d/"'
kubectl exec -n mikiri-waf mikiri-waf-filter-nginx-edit -- sed -i \
-e 's|^#\{0,1\}[[:space:]]*waf_product_key .*|waf_product_key YOUR_KEY;|' \
-e 's|^#\{0,1\}[[:space:]]*waf_api_url .*|waf_api_url http://mikiri-waf-api:8080;|' \
/mikiri-waf-filter-nginx/mikiri-waf/filter/global/waf.conf
kubectl delete pod mikiri-waf-filter-nginx-edit -n mikiri-waf --wait=true
Replace YOUR_KEY with the license key before running the command.
The same license key on two or more Filters violates the EULA.
mikiri-waf-mla and mikiri-waf-af. hostPort publishes container port 80 on the node. 8080 is an example. Replace it before applying the manifest. With hostIP set to 0.0.0.0, that port is open on the node that runs the Pod and stays open while the Pod runs. The node must have the port free. Port 5672 is for MLC in this namespace. It is not published outside the cluster.kubectl apply -n mikiri-waf -f - <<'EOF'
apiVersion: apps/v1
kind: Deployment
metadata:
name: mikiri-waf-filter-nginx
spec:
replicas: 1
strategy:
type: Recreate
selector:
matchLabels:
app: mikiri-waf-filter-nginx
template:
metadata:
labels:
app: mikiri-waf-filter-nginx
spec:
containers:
- name: filter
image: mikirisec/mikiri-waf-filter-nginx:latest
ports:
- containerPort: 80
hostPort: 8080
hostIP: "0.0.0.0"
- containerPort: 443
- containerPort: 5672
volumeMounts:
- name: data
mountPath: /mikiri-waf-filter-nginx
volumes:
- name: data
persistentVolumeClaim:
claimName: mikiri-waf-filter-nginx
---
apiVersion: v1
kind: Service
metadata:
name: mikiri-waf-filter-nginx
spec:
selector:
app: mikiri-waf-filter-nginx
ports:
- name: http
port: 80
targetPort: 80
- name: https
port: 443
targetPort: 443
- name: rabbitmq
port: 5672
targetPort: 5672
EOF
kubectl rollout status deployment/mikiri-waf-filter-nginx -n mikiri-waf
Mikiri WAF logs are in log/mikiri-waf/. Nginx logs are in log/nginx/.
<node> is an address of the node that runs the Pod. 8080 is the hostPort from the manifest.curl -i http://<node>:8080/mikiri-waf-test
The Filter answers 403.
| On the claim | In the container | Contents |
|---|---|---|
nginx.conf |
/etc/nginx/nginx.conf |
Main Nginx configuration |
mikiri-waf/filter/global/waf.conf |
/etc/nginx/mikiri-waf/filter/global/waf.conf |
Filter configuration |
mikiri-waf/mla/mla.conf |
/etc/nginx/mikiri-waf/mla/mla.conf |
MLA configuration |
mikiri-waf/html/ |
/etc/nginx/mikiri-waf/html/ |
Anti-bot pages and the custom block page |
log/mikiri-waf/ |
/var/log/mikiri-waf/ |
Filter, MLA and API Firewall logs |
log/nginx/ |
/var/log/nginx/ |
Nginx logs |
rabbitmq_password |
file on the claim | RabbitMQ user name and password |
kubectl rollout restart deployment/mikiri-waf-filter-nginx -n mikiri-waf
kubectl rollout status deployment/mikiri-waf-filter-nginx -n mikiri-waf
Do not create first-launch again. If the package version changed, the previous claim contents are copied to old/. The working files stay in place.