Skip to content

Commit

Permalink
allow defining additional commands as safe for read-only mode, defaul…
Browse files Browse the repository at this point in the history
…ting to "info" and "select"

Signed-off-by: Stefan Seide <account-github@seide.st>
  • Loading branch information
sseide committed Nov 22, 2023
1 parent bb5020e commit 49ab61c
Show file tree
Hide file tree
Showing 7 changed files with 52 additions and 5 deletions.
1 change: 1 addition & 0 deletions CHANGELOG.md
Expand Up @@ -14,6 +14,7 @@
* add option to overwrite global folding character per connection
* add Sentinel TLS connections and improved configuration and env var handling for TLS secured connections, #514
* add Redis Cluster support, #160 #216 #527
* allow defining additional commands as safe for read-only mode, defaulting to "info" and "select", #542
* update base image to alpine@3.17 using NodeJS 18.x now, #511
* update helm chart autoscaling apis for newer K8s versions, #520
* update helm chart to allow setting ingressClassName for newer K8s versions, #494
Expand Down
6 changes: 5 additions & 1 deletion config/default.json
Expand Up @@ -19,7 +19,11 @@
"rootPattern": "*",
"connectionName": "redis-commander",
"defaultLabel": "local",
"defaultSentinelGroup": "mymaster"
"defaultSentinelGroup": "mymaster",
"extraAllowedReadOnlyCommands": [
"select",
"info"
]
},
"server": {
"address": "0.0.0.0",
Expand Down
33 changes: 33 additions & 0 deletions docs/configuration.md
Expand Up @@ -91,6 +91,39 @@ while the second connection to 10.9.8.7 uses '/' here:
| redis.connectionName | string | 'redis-commander' | | REDIS_CONNECTION_NAME | connection name to set at redis client for easier identification of clients at redis server (command "client list") |
| redis.defaultLabel | string | 'local' | | REDIS_LABEL | default label to display for a connection if no label is specified (e.g. for connection from env vars or command line) |
| redis.defaultSentinelGroup | string | 'mymaster' | | | default redis database group if using sentinels to connect and no special database group via connection param 'sentinelName' is given. |
| redis.extraAllowedReadOnlyCommands | list | ['select', 'info'] | | | list of additional redis commands allowed if set to read-only. See remark below |

#### Read-Only Mode

Setting the parameter `redis.readOnly` to `true` only commands not changing data are allowed. As Default the list with all read-only commands
is directly queried from the server (calling "COMMANDS") and parsing the output for the "readonly" flag.

Some commands are not marked as read-only by there server - adding these commands to the list at `redis.extraAllowedReadOnlyCommands`
allows them too being in readOnly mode. This list is not used if all commands are allowed (readOnly=false).

Attention: if this list shall be changed (ore set to emtpy) within a local config file (like `local.json`) the new
value _overwrites_ the default list defined in the `default.json` file. The values are not appended and the full list of allowed
commands must be configured in the local file.

Example (shortened) output from "COMMANDS" command showing `dbsize` flagged as readonly while `select` is not
```
61) 1) "select"
2) (integer) 2
3) 1) loading
2) fast
4) (integer) 0
5) (integer) 0
6) (integer) 0
...
86) 1) "dbsize"
2) (integer) 1
3) 1) readonly
2) fast
4) (integer) 0
5) (integer) 0
6) (integer) 0
...
```

### 4. Express HTTP Server parameter

Expand Down
4 changes: 3 additions & 1 deletion lib/connections.js
Expand Up @@ -306,9 +306,11 @@ class ConnectionWrapper {
if (p[0].status === 'fulfilled' && Array.isArray(p[0].value)) {
// console.debug('Got list of ' + p[0].value.length + ' commands from server ' + redisConnection.options.host + ':' +
// redisConnection.options.port);
const extraROCmds = require('config').get('redis.extraAllowedReadOnlyCommands');
redisConnection.options.commandList = {
all: p[0].value.map((item) => (item[0].toLowerCase())),
ro: p[0].value.filter((item) => (item[2].indexOf('readonly') >= 0)).map((item) => (item[0].toLowerCase()))
ro: p[0].value.filter((item) => (item[2].indexOf('readonly') >= 0 || extraROCmds.indexOf(item[0]) >= 0))
.map((item) => (item[0].toLowerCase()))
};
}
else {
Expand Down
7 changes: 7 additions & 0 deletions lib/util.js
Expand Up @@ -662,6 +662,13 @@ function validateConfig() {
else c.util.setPath(c, ['sso', 'jwtAlgorithms'], "");
}

// check if extra readonly commands is a list, warn and set to empty list if not (be safe here)
if (! Array.isArray(c.get('redis.extraAllowedReadOnlyCommands'))) {
console.warn('Attention - config redis.extraAllowedReadOnlyCommands is not a list - ignoring value');
c.util.setPath(c, ['redis', 'extraAllowedReadOnlyCommands'], []);
}

// evaluate errors - exit if there are some critical ones...
if (errCount > 0) {
throw new Error(`Configuration invalid - ${errCount} errors found.`);
}
Expand Down
4 changes: 2 additions & 2 deletions package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion package.json
Expand Up @@ -8,7 +8,7 @@
"Stefan Seide <account-github@seide.st"
],
"name": "redis-commander",
"version": "0.9.0-rc3",
"version": "0.9.0-rc4",
"description": "Redis web-based management tool written in node.js",
"license": "MIT",
"repository": {
Expand Down

0 comments on commit 49ab61c

Please sign in to comment.