Kubernetes reverse proxy

IMPORTANT

This guide only applies to Next-Gen WAF customers with access to the Next-Gen WAF control panel. If you have access to the Next-Gen WAF product in the Fastly control panel, you can only deploy the Next-Gen WAF with the Edge WAF deployment method.

In this example, the Next-Gen WAF agent runs in a sidecar container and proxies all incoming requests for inspection before sending them upstream to the application container.

Integrating the Next-Gen WAF agent

The Next-Gen WAF agent can be installed as a sidecar into each pod or as a service for some specialized needs.

The recommended way of installing the Next-Gen WAF agent in Kubernetes is by integrating the sigsci-agent into a pod as a sidecar. This means adding the sigsci-agent as an additional container to the Kubernetes pod. As a sidecar, the agent will scale with the app/service in the pod instead of having to do this separately. However, in some situations, it may make more sense to install the sigsci-agent container as a service and scale it separately from the application.

The sigsci-agent container can be configured in various ways depending on the installation type and module being used.

You can use the preStop container hook to slow the pod's shutdown and ensure drain timeouts are met.

1
2
3
4
5
preStop:
exec:
command:
- sleep
- "30"

By default, the agent prioritizes quick start up and performance readiness for preliminary inspection. However, quick startup isn't always desirable if you only want the agent to inspect traffic after loading your rules and configuration data. If you want to delay agent startup, consider configuring a startup probe.

Getting and updating the agent container image

An official signalsciences/sigsci-agent container image is available on Docker Hub.

Alternatively, if you want to build your own image or need to customize the image, then follow the sigsci-agent build instructions.

These instructions reference the latest version of the agent with imagePullPolicy: Always, which will pull the latest agent version even if one already exist locally. This is so the documentation does not fall out of date and anyone using this will not have an agent that stays stagnant. However, this may not be what if you need to keep installations consistent or on a specific version of the agent. In these cases, you should specify an agent version. Images on Docker Hub are tagged with their versions and a list of versions is available on Docker Hub.

Whether you choose to use the latest image or a specific version, there are a few items to consider to keep the agent up-to-date.

Using the latest container image

If you do choose to use the latest image, then you will want to consider how you will keep the agent up to date.

  • If you have used the imagePullPolicy: Always option, then the latest image will be pulled on each startup and your agent will continue to get updates.

  • Alternatively, you may instead choose to manually update the local cache by periodically forcing a pull instead of always pulling on startup:

    $ docker pull signalsciences/sigsci-agent:latest

    Then, use latest with imagePullPolicy: Never set in the configuration so that pulls are never done on startup (only manually as above):

    1
    2
    3
    4
    - name: sigsci-agent
    image: signalsciences/sigsci-agent:latest
    imagePullPolicy: Never
    ...

Using a versioned container image

To use a specific version of the agent, replace latest with the agent version (represented here by x.xx.x). You may also want to change imagePullPolicy: IfNotPresent in this case as the image should not change.

1
2
3
4
- name: sigsci-agent
image: signalsciences/sigsci-agent:x.xx.x
imagePullPolicy: IfNotPresent
...

This will pull the specified agent version and cache it locally. If you use this method, then it is recommended that you parameterize the agent image, using Helm or similar, so that it is easier to update the agent images later on.

Using a custom tag for the container image

It is also possible to apply a custom tag to a local agent image. To do this, pull the agent image (by version or use latest), apply a custom tag, then use that custom tag in the configuration. You will need to specify imagePullPolicy: Never so local images are only updated manually. After doing so, you will need to periodically update the local image to keep the agent up-to-date.

For example:

$ docker pull signalsciences/sigsci-agent:latest
$ docker tag signalsciences/sigsci-agent:latest signalsciences/sigsci-agent:testing

Then use this image tag in the configuration:

1
2
3
4
- name: sigsci-agent
image: signalsciences/sigsci-agent:testing
imagePullPolicy: Never
...

Configuring the agent container

Agent configuration is normally done via the environment. Most configuration options are available as environment variables. Environment variables names have the configuration option name all capitalized, prefixed with SIGSCI_ and any dashes (-) changed to underscores (_). For example, the max-procs option would become the SIGSCI_MAX_PROCS environment variable. For more details on what options are available, see the Agent Configuration documentation.

The sigsci-agent container has a few required options that need to be configured:

  • Agent credentials (Agent Access Key and Agent Secret Key).
  • A volume to write temporary files.

Agent credentials

The sigsci-agent credentials are configured with two environment variables. These variables must be set or the agent will not start.

  • SIGSCI_ACCESSKEYID: The Agent Access Key identifies which site (also known as workspace) in the Next-Gen WAF control panel that the agent is configured for.
  • SIGSCI_SECRETACCESSKEY: The Agent Secret Key is the shared secret key to authenticate and authorize the agent.

Because of the sensitive nature of these values, we recommend you use the built in secrets functionality of Kubernetes. With this configuration, the agent will pull the values from the secrets data instead of reading hardcoded values into the deployment configuration. This also makes any desired agent credential rotation easier to manage by having to change them in only one place.

Use the valueFrom option instead of the value option to use the secrets functionality. For example:

1
2
3
4
5
6
7
8
9
10
11
12
13
env:
- name: SIGSCI_ACCESSKEYID
valueFrom:
secretKeyRef:
# Update my-site-name-here to the correct site (workspace) name or similar identifier
name: sigsci.my-site-name-here
key: accesskeyid
- name: SIGSCI_SECRETACCESSKEY
valueFrom:
secretKeyRef:
# Update my-site-name-here to the correct site (workspace) name or similar identifier
name: sigsci.my-site-name-here
key: secretaccesskey

