Kubernetes Agent + Ingress Controller + Module

In this example, the Next-Gen WAF agent is installed as a Docker sidecar, communicating with the Next-Gen WAF dynamic module for NGINX installed on an ingress-nginx Kubernetes ingress controller.

NOTE: The upstream ingress-nginx repository has been archived. Fastly's ingress controller image is now built on the Chainguard-maintained fork, which provides continued security maintenance. The installation steps remain the same.

Integrating the Next-Gen WAF agent into an ingress controller

In addition to installing the Next-Gen WAF per application, it is also possible to install the Next-Gen WAF into a Kubernetes ingress controller that will receive all external traffic to your applications. Doing this is similar to installing into an application with a Next-Gen WAF module:

  • Install and configure the Next-Gen WAF module into the ingress controller.
  • Add the sigsci-agent container to the ingress pod and mount a sigsci-agent volume.
  • Add an emptyDir{} volume as a place for the sigsci-agent to write temporary data.

Kubernetes NGINX ingress controller

The Kubernetes NGINX Ingress Controller is an NGINX based implementation for the ingress API. Next-Gen WAF supports a dynamic module for NGINX. This enables you to easily wrap the existing ingress-nginx controller to install the Next-Gen WAF module.

Wrap the base nginx-ingress-controller to install the Next-Gen WAF module

Wrapping the nginx-ingress-controller is done by using the base controller and installing the Next-Gen WAF dynamic NGINX module. A prebuilt container can be pulled from Docker Hub with: docker pull signalsciences/sigsci-nginx-ingress-controller-chainguard:latest

Installation

There are two methods for installing:

Prerequisites

Copy the agent keys for the site that you want the agent to be able to access. You will use the agent keys when configuring the Next-Gen WAF agent package.

Install via Helm using overrides

The following steps cover installing sigsci-nginx-ingress-controller-chainguard + sigsci-agent via the official ingress-nginx charts with an override file.

  1. Add the ingress-nginx repository:

    $ helm repo add ingress-nginx https://kubernetes.github.io/ingress-nginx
  2. In the sigsci-values.yaml file, add the agent keys as SIGSCI_ACCESSKEYID and SIGSCI_SECRETACCESSKEY.

  3. Install with the release name my-ingress in the default namespace:

    $ helm install -f values-sigsci.yaml my-ingress ingress-nginx/ingress-nginx

    You can specify a namespace with -n flag:

    $ helm install -n NAMESPACE -f values-sigsci.yaml my-ingress ingress-nginx/ingress-nginx
  4. After a few minutes, the agent will be listed on the Agents page in the Next-Gen WAF control panel and the Deployment page in the Fastly control panel.

  5. Create an Ingress resource. This step will vary depending on setup and supports a lot of configurations. Official documentation can be found regarding Basic usage - host based routing.

    Here is an example Ingress file:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    apiVersion: networking.k8s.io/v1
    kind: Ingress
    metadata:
    annotations:
    kubernetes.io/ingress.class: nginx
    nginx.ingress.kubernetes.io/rewrite-target: /
    name: hello-kubernetes-ingress
    #namespace: SET THIS IF NOT IN DEFAULT NAMESPACE
    spec:
    rules:
    - host: example.com
    http:
    paths:
    - pathType: Prefix
    path: /testpath
    backend:
    service:
    name: NAME OF SERVICE
    port:
    number: 80

Helm upgrade with override file

  1. In the sigsci-values.yaml file, update the sigsci-nginx-ingress-controller to the latest version to update the ingress-nginx charts:

    controller:
    # Replaces the default nginx-controller image with a custom image that contains the Next-Gen WAF NGINX module
    image:
    repository: signalsciences/sigsci-nginx-ingress-controller-chainguard
    tag: "latest"
    pullPolicy: IfNotPresent
  2. Run helm upgrade with the override file. This example is running helm upgrade against the my-ingress release created in the previous section:

    $ helm upgrade -f sigsci-values.yaml my-ingress ingress-nginx/ingress-nginx

    or

    $ helm upgrade -f sigsci-nginxinc-values.yaml my-ingress ingress-nginx/ingress-nginx

    If ingress is not in default namespace, use -n to specify namespace:

    $ helm upgrade -n NAMESPACE -f sigsci-values.yaml my-ingress ingress-nginx/ingress-nginx

    or

    $ helm upgrade -n NAMESPACE -f sigsci-nginxinc-values.yaml my-ingress ingress-nginx/ingress-nginx

Uninstall release

  1. Uninstall release my-ingress.

    $ helm uninstall my-ingress
  2. If it's not in the default namespace, use -n to specify the namespace:

    $ helm uninstall -n NAMESPACE my-ingress

