Tutorials

Mattermost Analytics with Tirreno

Mattermost does not directly offer user behavior analytics capabilities. To address this, we implement the Tirreno platform on top of Mattermost. This integration allows us to maintain an extended audit trail, monitor login locations, and protect accounts from sharing or takeover. We will perform data capturing by modifying the existing Nginx server configuration without the need to change the Mattermost codebase.

Requirements

Attention

Before implementing the provided Nginx configuration in a production environment, testing it in a development or staging environment is crucial. Using these settings without prior testing and validation is not recommended and is at your own risk.

Configuration Nginx with Tirreno

Mirroring of the original request allows the collection of information about user events and transmits them to the Tirreno API.

  1. To perform this, add location = /mirror {...} to the server section in the config and append mirror /mirror; directives to all existing location sections.

location = /mirror {
    internal;

    set $args "";
    set $new_query_string "userName=$cookie_MMUSERID&ipAddress=$remote_addr&userAgent=$http_user_agent&httpReferer=$http_referer&httpMethod=$request_method&url=$request_uri&eventTime=$php_timestamp&browserLanguage=$http_accept_language";

    proxy_pass https://tirreno.yourcompany.com; # Replace with your Tirreno URL
    proxy_method POST;
    rewrite ^ /sensor/ break;

    proxy_set_body $new_query_string;
    proxy_set_header Content-Type "application/x-www-form-urlencoded";
    proxy_set_header Api-Key "XXXXXXXXXXXXXXXXXXXXXXXXX"; # Replace with your Tirreno API key
    proxy_pass_request_body off;
}
  1. Set the Tirreno URL in proxy_pass (ex. https://tirreno.yourcompany.com)

  2. Set Api-Key with your current Tirreno API key (copy and paste from API section of Tirreno console).

Restart Nginx & Checking Results

After adjusting the Mattermost Nginx config, check the syntax with sudo nginx -t and apply changes by restarting the server with sudo systemctl restart nginx. Voilà! Open the Mattermost client and perform a login, then visit the Tirreno console and check the event details.

Example of Nginx Configuration File

server {
    listen 80;
    server_name mattermost.yourcompany.com;  # Replace with Mattermost host

    return 301 https://$server_name$request_uri;
}

map $time_iso8601 $formatted_datetime {
    "~^(?<date>\d{4}-\d{2}-\d{2})T(?<time>\d{2}:\d{2}:\d{2})" "$date $time";
}

map $msec $milliseconds {
    '~^\d+\.(?<millis>\d+)$' $millis;
}

map $formatted_datetime $php_timestamp {
    "~^(.+)$" "$formatted_datetime.$milliseconds";
}

server {
    listen 443 ssl http2;
    server_name mattermost.yourcompany.com; # Replace with Mattermost host

    ssl_certificate /etc/letsencrypt/live/mattermost.yourcompany.com/fullchain.pem; # Replace with you certificate path
    ssl_certificate_key /etc/letsencrypt/live/mattermost.yourcompany.com/privkey.pem; # Replace with you certificate path
    ssl_session_timeout 1d;
    ssl_session_cache shared:MozSSL:10m;
    ssl_session_tickets off;

    ssl_protocols TLSv1.2 TLSv1.3;
    ssl_ciphers 'ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES256-GCM-SHA384:ECDHE-RSA-AES256-GCM-SHA384:ECDHE-ECDSA-CHACHA20-POLY1305:ECDHE-RSA-CHACHA20-POLY1305:DHE-RSA-AES128-GCM-SHA256:DHE-RSA-AES256-GCM-SHA384';
    ssl_prefer_server_ciphers off;

    add_header Strict-Transport-Security "max-age=63072000" always;

    location / {
        proxy_pass http://backend; # Replace with IP and port if you use container deployment
        proxy_http_version 1.1;

        proxy_set_header Upgrade $http_upgrade;
        proxy_set_header Connection "upgrade";
        proxy_set_header Host $host;
        proxy_set_header X-Real-IP $remote_addr;
        proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
        proxy_set_header X-Forwarded-Proto $scheme;
        proxy_set_header X-Frame-Options SAMEORIGIN;

        # Websocket support
        proxy_set_header Upgrade $http_upgrade;
        proxy_set_header Connection "upgrade";

        mirror /mirror;
    }

    location = /mirror {
        internal;

        set $args "";
        set $new_query_string "userName=$cookie_MMUSERID&ipAddress=$remote_addr&userAgent=$http_user_agent&httpReferer=$http_referer&httpMethod=$request_method&url=$request_uri&eventTime=$php_timestamp&browserLanguage=$http_accept_language";

        proxy_pass https://tirreno.yourcompany.com; # Replace with your Tirreno URL
        proxy_method POST;
        rewrite ^ /sensor/ break;

        proxy_set_body $new_query_string;
        proxy_set_header Content-Type "application/x-www-form-urlencoded";
        proxy_set_header Api-Key "XXXXXXXXXXXXXXXXXXXXXXXXX"; # Replace with your Tirreno API key
        proxy_pass_request_body off;
    }
}

Troubleshooting

Time format

The Tirreno API requires the Y-m-d H:i:s.u format for eventTime. As Nginx does not directly allow timestamp format manipulation, we use the map directive to convert the time to the appropriate format as per Example. Also, setting the timezone to UTC is recommended if your server is not already in UTC. Ensure that Nginx or its environment is configured to use UTC. The env TZ=UTC directive may be used in the global Nginx.conf.

User name

By default Mattermost is providing only internal usernames. To find actual user names check Mattermost admin console at https://mattermost.yourcompany.com/admin_console/user_management/users and compare MMUSERID with the user’s name and email.

Your Tirreno Adventure Awaits

This exercise is just one small example of what you can achieve with the Tirreno platform.

Tirreno is the easiest way to get started with security user analytics. We offer an open-source version of Tirreno, available for free on GitHub.