How to Configure Appdome’s Docker Image for MobileBOT™ Defense

Last updated November 4, 2024 by Appdome

Now that you’ve completed the setup of your preferred server (e.g., GCP, Azure, AWS) and configured your WAF (e.g., Imperva), you’re ready to configure the Appdome Docker Image. This guide will walk you through the necessary steps to ensure that your Appdome MobileBOT™ Defense solution is properly integrated and operational within your Docker environment.

Appdome’s Docker Image is a custom solution designed to secure apps built on the Appdome platform with the Anti-Bot service enabled. This service operates within a Docker container based on Nginx. To facilitate its operation, users must supply an SSL certificate, configuration files and keys, and designated environment variables.

Prerequisites: Familiarity with Docker and UNIX-based machines is beneficial.

How Does It Work?

Based on Nginx and Lua, the service employs the Lua module to decrypt the payload and validate the signature, then it proxies the request to the target route as specified in the config file.

The module can be used with either the built-in LRU cache or with Redis, but it is recommended to use the built-in LRU to reduce the overhead of making the calls to Redis and ease the setup. If working in a cluster, it is necessary to use Redis to share storage across multiple instances.

Setup

The following environment variables are required to set up the service.

 

Environment Variable Name Required Description
REDIS Optional Only provide AD_REDIS_HOST if you intend to use it.
LOG_LEVEL Optional The default setting is warn. Available options include: debug, info, notice, warn, error, crit, alert, emerg. All logs are output to the stdout.
RESOLVER Mandatory Provide the resolver DNS server to use for discovering upstream servers.
PASSTHROUGH Optional A key that logs only headers but does not validate them.
USE_DEFAULT Optional If the default.json config file is passed in the configs folder and this variable is passed as true, only the default configuration will be used. This is meant for testing purposes without constantly updating the config file.
Note: For a Kubernetes server, the default DNS server IP is 192.168.0.10. For a pure Docker configuration, the default server IP is 127.0.0.11

1. Receive the JSON config file

  • Obtain the JSON config file from our Appdome support team. The files will be named after the taskID of that build. There may be multiple files, each corresponding to different tasks.

2. Modify the JSON config file

  • Add the following fields:
    • key: The filename of the key that is relative to the /home folder in your docker container used for validation.
    • target: The endpoint to which requests are forwarded. Make sure your DNS resolver resolves this address.
    • heartbeat_validity (optional): Time in seconds for how long the heartbeat remains valid.

Example:

[{

"key": "keys/your_key_file.key",

"target": "http://target_address",

"heartbeat_validity": 60

...

}]

3. Prepare the Docker Container:
– Ensure your Docker container has the necessary directories (`/home/configs` and `/home/keys`).

  • Configs Directory: This directory will store JSON files containing mobile anti-bot configurations provided by Appdome.
  • Keys Directory: This directory will store private keys used to validate the headers sent by Appdome.

Note: Ensure Key Matches. Verify that the key specified in the JSON config file correctly points to a key file located in the `/home/keys` directory within the Docker container.

Note: If you want to use only one config file for multiple task_ids for testing, rename the config file to default.json file and set the environment variable USE_DEFAULT=true. This setup is useful for initial testing but is not recommended for production if you regularly change the Anti-bot configuration.

4. Mount the JSON config file to the Docker Container

  • Use the `docker run` command with the `-v` option to bind mount the host directories to the container directories.

By following these steps, you’ll be able to correctly set up and mount the JSON config file to your Appdome Docker container.

Optional: How to Configure SSL & mTLS

If you want the Appdome Docker Image to handle SSL and mTLS, additional configuration is required. This includes passing environment variables and mounting certificates to the service.
Environment Variable Name Description
SSL_ON In order to enable the reverse proxy to handle SSL connections, you need to mark the SSL_ON=true. Make sure to mount SSL certificates to the container under /etc/nginx/certs/{ssl.crt, key.key}.
MTLS_ON In order to enable the reverse proxy to handle mTLS, you need to set both SSL_ON and MTLS_ON=true.
Make sure to mount the CA certificate that will be used for the mTLS under /etc/nginx/certs/ca.crt.
FINGERPRINTS If MTLS_ON=true the certificate fingerprints can be passed to allow only specific certificates identified by a SHA1 fingerprint. The value format should include a string of comma-separated values with a space following each comma as follows: asd, zxc, qwe

How to run Appdome Docker Image

Connect to your VM, and run the following commands:

  • Pull the docker image from our public repository:
docker pull public.ecr.aws/n2i7f1e2/appdome-waf:1.0.10
  • Run the docker image with the following command:
docker run -p 443:443 -p 80:80 -d \
-v "$(pwd)"/certs:/etc/nginx/certs \
-v "$(pwd)"/keys:/home/keys \
-v "$(pwd)"/configs:/home/configs \
-e REDIS=<redis address> \
-e PASSTHROUGH=false \
-e RESOLVER=<resolver address> \
-e SSL_ON=true \
-e MTLS_ON=true \
-e FINGERPRINTS=asd, zxc, qwe \
-e LOG_LEVEL=debug \
--restart unless-stopped \
public.ecr.aws/n2i7f1e2/appdome-waf:1.0.8

