F5 NGINX Ingress Controller

The DataDome Nginx module is compatible with F5 NGINX Ingress Controller.

Follow the steps below to integrate into your kubernetes infrastructure.

Prerequisites

  • Existing nginx-ingress deployment
  • kubectl access to your Kubernetes cluster
  • Container registry where you can push images (Docker Hub, ECR, GCR, ACR, etc.)

Overview

The deployment process involves:

  1. Building and pushing the custom F5 NGINX Ingress controller image with DataDome module to a registry
  2. Creating Kubernetes resources (Secret, ConfigMap)
  3. Updating the existing deployment to use the new image

Implementation

Step 1: Build and Push the Custom Image

❗️

Change NGINX_INGRESS_VERSION variable to the desired image version.

Change REGISTRY to a registry where Kubernetes cluster can pull.

export NGINX_INGRESS_VERSION="5.3.2-alpine"
export REGISTRY="your-registry.com"

# Build the image (replace with your registry and version)
docker build --build-arg NGINX_INGRESS_VERSION=${NGINX_INGRESS_VERSION} -f Dockerfile -t ${REGISTRY}/nginx-ingress-datadome:${NGINX_INGRESS_VERSION} .

# Push to your container registry
docker push ${REGISTRY}/nginx-ingress-datadome:${NGINX_INGRESS_VERSION}
ARG NGINX_INGRESS_VERSION=${NGINX_INGRESS_VERSION:-5.3.2-alpine}
ARG DATADOME_VERSION=${DATADOME_VERSION:-latest}

# STAGE1: Build DataDome module
FROM nginx/nginx-ingress:${NGINX_INGRESS_VERSION} AS module-builder
# Repeat ARGs definition to retain value
ARG NGINX_INGRESS_VERSION
ARG DATADOME_VERSION

# Make ENV variables from ARGs
ENV NGINX_INGRESS_VERSION=${NGINX_INGRESS_VERSION} \
  DATADOME_VERSION=${DATADOME_VERSION}

# Make default user root to be able to install packages.
USER root

