search close

Kubernetes Reverse Proxy

access_time Updated Jun 20, 2021

Introduction

In this example, the Signal Sciences agent runs in a Docker sidecar and proxies all incoming requests for inspection before sending upstream to the application container.

Integrating the Signal Sciences Agent

The Signal Sciences Agent can be installed as a sidecar into each pod or as a service for some specialized needs. The recommended way of installing the Signal Sciences Agent in Kubernetes is by integrating the sigsci-agent into a pod as a sidecar. This just 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.

Getting and Updating the Signal Sciences Agent Container Image

The official signalsciences/sigsci-agent container image available from the Signal Sciences account on Docker Hub is the recommended place to get the image. If you want to build your own image or need to customize the image, then follow the sigsci-agent build instructions.

The documentation references 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 this case you should specify a 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 Signal Sciences Container Image

If you do choose to use the latest image, then you 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. To keep some consistency, 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):

- name: sigsci-agent
   image: signalsciences/sigsci-agent:latest
   imagePullPolicy: Never
   ...

Using a Versioned Signal Sciences Container Image

To use a specific version of the agent, then just replace latest with the agent version. You may also want to change imagePullPolicy: IfNotPresent in this case as the image should not change.

- name: sigsci-agent
   image: signalsciences/sigsci-agent:4.1.0
   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 Signal Sciences 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 the latest), apply a custom tag, then use that custom tag in the configuration. You will want to specify imagePullPolicy: Never so that local images are only updated manually. 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:

- name: sigsci-agent
   image: signalsciences/sigsci-agent:testing
   imagePullPolicy: Never
...

Configuring the Signal Sciences 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 (_) (e.g., 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 (ID and 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: Identifies the site that the agent is configured against
  • SIGSCI_SECRETACCESSKEY: The shared secret key to authenticate and authorize the agent

The credentials can be found by following these steps:

  1. Log into the Signal Sciences console
  2. Go to Agents Configurations “Configurations Menu”
  3. On the Agents page click “View Agent Keys”
  4. Copy down the Access Key and Secret Key as this will be used later agent-keys “Agent Keys”

Because of the sensitive nature of these values, it is recommended to use the builtin secrets functionality of Kubernetes. With this configuration, the agent will pull the values from the secrets data instead of reading hardcoded the 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.

Using secrets via environment variables is done using the valueFrom option instead of the value option such as follows:

env:
 - name: SIGSCI_ACCESSKEYID
   valueFrom:
     secretKeyRef:
       # Update "my-site-name-here" to the correct site 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 name or similar identifier
       name: sigsci.my-site-name-here
       key: secretaccesskey

The secrets functionality keeps secrets in various stores in Kubernetes. This documentation 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 with something like the following YAML:

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:

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

See the documentation on secrets for more details.

Agent Temporary Volume

For added security, it is recommended that the sigsci-agent container be executed with the root filesystem mounted read only. The agent, however, still needs to write some temporary files such as the socket file for RPC communication and some periodically updated files such as GeoIP 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. Typically this is just configured in the volumes section of a deployment.

volumes:
 - name: sigsci-tmp
   emptyDir: {}

Containers would then typically mount this volume at /sigsci/tmp:

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

Signal Science Agent as a Reverse Proxy in Front of a Web Application without the Signal Sciences Module

If the web application does not support a Signal Science Module (or installing a module is not desired), then the sigsci-agent container can be configured to run as a reverse proxy in front of the web application in the same pod.

Changing the Application Port and Replacing it with the Signal Sciences Agent

To configure Signal Sciences with this deployment type you must:

  • Change the port in which the web application listens (e.g., from 8000 to 8001 or similar)
  • Add the sigsci-agent container to the pod, configured in reverse proxy mode to listen on the original web application port and proxy requests to the new web application listener port
  • Add an emptyDir{} volume as a place for the sigsci-agent to write temporary data

The following set of changes reconfigures the web application originally using port 8000 to use an alternate port of 8001 adding the sigsci-agent as a reverse proxy listening on a the original web application port 8000 with an upstream of the new web application port 8000.

Change the Application Port to an Alternate Port

Change the application configuration (in this case the first argument) and the containerPort to an alternate port (was 8000):

...
      containers:
      # Example helloworld app running on port 8001 without sigsci configured
      - name: helloworld
        image: signalsciences/example-helloworld:latest
        imagePullPolicy: IfNotPresent
        args:
        - localhost:8001
        ports:
        - containerPort: 8001

Add the Signal Sciences Agent as a Reverse Proxy

...
      containers:
      # Example helloworld app running on port 8001 without sigsci configured
      - name: helloworld
        image: signalsciences/example-helloworld:latest
        imagePullPolicy: IfNotPresent
        args:
        - localhost:8001
        ports:
        - containerPort: 8001
      # Signal Sciences 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 the original web application port 8000
        # forwarding to the app on the alternate port 8001 as the upstream
        - name: SIGSCI_REVPROXY_LISTENER
          value: "http:{listener='http://127.0.0.1:8000',upstreams='http://127.0.0.1:8001',access-log='/dev/stdout'}"
        ports:
        - containerPort: 8000
        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

Adding the Signal Sciences Agent Temp Volume Definition to the Deployment

Finally, the agent temp volume needs to be defined for use by the other containers in the pod. This just uses the builtin emptyDir: {} volume type.

...
      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 Signal Sciences Agent as a Reverse Proxy

Alternatively, if the application listener should not (or cannot) be reconfigured in the pod, modify the Kubernetes service to point to the listener port exposed by the sigsci-agent reverse proxy instead of directly to the web application. The sigsci-agent can then be configured to proxy to the application port inside the pod.

The following set of changes adds the sigsci-agent as a reverse proxy listening on a new port 8001 with an upstream of the application port on 8000 and changes the service to point to the reverse proxy on port 8001 instead of directly to the application on port 8000:

Add the Signal Sciences Agent as a Reverse Proxy to Proxy to the Application Port

...
      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
      # Signal Sciences 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 the new service port 8001
        # forwarding to the app on 8000 as the upstream
        - name: SIGSCI_REVPROXY_LISTENER
          value: "http:{listener='http://127.0.0.1:8001',upstreams='http://127.0.0.1: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

Change the Service Definition to Point to the Signal Sciences 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.

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

Note: The above modification assumes that sigsci secrets were added to the system. Adding the Signal Sciences Agent Temp Volume Definition to the Deployment

Finally, the agent temp volume needs to be defined for use by the other containers in the pod. This just uses the builtin emptyDir: {} volume type.

...
      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: {}