NGINX Module

Created:
June 13, 2024
Updated:
July 9, 2024

The FireTail NGINX module is a dynamic module that integrates with the FireTail platform to enhance your API's logging and validation capabilities.

Local Development

Use the Dockerfile to build the Firetail NGINX module, install it in an NGINX Docker image, and set up a custom nginx.conf and index.html.

To get started with the Docker setup:

1. Clone the repository:


git clone git@github.com:FireTail-io/firetail-nginx-module.git
cd firetail-nginx-module

2. Build the Docker image:


docker build -t firetail-nginx . --target firetail-nginx-dev -f dev/Dockerfile

3. Run the Docker container:


docker run -p 8080:80 firetail-nginx

When you make a request to localhost:8080, you may see a log entry like:


2023/07/14 11:44:37 [debug] 29#29: *1 Status code from POST request to Firetail /logs/bulk endpoint: 401

This indicates that the Firetail NGINX Module is receiving 401 responses due to an unconfigured API token. To resolve this, update the nginx.conf with a valid FireTail logs API token:


firetail_api_token "YOUR-API-TOKEN";

Request Validation

To demonstrate request validation, a POST /proxy/profile/{username}/comment operation is defined in the provided appspec.yml, with one profile defined in the provided nginx.conf: POST /proxy/profile/alice/comment. A proxy_pass directive is used to forward requests to /profile/alice/comment as the request body validation will not occur on locations where the return directive is used.

Making a curl request to POST /profile/alice/comment should yield the following result, which validates successfully against the provided appspec:


curl localhost:8080/proxy/profile/alice/comment -X POST -H 
"Content-Type: application/json" -d '{"comment":"Hello world!"}'
{"message":"Success!"}

If you alter the request body in any way that deviates from the appspec, you will receive an error response from the Firetail nginx module:


curl localhost:8080/proxy/profile/alice/comment -X 
POST -H "Content-Type: application/json" -d '{"comment":12345}'
{"code":400,"title":"something's wrong with your request body",
"detail":"the request's body did not match your appspec: request body has an error: 
doesn't match the schema: Error at \"/comment\": field must be set to string 
or not be present\nSchema:\n  {\n    \"type\": \"string\"\n  }\n\nValue:\n  \"number, integer\"\n"}


Response Validation

To demonstrate response validation, a GET /profile/{username} operation is defined in the provided appspec.yml, and two profiles are defined in the provided nginx.conf: GET /profile/alice and GET /profile/bob.

Making a curl request to GET /profile/alice should yield the following result, which validates successfully against the provided appspec, as it returns only Alice's username and friend count:


curl localhost:8080/profile/alice
{"username":"alice", "friends": 123456789}

Making a curl request to GET /profile/bob will yield a different result, as the response body defined in our nginx.conf erroneously includes Bob's address. This does not validate against our appspec, so the response body is overwritten by the FireTail middleware, which can protect Bob from having his personally identifiable information disclosed by our faulty application. For the purposes of this demo, the FireTail library's debugging responses are enabled, providing an explanation of the problem:


curl localhost:8080/profile/bob
{
    "code": 500,
    "title": "internal server error",
    "detail": "the response's body did not match your appspec: 
    response body doesn't match the schema: property \"address\" is unsupported\nSchema:\n  
    {\n    \"additionalProperties\": false,\n    \"properties\": {\n      \"friends\": 
    {\n        \"minimum\": 0,\n        \"type\": \"integer\"\n      },\n      \"username\": 
    {\n        \"type\": \"string\"\n      }\n    },\n    \"type\": \"object\"\n  }\n\nValue:\n  
    {\n    \"address\": \"this shouldn't be public!\",\n    
    \"friends\": 123456789,\n    \"username\": \"bob\"\n  }\n"
}

VSCode Setup

For local development with VSCode:

1. Download and configure the NGINX tarball:


curl -O http://nginx.org/download/nginx-1.24.0.tar.gz
tar xvzf nginx-1.24.0.tar.gz
cd nginx-1.24.0
./configure

2. Install VSCode's Microsoft C/C++ Extension. Ensure it can find your NGINX headers. If not, adjust the includePath in settings:

  • Open settings: C/C++: Edit configurations (UI)
  • Add to includePath: ${workspaceFolder}/**

3. Install dependencies using vcpkg:


vcpkg install pcre2 curl json-c


Compile Module

To compile the FireTail NGINX module, follow the NGINX documentation on compiling dynamic modules.

1. Clone the repository:


git clone git@github.com:FireTail-io/firetail-nginx-module.git
cd firetail-nginx-module

2. Download and extract the matching NGINX release:


curl -O http://nginx.org/download/nginx-1.24.0.tar.gz
tar xvzf nginx-1.24.0.tar.gz


3. Generate a makefile to build the dynamic module:


cd nginx-1.24.0
./configure --with-compat --add-dynamic-module=../src


4. Install the Firetail NGINX Module's dependencies, curl and json-c, before running:


make modules



Configuration

The FireTail NGINX module provides several directives to configure its behavior. To configure the Firetail NGINX Module:

  • Modify your nginx.conf to load the module using the load_module directive:

load_module modules/ngx_firetail_module.so;

To avoid placing plaintext credentials in your nginx.conf, use a module like ngx_http_lua_module and instead make use of system environment variables.

Note: Refer to dev/nginx.conf for an example configuration.

Here are the some directives that can be used:

  • firetail_api_token: This directive defines the API token the FireTail NGINX module will use when reporting logs to the FireTail SaaS platform. You need to create an API token in the FireTail platform and provide it using this directive. Learn how to generate an API token.
  • firetail_url: This directive determines the endpoint to which the FireTail NGINX module sends logs. By default, logs are sent to the EU region of the FireTail platform. If you are using a different region, configure this directive accordingly using the firetail_url directive.

http {
  firetail_api_token "YOUR-API-TOKEN";
  firetail_url "https://api.logging.eu-west-1.prod.firetail.app/logs/bulk";
}