RUN set -x && \
  nginx_version=$(nginx -v 2>&1 | awk '{print $3}' | sed -e 's|nginx/||') && \
  curl -SsL http://nginx.org/download/nginx-${nginx_version}.tar.gz -o /tmp/nginx-${nginx_version}.tar.gz && \
  curl -SsL https://package.datadome.co/linux/DataDome-Nginx-${DATADOME_VERSION}.tgz -o /tmp/datadome-nginx.tar.gz && \
  mkdir -p /tmp/src/ && \
  tar xzf /tmp/nginx-${nginx_version}.tar.gz -C /tmp/src && \
  tar xzf /tmp/datadome-nginx.tar.gz -C /tmp/src && \
  apk update && \
  apk add --no-cache --virtual builddeps \
  gcc \
  make \
  zlib-dev \
  musl-dev \
  pcre-dev \
  openssl-dev \
  && \
  DATADOME_DIR="DataDome-NginxDome-*" && \
  if ls -d /tmp/src/${DATADOME_DIR} 1> /dev/null 2>&1; then \
    echo "Old package structure pre AWS S3, it has the folder ${DATADOME_DIR}"; \
  else \
    echo "New package structure in AWS S3, it does not have the folder ${DATADOME_DIR}" ; \
    DATADOME_DIR=""; \
  fi && \
  cd /tmp/src/${DATADOME_DIR} && \
  sed -i 's/{ ngx_string("RequestModuleName"), ngx_string("Nginx")}/{ ngx_string("RequestModuleName"), ngx_string("nginxingress\/${nginx_version}")}/g' ngx_http_data_dome_shield_module.c && \
  cd /tmp/src/nginx-${nginx_version} && \
  nginx_flags=$(nginx -V 2>&1 | sed -n -e 's/^.*arguments: //p') && \
  echo $nginx_flags && \
  ./configure --with-compat --add-dynamic-module=../${DATADOME_DIR} && \
  make modules &&\
  cd ../ && \
  make -C nginx-${nginx_version} -f objs/Makefile modules && \
  mkdir -p /datadome-nginx-modules && \
  cp nginx-${nginx_version}/objs/ngx_http_data_dome_*.so /datadome-nginx-modules/ && \
  chown nginx:nginx /datadome-nginx-modules/* && \
  chmod 755 /datadome-nginx-modules/* && \
  apk del --no-cache builddeps && \
  rm -rf /tmp/* \
  /var/cache/apk/*  \
  /var/tmp/*

# revert to original user to drop privileges
USER nginx

# STAGE2: Final image
FROM nginx/nginx-ingress:${NGINX_INGRESS_VERSION}
ARG NGINX_INGRESS_VERSION
ARG DATADOME_VERSION

USER root

COPY --from=module-builder /datadome-nginx-modules /etc/nginx/modules

# check nginx configuration syntax
RUN nginx -t

# Switch back to nginx user
USER nginx


Step 2.1: Create the DataDome Secret

Create a file named datadome-secret.yaml:

❗️

Replace DATADOME_SERVER_SIDE_KEY with your API key from the DataDome dashboard.

apiVersion: v1
kind: Secret
metadata:
  name: datadome-ingress-controller-secret
  namespace: nginx-ingress  # Match your ingress controller namespace
type: Opaque
stringData:
  datadome-ingress-controller-secret: |
    data_dome_shield_key "DATADOME_SERVER_SIDE_KEY";

Apply the secret:

kubectl apply -f datadome-secret.yaml

Step 2.2: Create the DataDome ConfigMap

Create a file named datadome-configmap.yaml:

apiVersion: v1
kind: ConfigMap
metadata:
  name: nginx-config  # This must match your existing ConfigMap name
  namespace: nginx-ingress
data:
  # Load DataDome modules at NGINX startup
  main-snippets: |
    load_module /etc/nginx/modules/ngx_http_data_dome_auth_module.so;
    load_module /etc/nginx/modules/ngx_http_data_dome_shield_module.so;
    load_module /etc/nginx/modules/ngx_http_data_dome_upstream_dynamic_servers_module.so;

  # Define DataDome API upstream and DNS resolver
  http-snippets: |
    resolver 8.8.8.8;

    upstream datadome {
      dd_server api.datadome.co:443;
      keepalive 10;
    }

  # Enable DataDome protection at server level
  server-snippets: |
    data_dome_auth @datadome;

    location = @datadome {
        # Include the API key from the secret
        include /etc/nginx/secrets/datadome-ingress-controller-secret;

        proxy_pass https://datadome/validate-request/;
        proxy_method POST;
        proxy_http_version 1.1;
        proxy_set_header Connection "keep-alive";
        proxy_set_header Content-Type "application/x-www-form-urlencoded";
        proxy_set_header X-DataDome-X-Set-Cookie $data_dome_header_x_set_cookie;
        proxy_set_body $data_dome_request_body;
        proxy_ignore_client_abort on;
        proxy_connect_timeout 150ms;
        proxy_read_timeout 50ms;
        proxy_next_upstream off;
    }

Apply the ConfigMap:

kubectl apply -f datadome-configmap.yaml

Note: If you already have a nginx-config ConfigMap with custom settings, merge the DataDome snippets with your existing configuration instead of replacing it entirely.


Step 3: Update the Ingress Controller Deployment

This single command updates your existing NGINX Ingress Controller deployment with:

  • The new DataDome-enabled image
  • Snippets support enabled (-enable-snippets=true flag)
  • Secret volume mount (at /etc/nginx/secrets/)
❗️
  • Replace ${REGISTRY}/nginx-ingress-datadome:${NGINX_INGRESS_VERSION} with your image path from Step 1.
  • If different, adjust the deployment name (nginx-ingress) and namespace (-n nginx-ingress).
kubectl patch deployment nginx-ingress -n nginx-ingress --type='json' -p='[
  {"op": "replace", "path": "/spec/template/spec/containers/0/image", "value": "${REGISTRY}/nginx-ingress-datadome:${NGINX_INGRESS_VERSION}"},
  {"op": "add", "path": "/spec/template/spec/containers/0/args/-", "value": "-enable-snippets=true"},
  {"op": "add", "path": "/spec/template/spec/volumes", "value": [
    {"name": "datadome-secret", "secret": {"secretName": "datadome-ingress-controller-secret"}}
  ]},
  {"op": "add", "path": "/spec/template/spec/containers/0/volumeMounts", "value": [
    {"name": "datadome-secret", "mountPath": "/etc/nginx/secrets", "readOnly": true}
  ]}
]'

Kubernetes will perform a rolling update, gradually replacing old pods with new ones to avoid downtime.


FAQ

How can I monitor the rollout?

To monitor the deployment rollout:

kubectl rollout status deployment/nginx-ingress -n nginx-ingress

Wait until you see: deployment "nginx-ingress" successfully rolled out

You can also check pod status:

kubectl get pods -n nginx-ingress

How can I rollback?

If something goes wrong, you can rollback to the previous deployment:

kubectl rollout undo deployment/nginx-ingress -n nginx-ingress

This restores the previous image, args, and volume configuration.