Install with custom file

Integrating the Next-Gen WAF agent

Refer to the Agent container image integration.

The NGINX ingress controller is installed with the mandatory.yaml file. This file contains a modified template of the Generic Ingress Controller Deployment. The main additions are:

  1. Change the ingress container to load the custom ingress container and add Volume mounts for socket file communication between the Module/ingress container and Agent sidecar container:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    ...
    containers:
    - name: nginx-ingress-controller
    image: signalsciences/sigsci-nginx-ingress-controller-chainguard:latest
    ...
    volumeMounts:
    - name: sigsci-tmp
    mountPath: /sigsci/tmp
    ...
  2. Load the Next-Gen WAF module in the NGINX configuration file (nginx.conf) via ConfigMap:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    kind: ConfigMap
    apiVersion: v1
    data:
    main-snippet: load_module /usr/lib/nginx/modules/ngx_http_sigsci_nxo_module-1.17.7.so;
    http-snippet: sigsci_agent_host unix:/sigsci/tmp/sigsci.sock;
    metadata:
    name: nginx-configuration
    namespace: ingress-nginx
    labels:
    app.kubernetes.io/name: ingress-nginx
    app.kubernetes.io/part-of: ingress-nginx
  3. Add a container for the Next-Gen WAF agent:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    ...
    containers:
    ...
    # Next-Gen WAF agent running in default RPC mode
    - name: sigsci-agent
    image: signalsciences/sigsci-agent:latest
    imagePullPolicy: IfNotPresent
    env:
    - name: SIGSCI_ACCESSKEYID
    valueFrom:
    secretKeyRef:
    # This secret needs added (see docs on sigsci secrets)
    name: sigsci.my-site-name-here
    key: accesskeyid
    - name: SIGSCI_SECRETACCESSKEY
    valueFrom:
    secretKeyRef:
    # This secret needs added (see docs on sigsci secrets)
    name: sigsci.my-site-name-here
    key: secretaccesskey
    securityContext:
    # The sigsci-agent container should run with its root filesystem read only
    readOnlyRootFilesystem: true
    volumeMounts:
    # Default volume mount location for sigsci-agent writeable data (do not change mount path)
    - name: sigsci-tmp
    mountPath: /sigsci/tmp
    ...
  4. Define the volume used above:

    ...
    volumes:
    # Define a volume where sigsci-agent will write temp data and share the socket file,
    # which is required with the root filesystem is mounted read only
    - name: sigsci-tmp
    emptyDir: {}
    ...

Setup

The mandatory.yaml file creates the resources in the ingress-nginx namespace. If using Kubernetes Secrets to store the agent access keys, you will need to create the namespace and access keys before running the mandatory.yaml file.

  1. Set the name for the secrets for the agent keys in mandatory.yaml.

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    ...
    env:
    - name: SIGSCI_ACCESSKEYID
    valueFrom:
    secretKeyRef:
    # This secret needs added (see docs on sigsci secrets)
    name: sigsci.my-site-name-here
    key: accesskeyid
    - name: SIGSCI_SECRETACCESSKEY
    valueFrom:
    secretKeyRef:
    # This secret needs added (see docs on sigsci secrets)
    name: sigsci.my-site-name-here
    key: secretaccesskey
    ...
  2. Pull or build the NGINX ingress + Signal Sciences Module container. Set any preferred registry and repository name, and set the image to match in mandatory.yaml:

    $ docker pull signalsciences/sigsci-nginx-ingress-controller-chainguard:latest
  3. Deploy using modified Generic Deployment:

    $ kubectl apply -f mandatory.yaml
  4. Create the service to expose the Ingress Controller. The steps necessary are dependent on your cloud provider. Official instructions can be found at https://kubernetes.github.io/ingress-nginx/deploy/#environment-specific-instructions.

    Below is an example service.yaml file:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    kind: Service
    apiVersion: v1
    metadata:
    name: ingress-nginx
    namespace: ingress-nginx
    spec:
    externalTrafficPolicy: Cluster
    selector:
    app.kubernetes.io/name: ingress-nginx
    type: LoadBalancer
    ports:
    - name: http
    port: 80
    targetPort: http
    - name: https
    port: 443
    targetPort: https
  5. Create the Ingress Resource. Below is an example Ingress Resource:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    apiVersion: extensions/v1
    kind: Ingress
    metadata:
    name: test-ingress
    namespace: ingress-nginx
    annotations:
    nginx.ingress.kubernetes.io/rewrite-target: /
    spec:
    rules:
    - http:
    paths:
    - path: /testpath
    backend:
    serviceName: nginx
    servicePort: 80