Skip to content

Commit 37cc515

Browse files
committed
feat: added redis/mongo playbooks, updated existing (linted), added tuning and sysctl fixes, misc ansible security fixes
1 parent a4afa88 commit 37cc515

20 files changed

+2203
-63
lines changed

ansible/playbooks/DISASTER_RECOVERY.md

Lines changed: 575 additions & 0 deletions
Large diffs are not rendered by default.

ansible/playbooks/MONGODB_PERFORMANCE_TUNING.md

Lines changed: 405 additions & 0 deletions
Large diffs are not rendered by default.

ansible/playbooks/README_MONGO_REDIS.md

Lines changed: 152 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -8,22 +8,73 @@ These playbooks provide complete automation for:
88

99
- **MongoDB v6** installation and configuration
1010
- **Redis** installation and configuration
11+
- **Dynamic swap configuration** (swap file size = system RAM)
1112
- **TLS/SSL encryption** for both databases
1213
- **UFW firewall** with dynamic IP whitelist management
14+
- **DNS caching** with DNSSEC, DANE, and DNS-over-TLS support
15+
- **Kernel optimizations** for database performance
1316
- **Automated encrypted backups** to Cloudflare R2 every 6 hours
1417
- **Intelligent backup retention** (30-day retention with daily consolidation after 7 days)
1518

19+
## Architecture
20+
21+
### Inheritance Model
22+
23+
Both MongoDB and Redis playbooks inherit base configurations from `security.yml`:
24+
25+
```
26+
security.yml (imported by mongo.yml and redis.yml)
27+
├── Transparent Huge Pages (THP) disabled
28+
├── ulimits configured (nofile: 65536, nproc: 65536)
29+
├── Base sysctl settings (vm.swappiness: 0)
30+
├── devops and deploy user creation
31+
├── SSH hardening
32+
└── Unbound DNS caching (via unbound.yml)
33+
34+
mongo.yml / redis.yml
35+
├── Database-specific sysctl optimizations
36+
├── TLS/SSL configuration
37+
├── UFW firewall with IP whitelist
38+
├── Automated encrypted backups to R2
39+
└── Database installation and configuration
40+
```
41+
42+
**Key point:** THP, ulimits, and base sysctl settings are configured once in `security.yml` and inherited by all hosts including `mongo` and `redis`. This avoids duplication and ensures consistency.
43+
44+
### User Model
45+
46+
**Security best practice:** Database services run as dedicated unprivileged users:
47+
48+
- **MongoDB** runs as `mongod` user (created by MongoDB package)
49+
- **Redis** runs as `redis` user (created by Redis package)
50+
- **deploy** user is for application code deployment
51+
- **devops** user has sudo access for administration
52+
53+
This provides proper isolation and follows the principle of least privilege.
54+
55+
## Files
56+
57+
- **`mongo.yml`** - MongoDB deployment playbook
58+
- **`redis.yml`** - Redis deployment playbook
59+
- **`unbound.yml`** - DNS caching with DNSSEC/DANE support
60+
- **`security.yml`** - Security hardening (updated to include mongo/redis hosts)
61+
- **`requirements.yml`** - Ansible Galaxy role dependencies
62+
1663
## Prerequisites
1764

1865
### Ansible Roles
1966

2067
Install the required Ansible roles from Galaxy:
2168

2269
```bash
23-
ansible-galaxy install trfore.mongodb_install
24-
ansible-galaxy install geerlingguy.redis
70+
cd /path/to/forwardemail.net
71+
ansible-galaxy install -r ansible/requirements.yml
2572
```
2673

74+
This installs:
75+
- `trfore.mongodb_install` v3.0.5 - MongoDB installation
76+
- `geerlingguy.redis` v1.9.0 - Redis installation
77+
2778
### Environment Variables
2879

2980
The following environment variables must be set before running the playbooks:
@@ -163,7 +214,105 @@ This provides:
163214
- Daily recovery points for the past month
164215
- Automatic cleanup to control storage costs
165216