The secrets functionality keeps secrets in various stores in Kubernetes. This guide uses the generic secret store in its examples, however any equivalent store can be used. Agent secrets can be added to the generic secret store using YAML similar to the following example:

1
2
3
4
5
6
7
apiVersion: v1
kind: Secret
metadata:
name: sigsci.my-site-name-here
stringData:
accesskeyid: 12345678-abcd-1234-abcd-1234567890ab
secretaccesskey: abcdefg_hijklmn_opqrstuvwxy_z0123456789ABCD

This can also be created from the command line with kubectl such as with the following example:

1
2
3
$ kubectl create secret generic sigsci.my-site-name-here \
--from-literal=accesskeyid=12345678-abcd-1234-abcd-1234567890ab \
--from-literal=secretaccesskey=abcdefg_hijklmn_opqrstuvwxy_z0123456789ABCD

Additional information about Kubernetes secrets functionality can be found in the Kubernetes documentation.

Agent temporary volume

For added security, we recommended the sigsci-agent container be executed with the root filesystem mounted as read only. However, the agent still needs to write some temporary files such as the socket file for RPC communication and some periodically updated files such as geolocation data.

To accomplish this with a read only root filesystem, there needs to be a writeable volume mounted. This writeable volume can also be shared to expose the RPC socket file to other containers in the same pod.

The recommended way of creating a writeable volume is to use the builtin emptyDir volume type. This is typically configured in the volumes section of a deployment, as shown in the following example:

1
2
3
volumes:
- name: sigsci-tmp
emptyDir: {}

Containers will then mount this volume at /sigsci/tmp:

1
2
3
volumeMounts:
- name: sigsci-tmp
mountPath: /sigsci/tmp

The default in the official agent container image is to have the temporary volume mounted at /sigsci/tmp. If this needs to be moved for the agent container, then the following agent configuration options should also be changed from their defaults to match the new mount location:

  • rpc-address defaults to /sigsci/tmp/sigsci.sock
  • shared-cache-dir defaults to /sigsci/tmp/cache

Next-Gen WAF agent as a reverse proxy in front of a web application without the Next-Gen WAF module

If your web application does not support a Next-Gen WAF module (or you prefer not to install a module), then you can configure the sigsci-agent container to run as a reverse proxy in front of the web application in the same pod.

To configure the Next-Gen WAF agent to run in reverse proxy mode in a sidecar container, you must:

  • Add the sigsci-agent container to the pod, configured in reverse proxy mode to:

    • listen for incoming requests (on a new port or by reconfiguring your application or Kubernetes service accordingly)
    • proxy requests to your web application container
  • Add an emptyDir{} volume as a place for the sigsci-agent to write temporary data.

The following configuration exposes an example application (helloworld) on port 8000, adding the sigsci-agent as a reverse proxy listener on a new port 8001 with an upstream of the example web application port 8000.

Add the Next-Gen WAF agent as a reverse proxy

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
29
30
31
32
33
34
35
36
37
38
39
40
...
containers:
# Example helloworld app running on port 8000 without sigsci configured
- name: helloworld
image: signalsciences/example-helloworld:latest
imagePullPolicy: IfNotPresent
args:
- localhost:8000
ports:
- containerPort: 8000
# Next-Gen WAF agent running in reverse proxy mode (SIGSCI_REVPROXY_LISTENER configured)
- name: sigsci-agent
image: signalsciences/sigsci-agent:latest
imagePullPolicy: Always
env:
- name: SIGSCI_ACCESSKEYID
valueFrom:
secretKeyRef:
name: sigsci.my-site-name-here
key: accesskeyid
- name: SIGSCI_SECRETACCESSKEY
valueFrom:
secretKeyRef:
name: sigsci.my-site-name-here
key: secretaccesskey
# Configure the revproxy listener to listen on a new port 8001
# forwarding to the app on the original port 8000 as the upstream
- name: SIGSCI_REVPROXY_LISTENER
value: "http:{listener='http://0.0.0.0:8001',upstreams='http://0.0.0.0:8000',access-log='/dev/stdout'}"
ports:
- containerPort: 8001
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
# NOTE: Also change `SIGSCI_SHARED_CACHE_DIR` (default `/sigsci/tmp/cache`)
# if mountPath is changed, but best not to change.
- name: sigsci-tmp
mountPath: /sigsci/tmp
NOTE

The above modification assumes that sigsci secrets were added to the system.

Adding the Next-Gen WAF agent temp volume definition to the deployment

You must define the agent temp volume for use by the other containers in the pod. This example uses the builtin emptyDir: {} volume type.

1
2
3
4
5
6
...
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: {}

Changing the service definition and adding the Next-Gen WAF agent as a reverse proxy

In the example above, the sigsci-agent reverse proxy listens on a new port, leaving the original application listener in place. You may wish for requests to be routed to the sigsci-agent at the original application port to make the agent addition as seamless as possible. One way to do this is to modify the Kubernetes service definition to route traffic to the sigsci-agent reverse proxy listener port instead of directly to the web application.

Change the service definition to point to the Next-Gen WAF agent port

Change the service targetPort from pointing directly to the application, to instead point to the sigsci-agent reverse proxy listener port. The sigsci-agent will then proxy to the application port:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
apiVersion: v1
kind: Service
metadata:
name: helloworld
labels:
app: helloworld
spec:
ports:
- name: http
port: 8000
# Target is now sigsci-agent on port 8001
targetPort: 8001
selector:
app: helloworld
type: LoadBalancer
Was this guide helpful?

Do not use this form to send sensitive information. If you need assistance, contact support. This form is protected by reCAPTCHA and the Google Privacy Policy and Terms of Service apply.