Mattermost

Configuration for the Mattermost/Mostlymatter instant messaging platform.

Mattermost logs failed login attempts, but only when the username exists. Depending on your needs, you can either use those logs, or read the logs of the reverse proxy in front of it if you want to check for failed attempts on inexisting accounts too. That's what I would recommend.

Option 1: Reverse proxy logs

The HTTP code sent after a failed login is 401, Unauthorized.

The request to authenticate is a POST on /api/v4/users/login.

This example makes the assumption that a function named banFor is defined. See the ipset example. It also makes the assumption that there is a pattern named ip.

A regex for nginx can look like this:

@'^<ip> .* domain.name "POST /api/v\d/users/login HTTP/..." 401 '

Adjust domain.name according to your domain.

Example:

{
  streams: {
    nginx: {
      cmd: ['...'], // see ./nginx.md
      filters: {
        directus: {
          regex: [
            @'^<ip> .* mattermost.example.com "POST /api/v\d/users/login HTTP/..." 401 '
          ],
          retry: 3,
          retryperiod: '6h',
          actions: banFor('48h'),
        },
      },
    },
  },
}

Option 2: Application logs

Mattermost logs a line with the info loglevel like this:

A user tried to sign in, which matched a Mattermost account, but the password was incorrect. caller="app/authentication.go:398" path=/api/v4/users/login request_id=abcdefghijklmnopqrsrtuvwxy ip_addr=X.X.X.X user_id= method=POST username=examplelogin

Please make sure that the logged address is not one from your private network! Docker addresses typically are in 172.X.X.X, etc. By default, Mattermost doesn't trust the X-Forwarded-For header. You will most probably encounter this problem if Mattermost is not configured properly. Be sure to set the trusted proxy variable.

We can regexify it like this:

user tried to sign in.* but the password was incorrect.* ip_addr=<ip>

Example:

{
  streams: {
    mattermost: {
      cmd: ['docker', 'logs', '-f', '-n0', 'mattermost-api'],
      filters: {
        regex: [
          @'user tried to sign in.* but the password was incorrect.* ip_addr=<ip>'
        ],
        retry: 4,
        retryperiod: '2h',
        actions: banFor('48h'),
      }
    }
  }
}

This example makes the assumption that a function named banFor is defined. See the ipset example. It also makes the assumption that there is a pattern named ip.