166-
### 4. Restoring Encrypted Backups
217+
### 4. DNS Caching with DNSSEC and DANE
218+
219+
**Unbound DNS resolver** is automatically configured on all hosts via `unbound.yml` (imported by `security.yml`).
220+
221+
**Features:**
222+
- **DNSSEC validation** - Cryptographic verification of DNS responses
223+
- **DANE/TLSA support** - DNS-based authentication of TLS certificates
224+
- **DNS-over-TLS (DoT)** - Encrypted DNS queries to Cloudflare (1.1.1.1)
225+
- **Query minimization** - Enhanced privacy
226+
- **Aggressive NSEC** - Faster negative responses
227+
- **DNS rebinding protection** - Security hardening
228+
229+
**Cache TTLs optimized for fast failover:**
230+
- Minimum TTL: 60 seconds
231+
- Maximum TTL: 300 seconds (5 minutes)
232+
- Negative cache TTL: 60 seconds
233+
234+
**Verification:**
235+
```bash
236+
# Test DNS resolution
237+
dig @127.0.0.1 +short cloudflare.com
238+
239+
# Verify DNSSEC
240+
dig @127.0.0.1 +dnssec cloudflare.com
241+
242+
# Check DANE/TLSA records
243+
dig @127.0.0.1 +short TLSA _443._tcp.example.com
244+
245+
# Check Unbound status
246+
sudo systemctl status unbound
247+
```
248+
249+
### 5. Dynamic Swap Configuration
250+
251+
Both MongoDB and Redis playbooks automatically configure swap space per official recommendations.
252+
253+
**Redis Official Documentation:**
254+
> "Ensured that swap is enabled and that your swap file size is equal to amount of memory on your system. If Linux does not have swap set up, and your Redis instance accidentally consumes too much memory, Redis can crash when it is out of memory, or the Linux kernel OOM killer can kill the Redis process."
255+
256+
Source: [Redis Administration - Memory](https://redis.io/docs/latest/operate/oss_and_stack/management/admin/)
257+
258+
**Implementation:**
259+
- Automatically detects total system RAM using `free -m`
260+
- Creates `/swapfile` with size equal to RAM
261+
- Sets `vm.swappiness=1` (minimize swapping but allow for safety)
262+
- Overrides `vm.swappiness=0` from security.yml
263+
- Idempotent: only recreates swap if size doesn't match RAM
264+
- Persists across reboots via `/etc/fstab`
265+
266+
**Verification:**
267+
```bash
268+
# Check swap status
269+
sudo swapon --show
270+
271+
# Check swappiness setting
272+
sysctl vm.swappiness
273+
274+
# View swap usage
275+
free -h
276+
```
277+
278+
**Why this matters:**
279+
- **Without swap:** Database crashes or OOM killer terminates process
280+
- **With swap:** Latency spikes are detectable, allowing intervention before crash
281+
- **Swappiness=1:** Minimizes performance impact while providing safety net
282+
283+
### 6. Performance Optimizations
284+
285+
#### Kernel Parameters (Inherited from security.yml)
286+
287+
**Base settings for all hosts:**
288+
- `vm.swappiness = 0` - Disable swapping (overridden to `1` for MongoDB/Redis)
289+
- `nofile = 65536` - File descriptor limit
290+
- `nproc = 65536` - Process limit
291+
- THP disabled via systemd service
292+
293+
#### MongoDB-Specific Optimizations
294+
295+
```
296+
vm.dirty_background_ratio = 10
297+
vm.dirty_ratio = 20
298+
net.core.somaxconn = 4096
299+
net.ipv4.tcp_max_syn_backlog = 4096
300+
net.ipv4.tcp_fin_timeout = 30
301+
net.ipv4.tcp_keepalive_intvl = 30
302+
net.ipv4.tcp_keepalive_time = 120
303+
```
304+
305+
#### Redis-Specific Optimizations
306+
307+
```
308+
vm.overcommit_memory = 1
309+
net.core.somaxconn = 65536
310+
net.ipv4.tcp_max_syn_backlog = 65536
311+
```
312+
313+
**See:** `MONGODB_PERFORMANCE_TUNING.md` and `REDIS_PERFORMANCE_TUNING.md` for detailed explanations.
314+
315+
### 6. Restoring Encrypted Backups
167316

168317
#### MongoDB Restore
169318

0 commit comments

Comments
 (0)