antirez/redis — pull request #1746 by mattsta (2014-05-12 19:38:20+00:00)
Title: Add disable persistence option

This is a first attempt at fixing issue #1704.

Some security applications require the ability to disable all disk persistence. Redis makes globally disabling persistence difficult since multiple places enable/disable persistence and persistence can always be manipulated by `CONFIG SET` during runtime. This commit removes the ability to enable persistence after the server starts.

New configuration options (can be set at start only, no live changes):
- `disable-replication` - removes `SYNC`, `PSYNC`, `SLAVEOF`, `MIGRATE`, `CLUSTER`, `REPLCONF` commands.
- Adds guards to replication functions making sure they can't be forced to run.
- `disable-all-persistence` - removes `SAVE`, `BGSAVE`, `BGREWRITEAOF` commands. Disables reading AOF or RDB on startup. Disables `CONFIG REWRITE` so people can't try to change configuration options to hold data then save it to disk. Disables `SHUTDOWN SAVE`. Avoids spawning the background I/O threads.
- Adds guards to write functions making sure they can't be circumvented through other entry points.
- This config option has a long name and includes an annoying-to-type word like "persistence" to hopefully stop people from enabling it by mistake.

`disable-all-persistence` automatically enables `disable-replication` because a.) we don't want replicas to persist our data and b.) replication requires serializing the DB to disk to send to the replica.

`disable-replication` automatically sets `cluster-enabled` to `no`.

If you're on Linux, `disable-all-persistence` also attempts to lock all memory into RAM to stop anything from entering your swap space. That can only happen if you either run as root or have explicit capability `CAP_IPC_LOCK`.

The implementation is very paranoid. It disables commands then, in the commands themselves, each potential write command aborts if nopersist is set, then in the functions performing writes or network connections, the function immediately returns if nopersist (or noreplication) is set.

The reason for the multi-layered approach is: some operations (like saving an RDB) have multiple entry points (`SAVE`, `BGSAVE`, the `save` config option, `SHUTDOWN SAVE`, ...) and I wanted to make sure, even if we miss disabling an entry point, that write functions are still disabled. Multi-layered blocks will make security audit people happier too.