At this point, you have a machine that will run the Appdome Docker Image. Make sure that your application traffic is routing correctly to the Appdome Docker Image and that the Appdome Docker Image is passing the traffic correctly to the target.

Monitoring Docker Health

To ensure your Docker container is operational, it is essential to configure a health check endpoint within your system’s monitoring tools. Set up an endpoint in your health monitoring system to regularly check the /_health endpoint of the Docker container. This setup helps confirm that the Docker container is running correctly and is responsive. You can use any system that supports health checks, ensuring it aligns with your deployment environment and monitoring needs.

Note: The health check only verifies that the docker is up and running, but it does not confirm that the target is accessible. If you want to make sure that the connectivity between the reverse proxy and the target is working as expected, configure an additional health check that monitors the target connectivity.

Frequently Asked Questions (FAQ)

Question: Are timestamp and nonce enforcement enabled by default in Appdome’s Docker Image?
Answer: Yes, both timestamp and nonce enforcement are enabled by default to enhance security measures. If you wish to disable these features, set the environment variables DISABLE_TIMESTAMP_ENFORCE and DISABLE_NONCE_ENFORCE to “true”.

Log Information

Appdome’s Docker Image utilizes structured logging to ensure transparency and ease of monitoring. Logs are formatted as follows:

<timestamp> [<log level>]: [lua] <file><line number>: <function>: [<request_id>] [<client ip> - <user agent> - <request uri>] [<message>]

This format helps pinpoint issues with precision, tracking the logs back to the exact file, line number, and function where the event was logged. The inclusion of client IP, user agent, and request URI provides a comprehensive context for each entry.

Additional Options:

This section explains how to configure custom exit rules for handling session requests using the Appdome Docker Image. By utilizing the handle file, users can specify behavior for different scenarios based on the request headers.

Setting Up the Handle File

  • Provide a handle file under /home/lua/handle.lua.
  • This Lua script will determine the routing instructions (e.g., pass through or block) for each request based on the specified conditions.

Structure of the Handle File

  • To write custom exit rules, create the following folder structure:
    ➜  lua git:(master) ✗ tree .
    .
    ├── src
    │   └── handle.lua
    └── wrapper.lua

Writing Custom Rules in Handle.lua:

  • Implement functions within handle.lua for different request scenarios such as VALID, COMPROMISED, COULD_NOT_DECRYPT, and INVALID:
  • Each function should return a boolean indicating whether the request is allowed, a corresponding HTTP status code, and a response body if applicable.
    local M = {}
    -- Handle the response based on the case, returning the appropriate values
    -- First return value is a boolean indicating if the request is valid, the second is the status code and the third is the body
    -- @return boolean, number, string
    M.handle_response = function(ngx, case, external_ids)
      local cases = {
        ["VALID"] = function()
          ngx.log(ngx.DEBUG, "Valid request")
          return true
        end,
        ["COMPROMISED"] = function()
          -- extrernal_ids are comma separated string of ids
          ngx.log(ngx.DEBUG, "Compromised request")
          ngx.log(ngx.DEBUG, "External ids: " .. (external_ids or ""))
          return false, 400, ""
        end,
        ["COULD_NOT_DECRYPT"] = function()
          ngx.log(ngx.DEBUG, "Invalid request - could not decrypt signed message")
          return false, 400, ""
        end,
        ["INVALID"] = function()
          ngx.log(ngx.DEBUG, "Invalid request - derypted correctly but not valid or compromised")
          return false, 400, ""
        end,
        default = function()
          ngx.log(ngx.DEBUG, "Unknown case: " .. string(case))
          return false, 400, ""
        end,
      }
      -- Execute the matching case or the default
      local caseFunc = cases[case] or cases.default
      return caseFunc()
    end
    return M
    

Testing the Handle File

  • Use wrapper.lua to test the handle.lua script. This testing should be done using a plain Lua interpreter, independent of OpenResty, to ensure that the script operates correctly in isolation.
  • This testing step is vital to verify the script’s ability to manage all specified cases effectively and handle external IDs received from the requests:
    local handle = require("src.handle")
    local log = function(level, msg)
      print(string.format("[%s] %s", level, msg))
    end
    local check = function()
      local ngx = { log = log, DEBUG = "DEBUG", INFO = "INFO" }
      handle.handle_response(ngx, "VALID")
      handle.handle_response(ngx, "COULD_NOT_DECRYPT")
      handle.handle_response(ngx, "INVALID")
      handle.handle_response(ngx, "COMPROMISED")
    end
    check()

Related Articles:

How Do I Learn More?

If you have any questions, please send them our way at support.appdome.com or via the chat window on the Appdome platform.

Thank you!

Thanks for visiting Appdome! Our mission is to secure every app on the planet by making mobile app defense easy. We hope we’re living up to the mission with your project. If you don’t already have an account, you can sign up for free.

Appdome

Want a Demo?

Mobile Bot Defense

AlanWe're here to help
We'll get back to you in 24 hours to schedule your demo.