Skip to content

Commit

Permalink
feat: Modify logger to log to file that supports fail2ban (#284)
Browse files Browse the repository at this point in the history
  • Loading branch information
StevenJCorreia committed Aug 22, 2022
1 parent 21ef850 commit 6429e22
Show file tree
Hide file tree
Showing 12 changed files with 425 additions and 7,842 deletions.
2 changes: 2 additions & 0 deletions .gitignore
@@ -1,5 +1,7 @@
node_modules
docker-compose.override.yml

/logs

.idea
.DS_Store
73 changes: 73 additions & 0 deletions README.md
Expand Up @@ -44,6 +44,79 @@ docker-compose up -d

Demo user: demo@demo.demo demo

### Logging

Planka currently allows you to expose the applciation's logfile directory to the host machine via a shared volume. This feature is not enabled by default.

To expose the logfile director to the host machine, add the item `./logs/:/app/logs/` under `services.planka.volumes`.

Note that the directory to the left of the semicolon is regarding the host machine while the directory to hte right of the semicolon is regarding the Docker container.

For example, in the above step, `./logs/:/app/logs/` will create the folder `logs` in the same directory where the `docker-compose.yml` file lives.

### Rotating Logs

logrotate is designed to ease administration of systems that generate large numbers of log files. It allows automatic rotation, compression, removal, and mailing of log files. Each log file may be handled daily, weekly, monthly, or when it grows too large.

#### Setup logrotate for Planka logs

Create a file in `/etc/logrotate.d` named `planka` with the following contents:

```
/path/to/planka/logs/planka.log {
daily
missingok
rotate 14
compress
delaycompress
notifempty
create 640 root adm
sharedscripts
}
```

Ensure to replace logfile directory with your installation’s `/logs/planka.log` location.

Restart the logrotate service.

### Fail2ban

Fail2ban is a service that uses iptables to automatically drop connections for a pre-defined amount of time from IPs that continuously failed to authenticate to the configured services.

#### Setup a filter and a jail for Planka

A filter defines regex rules to identify when users fail to authenticate on Planka's user interface.

Create a file in `/etc/fail2ban/filter.d` named `planka.conf` with the following contents:

```conf
[Definition]
failregex=^(.*) Invalid (email or username:|password!) (\"(.*)\"!)? ?\(IP: <ADDR>\)$
ignoreregex=
```

The jail file defines how to handle the failed authentication attempts found by the Planka filter.

Create a file in `/etc/fail2ban/jail.d` named `planka.local` with the following contents:

```conf
[planka]
enabled = true
port = http,https
filter = planka
logpath = /path/to/planka/logs/planka.log
maxretry = 5
bantime = 900
```

Ensure to replace `logpath`'s value with your installation’s `/logs/planka.log` location. If you are using ports other than 80 and 443 for your Web server you should replace those too. The bantime and findtime are defined in seconds.

Restart the fail2ban service. You can check the status of your Planka jail by running:

```bash
fail2ban-client status planka
```

## Development

Clone the repository and install dependencies:
Expand Down
7 changes: 6 additions & 1 deletion docker-start.sh
@@ -1,4 +1,9 @@
#!/bin/bash
set -e

# db
node db/init.js
exec node app.js --prod $@

# app
export NODE_ENV=production
exec node app.js
8 changes: 8 additions & 0 deletions server/api/controllers/access-tokens/create.js
@@ -1,6 +1,8 @@
const bcrypt = require('bcrypt');
const validator = require('validator');

const { getRemoteAddress } = require('../../../utils/remoteAddress');

const Errors = {
INVALID_EMAIL_OR_USERNAME: {
invalidEmailOrUsername: 'Invalid email or username',
Expand Down Expand Up @@ -41,10 +43,16 @@ module.exports = {
const user = await sails.helpers.users.getOneByEmailOrUsername(inputs.emailOrUsername);

if (!user) {
sails.log.warn(
`Invalid email or username: "${inputs.emailOrUsername}"! (IP: ${getRemoteAddress(
this.req,
)})`,
);
throw Errors.INVALID_EMAIL_OR_USERNAME;
}

if (!bcrypt.compareSync(inputs.password, user.password)) {
sails.log.warn(`Invalid password! (IP: ${getRemoteAddress(this.req)})`);
throw Errors.INVALID_PASSWORD;
}

Expand Down
4 changes: 1 addition & 3 deletions server/config/env/production.js
Expand Up @@ -243,9 +243,7 @@ module.exports = {
*
*/

log: {
level: 'debug',
},
log: {},

http: {
/**
Expand Down
4 changes: 1 addition & 3 deletions server/config/env/test.js
Expand Up @@ -64,7 +64,5 @@ module.exports = {
},
},

log: {
level: 'warn',
},
log: {},
};
19 changes: 18 additions & 1 deletion server/config/log.js
Expand Up @@ -10,6 +10,8 @@
* https://sailsjs.com/docs/concepts/logging
*/

const { customLogger } = require('../utils/logger');

module.exports.log = {
/**
*
Expand All @@ -22,5 +24,20 @@ module.exports.log = {
* You may also set the level to "silent" to suppress all logs.
*
*/
// level: 'info',

/**
* Passthrough plain log message(s) to
* custom Winston console and file logger.
*
* Note that Winston's log levels override Sails' log levels.
* Refer: https://github.com/winstonjs/winston#logging
*/
custom: customLogger,
inspect: false,

/**
* Removes the Sail.js init success logs
* (ASCII ship art) for production instances.
*/
noShip: process.env.NODE_ENV === 'production',
};

0 comments on commit 6429e22

Please sign in to comment.