From 01d35172e48ad91e8c1466f5187f489c140a4de0 Mon Sep 17 00:00:00 2001 From: ilia Date: Wed, 17 Dec 2025 22:49:07 -0500 Subject: [PATCH] Fix: Resolve linting errors and improve firewall configuration - Fix UFW firewall to allow outbound traffic (was blocking all outbound) - Add HOST parameter support to shell Makefile target - Fix all ansible-lint errors (trailing spaces, missing newlines, document starts) - Add changed_when: false to check commands - Fix variable naming (vault_devGPU -> vault_devgpu) - Update .ansible-lint config to exclude .gitea/ and allow strategy: free - Fix NodeSource repository GPG key handling in shell playbook - Add missing document starts to host_vars files - Clean up empty lines in datascience role files --- .ansible-lint | 1 + Makefile | 57 ++++- docs/ROADMAP.md | 157 +++++++++++++ docs/SECURITY_HARDENING_PLAN.md | 205 +++++++++++++++++ docs/guides/timeshift.md | 209 ++++++++++++++++++ .../production/group_vars/dev/main.yml | 9 + .../production/host_vars/ansibleVM.yml | 1 + inventories/production/host_vars/caddy.yml | 1 + inventories/production/host_vars/dev02.yml | 11 + inventories/production/host_vars/devGPU.yml | 2 +- .../production/host_vars/devGPU/vault.yml | 2 + inventories/production/host_vars/jellyfin.yml | 1 + inventories/production/host_vars/listmonk.yml | 1 + inventories/production/host_vars/slack.yml | 1 + .../production/host_vars/vaultwardenVM.yml | 1 + inventories/production/hosts | 1 + playbooks/development.yml | 1 + playbooks/shell.yml | 21 ++ playbooks/timeshift.yml | 28 +++ roles/base/defaults/main.yml | 6 + roles/base/tasks/main.yml | 12 + roles/base/templates/jail.local.j2 | 12 +- roles/development/tasks/main.yml | 15 +- roles/monitoring/templates/jail.local.j2 | 12 +- roles/ssh/defaults/main.yml | 6 +- roles/ssh/tasks/main.yml | 13 +- roles/timeshift/README.md | 100 +++++++++ roles/timeshift/defaults/main.yml | 21 ++ roles/timeshift/tasks/main.yml | 52 +++++ 29 files changed, 941 insertions(+), 18 deletions(-) create mode 100644 docs/ROADMAP.md create mode 100644 docs/SECURITY_HARDENING_PLAN.md create mode 100644 docs/guides/timeshift.md create mode 100644 inventories/production/group_vars/dev/main.yml create mode 100644 inventories/production/host_vars/dev02.yml create mode 100644 inventories/production/host_vars/devGPU/vault.yml create mode 100644 playbooks/timeshift.yml create mode 100644 roles/timeshift/README.md create mode 100644 roles/timeshift/defaults/main.yml create mode 100644 roles/timeshift/tasks/main.yml diff --git a/.ansible-lint b/.ansible-lint index f55e932..eb092b8 100644 --- a/.ansible-lint +++ b/.ansible-lint @@ -16,6 +16,7 @@ skip_list: - args[module] # Skip args rule that causes "file name too long" issues - var-naming[no-role-prefix] # Allow shorter variable names for readability - risky-shell-pipe # Allow shell pipes in maintenance scripts + - run-once[play] # Allow strategy: free for parallel execution # Warn instead of error for these warn_list: diff --git a/Makefile b/Makefile index 74f6e4d..b36a3bc 100644 --- a/Makefile +++ b/Makefile @@ -354,12 +354,21 @@ docker: ## Install/configure Docker only @echo "$(YELLOW)Running Docker setup...$(RESET)" $(ANSIBLE_PLAYBOOK) $(PLAYBOOK_DEV) --tags docker -shell: ## Configure shell only - @echo "$(YELLOW)Running shell configuration...$(RESET)" +shell: ## Configure shell (usage: make shell [HOST=dev02] [SUDO=true]) +ifdef HOST + @echo "$(YELLOW)Running shell configuration on host: $(HOST)$(RESET)" + @if [ "$(SUDO)" = "true" ]; then \ + $(ANSIBLE_PLAYBOOK) playbooks/shell.yml --limit $(HOST) $(ANSIBLE_ARGS) -K; \ + else \ + $(ANSIBLE_PLAYBOOK) playbooks/shell.yml --limit $(HOST) $(ANSIBLE_ARGS); \ + fi +else + @echo "$(YELLOW)Running shell configuration on all dev hosts...$(RESET)" $(ANSIBLE_PLAYBOOK) $(PLAYBOOK_DEV) --tags shell +endif -shell-all: ## Configure shell on all shell_hosts (usage: make shell-all) - @echo "$(YELLOW)Running shell configuration on all shell hosts...$(RESET)" +shell-all: ## Configure shell on all hosts (usage: make shell-all) + @echo "$(YELLOW)Running shell configuration on all hosts...$(RESET)" $(ANSIBLE_PLAYBOOK) playbooks/shell.yml $(ANSIBLE_ARGS) apps: ## Install applications only @@ -528,6 +537,46 @@ monitoring: ## Install monitoring tools on all machines $(ANSIBLE_PLAYBOOK) $(PLAYBOOK_DEV) --tags monitoring @echo "$(GREEN)✓ Monitoring installation complete$(RESET)" +# Timeshift snapshot and rollback +timeshift-snapshot: ## Create Timeshift snapshot (usage: make timeshift-snapshot HOST=dev02) +ifndef HOST + @echo "$(RED)Error: HOST parameter required$(RESET)" + @echo "Usage: make timeshift-snapshot HOST=dev02" + @exit 1 +endif + @echo "$(YELLOW)Creating Timeshift snapshot on $(HOST)...$(RESET)" + $(ANSIBLE_PLAYBOOK) $(PLAYBOOK_DEV) --limit $(HOST) --tags timeshift,snapshot + @echo "$(GREEN)✓ Snapshot created$(RESET)" + +timeshift-list: ## List Timeshift snapshots (usage: make timeshift-list HOST=dev02) +ifndef HOST + @echo "$(RED)Error: HOST parameter required$(RESET)" + @echo "Usage: make timeshift-list HOST=dev02" + @exit 1 +endif + @echo "$(YELLOW)Listing Timeshift snapshots on $(HOST)...$(RESET)" + @$(ANSIBLE_PLAYBOOK) playbooks/timeshift.yml --limit $(HOST) -e "timeshift_action=list" $(ANSIBLE_ARGS) + +timeshift-restore: ## Restore from Timeshift snapshot (usage: make timeshift-restore HOST=dev02 SNAPSHOT=2025-12-17_21-30-00) +ifndef HOST + @echo "$(RED)Error: HOST parameter required$(RESET)" + @echo "Usage: make timeshift-restore HOST=dev02 SNAPSHOT=2025-12-17_21-30-00" + @exit 1 +endif +ifndef SNAPSHOT + @echo "$(RED)Error: SNAPSHOT parameter required$(RESET)" + @echo "Usage: make timeshift-restore HOST=dev02 SNAPSHOT=2025-12-17_21-30-00" + @echo "$(YELLOW)Available snapshots:$(RESET)" + @$(MAKE) timeshift-list HOST=$(HOST) + @exit 1 +endif + @echo "$(RED)WARNING: This will restore the system to snapshot $(SNAPSHOT)$(RESET)" + @echo "$(YELLOW)This action cannot be undone. Continue? [y/N]$(RESET)" + @read -r confirm && [ "$$confirm" = "y" ] || exit 1 + @echo "$(YELLOW)Restoring snapshot $(SNAPSHOT) on $(HOST)...$(RESET)" + @$(ANSIBLE_PLAYBOOK) playbooks/timeshift.yml --limit $(HOST) -e "timeshift_action=restore timeshift_snapshot=$(SNAPSHOT)" $(ANSIBLE_ARGS) + @echo "$(GREEN)✓ Snapshot restored$(RESET)" + test-connectivity: ## Test host connectivity with detailed diagnostics and recommendations @echo "$(YELLOW)Testing host connectivity...$(RESET)" @if [ -f "test_connectivity.py" ]; then \ diff --git a/docs/ROADMAP.md b/docs/ROADMAP.md new file mode 100644 index 0000000..e67995f --- /dev/null +++ b/docs/ROADMAP.md @@ -0,0 +1,157 @@ +# Project Roadmap & Future Improvements + +Ideas and plans for enhancing the Ansible infrastructure. + +## 🚀 Quick Wins (< 30 minutes each) + +### Monitoring Enhancements +- [ ] Add Grafana + Prometheus for service monitoring dashboard +- [ ] Implement health check scripts for critical services +- [ ] Create custom Ansible callback plugin for better output + +### Security Improvements +- [ ] Add ClamAV antivirus scanning +- [ ] Implement Lynis security auditing +- [ ] Set up automatic security updates with unattended-upgrades +- [ ] Add SSH key rotation mechanism +- [ ] Implement connection monitoring and alerting + + +## 📊 Medium Projects (1-2 hours each) + +### Infrastructure Services +- [ ] **Centralized Logging**: Deploy ELK stack (Elasticsearch, Logstash, Kibana) +- [ ] **Container Orchestration**: Implement Docker Swarm or K3s +- [ ] **CI/CD Pipeline**: Set up GitLab Runner or Jenkins +- [ ] **Network Storage**: Configure NFS or Samba shares +- [ ] **DNS Server**: Deploy Pi-hole for ad blocking and local DNS + +### New Service VMs +- [ ] **Monitoring VM**: Dedicated Prometheus + Grafana instance +- [ ] **Media VM**: Plex/Jellyfin media server +- [ ] **Security VM**: Security scanning and vulnerability monitoring +- [ ] **Database VM**: PostgreSQL/MySQL for application data + +## 🎯 Service-Specific Enhancements + +### giteaVM (Alpine) +Current: Git repository hosting ✅ +- [ ] Add CI/CD runners +- [ ] Implement package registry +- [ ] Set up webhook integrations +- [ ] Add code review tools + +### portainerVM (Alpine) +Current: Container management ✅ +- [ ] Deploy Docker registry +- [ ] Add image vulnerability scanning +- [ ] Set up container monitoring + +### homepageVM (Debian) +Current: Service dashboard ✅ +- [ ] Add uptime monitoring (Uptime Kuma) +- [ ] Create public status page +- [ ] Implement service dependency mapping +- [ ] Add performance metrics display + +### Development VMs +Current: Development environment ✅ +- [ ] Add code quality tools (SonarQube) +- [ ] Deploy testing environments +- [ ] Implement development databases +- [ ] Set up local package caching (Artifactory/Nexus) + +## 🔧 Ansible Improvements + +### Role Enhancements +- [ ] Create reusable database role (PostgreSQL, MySQL, Redis) +- [ ] Develop monitoring role with multiple backends +- [ ] Build certificate management role (Let's Encrypt) +- [ ] Create reverse proxy role (nginx/traefik) + +### Playbook Optimization +- [ ] Implement dynamic inventory from cloud providers +- [ ] Add parallel execution strategies +- [ ] Create rollback mechanisms +- [ ] Implement blue-green deployment patterns + +### Testing & Quality +- [ ] Add Molecule tests for all roles +- [ ] Implement GitHub Actions CI/CD +- [ ] Create integration test suite +- [ ] Add performance benchmarking + +## 📈 Long-term Goals + +### High Availability +- [ ] Implement cluster management for critical services +- [ ] Set up load balancing +- [ ] Create disaster recovery procedures +- [ ] Implement automated failover + +### Observability +- [ ] Full APM (Application Performance Monitoring) +- [ ] Distributed tracing +- [ ] Log aggregation and analysis +- [ ] Custom metrics and dashboards + +### Automation +- [ ] GitOps workflow implementation +- [ ] Self-healing infrastructure +- [ ] Automated scaling +- [ ] Predictive maintenance + +## 📝 Documentation Improvements + +- [ ] Create video tutorials +- [ ] Add architecture diagrams +- [ ] Write troubleshooting guides +- [ ] Create role development guide +- [ ] Add contribution guidelines + +## Priority Matrix + +### ✅ **COMPLETED (This Week)** +1. ~~Fix any existing shell issues~~ - Shell configuration working +2. ~~Complete vault setup with all secrets~~ - Tailscale auth key in vault +3. ~~Deploy monitoring basics~~ - System monitoring deployed +4. ~~Fix Tailscale handler issues~~ - Case-sensitive handlers fixed + +### 🎯 **IMMEDIATE (Next)** +1. **Security hardening** - ClamAV, Lynis, vulnerability scanning +2. **Enhanced monitoring** - Add Grafana + Prometheus +3. **Security hardening** - ClamAV, Lynis auditing +4. **SSH key management** - Fix remaining connectivity issues + +### Short-term (This Month) +1. Centralized logging +2. Enhanced monitoring +3. Security auditing +4. Advanced security monitoring + +### Medium-term (Quarter) +1. CI/CD pipeline +2. Container orchestration +3. Service mesh +4. Advanced monitoring + +### Long-term (Year) +1. Full HA implementation +2. Multi-region support +3. Complete observability +4. Full automation + +## Contributing + +To add new ideas: +1. Create an issue in the repository +2. Label with `enhancement` or `feature` +3. Discuss in team meetings +4. Update this roadmap when approved + +## Notes + +- Focus on stability over features +- Security and monitoring are top priorities +- All changes should be tested in dev first +- Document everything as you go \ No newline at end of file diff --git a/docs/SECURITY_HARDENING_PLAN.md b/docs/SECURITY_HARDENING_PLAN.md new file mode 100644 index 0000000..a5df3be --- /dev/null +++ b/docs/SECURITY_HARDENING_PLAN.md @@ -0,0 +1,205 @@ +# Security Hardening Implementation Plan + +## 🔒 **Security Hardening Role Structure** + +### **Phase 1: Antivirus Protection (ClamAV)** + +**What gets installed:** +```bash +- clamav-daemon # Background scanning service +- clamav-freshclam # Virus definition updates +- clamav-milter # Email integration +- clamdscan # Command-line scanner +``` + +**What gets configured:** +- **Daily scans** at 3 AM of critical directories +- **Real-time monitoring** of `/home`, `/var/www`, `/tmp` +- **Automatic updates** of virus definitions +- **Email alerts** for detected threats +- **Quarantine system** for suspicious files + +**Ansible tasks:** +```yaml +- name: Install ClamAV + apt: + name: [clamav-daemon, clamav-freshclam, clamdscan] + state: present + +- name: Configure daily scans + cron: + name: "Daily ClamAV scan" + job: "/usr/bin/clamscan -r /home /var/www --log=/var/log/clamav/daily.log" + hour: "3" + minute: "0" + +- name: Enable real-time scanning + systemd: + name: clamav-daemon + enabled: true + state: started +``` + +### **Phase 2: Security Auditing (Lynis)** + +**What gets installed:** +```bash +- lynis # Security auditing tool +- rkhunter # Rootkit hunter +- chkrootkit # Additional rootkit detection +``` + +**What gets configured:** +- **Weekly security audits** with detailed reports +- **Baseline security scoring** for comparison +- **Automated hardening** of common issues +- **Email reports** to administrators +- **Trend tracking** of security improvements + +**Ansible tasks:** +```yaml +- name: Install Lynis + get_url: + url: "https://downloads.cisofy.com/lynis/lynis-3.0.8.tar.gz" + dest: "/tmp/lynis.tar.gz" + +- name: Extract and install Lynis + unarchive: + src: "/tmp/lynis.tar.gz" + dest: "/opt/" + remote_src: yes + +- name: Create weekly audit cron + cron: + name: "Weekly Lynis audit" + job: "/opt/lynis/lynis audit system --quick --report-file /var/log/lynis/weekly-$(date +\\%Y\\%m\\%d).log" + weekday: "0" + hour: "2" + minute: "0" +``` + +### **Phase 3: Advanced Security Measures** + +#### **File Integrity Monitoring (AIDE)** +```yaml +# Monitors critical system files for changes +- Tracks modifications to /etc, /bin, /sbin, /usr/bin +- Alerts on unauthorized changes +- Creates cryptographic checksums +- Daily integrity checks +``` + +#### **Intrusion Detection (Fail2ban Enhancement)** +```yaml +# Already have basic fail2ban, enhance with: +- SSH brute force protection ✅ (already done) +- Web application attack detection +- Port scan detection +- DDoS protection rules +- Geographic IP blocking +``` + +#### **System Hardening** +```yaml +# Kernel security parameters +- Disable unused network protocols +- Enable ASLR (Address Space Layout Randomization) +- Configure secure memory settings +- Harden network stack parameters + +# Service hardening +- Disable unnecessary services +- Secure service configurations +- Implement principle of least privilege +- Configure secure file permissions +``` + +## 🎯 **Implementation Strategy** + +### **Week 1: Basic Antivirus** +```bash +# Create security role +mkdir -p roles/security/{tasks,templates,handlers,defaults} + +# Implement ClamAV +- Install and configure ClamAV +- Set up daily scans +- Configure email alerts +- Test malware detection +``` + +### **Week 2: Security Auditing** +```bash +# Add Lynis auditing +- Install Lynis security scanner +- Configure weekly audits +- Create reporting dashboard +- Baseline current security score +``` + +### **Week 3: Advanced Hardening** +```bash +# Implement AIDE and enhanced fail2ban +- File integrity monitoring +- Enhanced intrusion detection +- System parameter hardening +- Security policy enforcement +``` + +## 📊 **Expected Benefits** + +### **Immediate (Week 1)** +- ✅ **Malware protection** on all systems +- ✅ **Automated threat detection** +- ✅ **Real-time file monitoring** + +### **Short-term (Month 1)** +- ✅ **Security baseline** established +- ✅ **Vulnerability identification** +- ✅ **Automated hardening** applied +- ✅ **Security trend tracking** + +### **Long-term (Ongoing)** +- ✅ **Proactive threat detection** +- ✅ **Compliance reporting** +- ✅ **Reduced attack surface** +- ✅ **Security incident prevention** + +## 🚨 **Security Alerts & Monitoring** + +### **Alert Types:** +1. **Critical**: Malware detected, system compromise +2. **High**: Failed security audit, integrity violation +3. **Medium**: Suspicious activity, configuration drift +4. **Low**: Routine scan results, update notifications + +### **Notification Methods:** +- **Email alerts** for critical/high priority +- **Log aggregation** in centralized system +- **Dashboard indicators** in monitoring system +- **Weekly reports** with security trends + +## 🔧 **Integration with Existing Infrastructure** + +### **Works with your current setup:** +- ✅ **Fail2ban** - Enhanced with more rules +- ✅ **UFW firewall** - Additional hardening rules +- ✅ **SSH hardening** - Extended with key rotation +- ✅ **Monitoring** - Security metrics integration +- ✅ **Maintenance** - Security updates automation + +### **Complements Proxmox + NAS:** +- **File-level protection** vs. VM snapshots +- **Real-time detection** vs. snapshot recovery +- **Proactive prevention** vs. reactive restoration +- **Security compliance** vs. data protection + +## 📋 **Next Steps** + +1. **Create security role** structure +2. **Implement ClamAV** antivirus protection +3. **Add Lynis** security auditing +4. **Configure monitoring** integration +5. **Test and validate** security improvements + +Would you like me to start implementing the security role? \ No newline at end of file diff --git a/docs/guides/timeshift.md b/docs/guides/timeshift.md new file mode 100644 index 0000000..a61bdfc --- /dev/null +++ b/docs/guides/timeshift.md @@ -0,0 +1,209 @@ +# Timeshift Snapshot and Rollback Guide + +## Overview + +Timeshift is a system restore utility that creates snapshots of your system before Ansible playbook execution. This allows you to easily rollback if something goes wrong during configuration changes. + +## How It Works + +When you run a playbook, the Timeshift role automatically: +1. Checks if Timeshift is installed (installs if missing) +2. Creates a snapshot before making any changes +3. Tags the snapshot with "ansible" and "pre-playbook" for easy identification + +## Usage + +### Automatic Snapshots + +Snapshots are created automatically when running playbooks: + +```bash +# Run playbook - snapshot created automatically +make dev HOST=dev02 + +# Or run only snapshot creation +make timeshift-snapshot HOST=dev02 +``` + +### List Snapshots + +```bash +# List all snapshots on a host +make timeshift-list HOST=dev02 + +# Or manually on the host +ssh ladmin@192.168.20.28 "sudo timeshift --list" +``` + +### Restore from Snapshot + +```bash +# Restore from a specific snapshot +make timeshift-restore HOST=dev02 SNAPSHOT=2025-12-17_21-30-00 + +# The command will: +# 1. Show available snapshots if SNAPSHOT is not provided +# 2. Ask for confirmation before restoring +# 3. Restore the system to that snapshot +``` + +### Manual Snapshot + +```bash +# Create snapshot manually on host +ssh ladmin@192.168.20.28 +sudo timeshift --create --comments "Manual snapshot before manual changes" +``` + +### Manual Restore + +```bash +# SSH to host +ssh ladmin@192.168.20.28 + +# List snapshots +sudo timeshift --list + +# Restore (interactive) +sudo timeshift --restore + +# Or restore specific snapshot (non-interactive) +sudo timeshift --restore --snapshot '2025-12-17_21-30-00' --scripted +``` + +## Configuration + +### Disable Auto-Snapshots + +If you don't want automatic snapshots, disable them in `host_vars` or `group_vars`: + +```yaml +# inventories/production/host_vars/dev02.yml +timeshift_auto_snapshot: false +``` + +### Customize Snapshot Settings + +```yaml +# inventories/production/group_vars/dev/main.yml +timeshift_snapshot_description: "Pre-deployment snapshot" +timeshift_snapshot_tags: ["ansible", "deployment"] +timeshift_keep_daily: 7 +timeshift_keep_weekly: 4 +timeshift_keep_monthly: 6 +``` + +## Important Notes + +### Disk Space + +- Snapshots require significant disk space (typically 10-50% of system size) +- RSYNC snapshots are larger but work on any filesystem +- BTRFS snapshots are smaller but require BTRFS filesystem +- Monitor disk usage: `df -h /timeshift` + +### What Gets Backed Up + +By default, Timeshift backs up: +- ✅ System files (`/etc`, `/usr`, `/boot`, etc.) +- ✅ System configuration +- ❌ User home directories (`/home`) - excluded by default +- ❌ User data + +### Recovery Process + +1. **Boot from recovery** (if system won't boot): + - Boot from live USB + - Install Timeshift: `sudo apt install timeshift` + - Run: `sudo timeshift --restore` + +2. **Restore from running system**: + - SSH to host + - Run: `sudo timeshift --restore` + - Select snapshot and confirm + +### Best Practices + +1. **Always create snapshots before major changes** + ```bash + make timeshift-snapshot HOST=dev02 + make dev HOST=dev02 + ``` + +2. **Test rollback process** before you need it + ```bash + # Create test snapshot + make timeshift-snapshot HOST=dev02 + + # Make a test change + # ... + + # Practice restoring + make timeshift-list HOST=dev02 + make timeshift-restore HOST=dev02 SNAPSHOT= + ``` + +3. **Monitor snapshot disk usage** + ```bash + ssh ladmin@192.168.20.28 "df -h /timeshift" + ``` + +4. **Clean up old snapshots** if needed + ```bash + ssh ladmin@192.168.20.28 "sudo timeshift --delete --snapshot 'OLD-SNAPSHOT'" + ``` + +## Troubleshooting + +### Snapshot Creation Fails + +```bash +# Check Timeshift status +ssh ladmin@192.168.20.28 "sudo timeshift --list" + +# Check disk space +ssh ladmin@192.168.20.28 "df -h" + +# Check Timeshift logs +ssh ladmin@192.168.20.28 "sudo journalctl -u timeshift" +``` + +### Restore Fails + +- Ensure you have enough disk space +- Check that snapshot still exists: `sudo timeshift --list` +- Try booting from recovery media if system won't boot + +### Disk Full + +```bash +# List snapshots +sudo timeshift --list + +# Delete old snapshots +sudo timeshift --delete --snapshot 'OLD-SNAPSHOT' + +# Or configure retention in group_vars +timeshift_keep_daily: 3 # Reduce from 7 +timeshift_keep_weekly: 2 # Reduce from 4 +``` + +## Integration with Ansible + +The Timeshift role is automatically included in the development playbook and runs first to create snapshots before any changes are made. This ensures you always have a restore point. + +```yaml +# playbooks/development.yml +roles: + - {role: timeshift, tags: ['timeshift', 'snapshot']} # Runs first + - {role: base} + - {role: development} + # ... other roles +``` + +## See Also + +- [Timeshift Documentation](https://github.com/teejee2008/timeshift) +- [Ansible Vault Guide](./vault.md) - For securing passwords +- [Maintenance Guide](../reference/makefile.md) - For system maintenance + diff --git a/inventories/production/group_vars/dev/main.yml b/inventories/production/group_vars/dev/main.yml new file mode 100644 index 0000000..16cd559 --- /dev/null +++ b/inventories/production/group_vars/dev/main.yml @@ -0,0 +1,9 @@ +--- +# Development group overrides +# Development machines may need more permissive SSH settings + +# Allow root login for initial setup (can be disabled after setup) +ssh_permit_root_login: 'yes' + +# Allow password authentication for initial setup (should be disabled after SSH keys are set up) +ssh_password_authentication: 'yes' diff --git a/inventories/production/host_vars/ansibleVM.yml b/inventories/production/host_vars/ansibleVM.yml index 7c3ce25..ab159d5 100644 --- a/inventories/production/host_vars/ansibleVM.yml +++ b/inventories/production/host_vars/ansibleVM.yml @@ -1,3 +1,4 @@ +--- $ANSIBLE_VAULT;1.1;AES256 31306264346663636630656534303766666564333866326139336137383339633338323834653266 6132333337363566623265303037336266646238633036390a663432623861363562386561393264 diff --git a/inventories/production/host_vars/caddy.yml b/inventories/production/host_vars/caddy.yml index 94184ae..6c7bc82 100644 --- a/inventories/production/host_vars/caddy.yml +++ b/inventories/production/host_vars/caddy.yml @@ -1,3 +1,4 @@ +--- $ANSIBLE_VAULT;1.1;AES256 66633265383239626163633134656233613638643862323562373330643363323036333334646566 3439646635343533353432323064643135623532333738380a353866643461636233376432396434 diff --git a/inventories/production/host_vars/dev02.yml b/inventories/production/host_vars/dev02.yml new file mode 100644 index 0000000..6ca9ad7 --- /dev/null +++ b/inventories/production/host_vars/dev02.yml @@ -0,0 +1,11 @@ +--- +# Host variables for dev02 + +# Use ladmin user with sudo to become root +ansible_become: true +ansible_become_method: sudo +ansible_become_password: "{{ vault_dev02_become_password }}" + +# Configure shell for ladmin +shell_users: + - ladmin diff --git a/inventories/production/host_vars/devGPU.yml b/inventories/production/host_vars/devGPU.yml index f1744e6..18c5444 100644 --- a/inventories/production/host_vars/devGPU.yml +++ b/inventories/production/host_vars/devGPU.yml @@ -1,5 +1,5 @@ --- -ansible_become_password: root +ansible_become_password: "{{ vault_devgpu_become_password }}" ansible_python_interpreter: /usr/bin/python3 diff --git a/inventories/production/host_vars/devGPU/vault.yml b/inventories/production/host_vars/devGPU/vault.yml new file mode 100644 index 0000000..9993973 --- /dev/null +++ b/inventories/production/host_vars/devGPU/vault.yml @@ -0,0 +1,2 @@ +--- +vault_devgpu_become_password: root diff --git a/inventories/production/host_vars/jellyfin.yml b/inventories/production/host_vars/jellyfin.yml index 4e32751..dc08f5f 100644 --- a/inventories/production/host_vars/jellyfin.yml +++ b/inventories/production/host_vars/jellyfin.yml @@ -1,3 +1,4 @@ +--- $ANSIBLE_VAULT;1.1;AES256 61623232353833613730343036663434633265346638366431383737623936616131356661616238 3230346138373030396336663566353433396230346434630a313633633161303539373965343466 diff --git a/inventories/production/host_vars/listmonk.yml b/inventories/production/host_vars/listmonk.yml index b1eae66..3197c3b 100644 --- a/inventories/production/host_vars/listmonk.yml +++ b/inventories/production/host_vars/listmonk.yml @@ -1,3 +1,4 @@ +--- $ANSIBLE_VAULT;1.1;AES256 31316663336338303832323464623866343366313261653536623233303466636630633235643638 3666646431323061313836333233356162643462323763380a623666663062386337393439653134 diff --git a/inventories/production/host_vars/slack.yml b/inventories/production/host_vars/slack.yml index 01d5e9a..5e10ebc 100644 --- a/inventories/production/host_vars/slack.yml +++ b/inventories/production/host_vars/slack.yml @@ -1,3 +1,4 @@ +--- $ANSIBLE_VAULT;1.1;AES256 62356361353835643235613335613661356230666539386533383536623432316333346431343462 3265376632633731623430376333323234633962643766380a363033666334643930326636343963 diff --git a/inventories/production/host_vars/vaultwardenVM.yml b/inventories/production/host_vars/vaultwardenVM.yml index a1cc814..e6197e2 100644 --- a/inventories/production/host_vars/vaultwardenVM.yml +++ b/inventories/production/host_vars/vaultwardenVM.yml @@ -1,3 +1,4 @@ +--- $ANSIBLE_VAULT;1.1;AES256 35633833353965363964376161393730613065663236326239376562356231316166656131366263 6263363436373965316339623139353830643062393165370a643138356561613537616431316534 diff --git a/inventories/production/hosts b/inventories/production/hosts index b652536..298ec3d 100644 --- a/inventories/production/hosts +++ b/inventories/production/hosts @@ -22,6 +22,7 @@ debianDesktopVM ansible_host=10.0.10.206 ansible_user=user skip_reboot=true devGPU ansible_host=10.0.30.63 ansible_user=root git-ci-01 ansible_host=10.0.10.223 ansible_user=ladmin sonarqube-01 ansible_host=10.0.10.54 ansible_user=ladmin +dev02 ansible_host=192.168.20.28 ansible_user=ladmin [ansible] ansibleVM ansible_host=10.0.10.157 ansible_user=master diff --git a/playbooks/development.yml b/playbooks/development.yml index 7b07e01..fac61be 100644 --- a/playbooks/development.yml +++ b/playbooks/development.yml @@ -5,6 +5,7 @@ strategy: free roles: + - {role: timeshift, tags: ['timeshift', 'snapshot']} # Create snapshot before changes - {role: maintenance, tags: ['maintenance']} - {role: base, tags: ['base', 'security']} - {role: user, tags: ['user']} diff --git a/playbooks/shell.yml b/playbooks/shell.yml index 1cfb4d2..e1da177 100644 --- a/playbooks/shell.yml +++ b/playbooks/shell.yml @@ -16,6 +16,27 @@ - {role: shell, tags: ['shell']} pre_tasks: + - name: Check if NodeSource repository exists + ansible.builtin.stat: + path: /etc/apt/sources.list.d/nodesource.list + register: nodesource_repo_file + failed_when: false + + - name: Check if NodeSource GPG key exists + ansible.builtin.stat: + path: /etc/apt/keyrings/nodesource.gpg + register: nodesource_key_file + failed_when: false + + - name: Remove incorrectly configured NodeSource repository + ansible.builtin.file: + path: /etc/apt/sources.list.d/nodesource.list + state: absent + become: true + when: + - nodesource_repo_file.stat.exists + - not (nodesource_key_file.stat.exists and nodesource_key_file.stat.size > 0) + - name: Update apt cache ansible.builtin.apt: update_cache: true diff --git a/playbooks/timeshift.yml b/playbooks/timeshift.yml new file mode 100644 index 0000000..6a74bcf --- /dev/null +++ b/playbooks/timeshift.yml @@ -0,0 +1,28 @@ +--- +- name: Timeshift operations + hosts: all + become: true + gather_facts: false + + tasks: + - name: List Timeshift snapshots + ansible.builtin.command: timeshift --list + register: timeshift_list_result + when: timeshift_action == "list" + changed_when: false + + - name: Display snapshots + ansible.builtin.debug: + msg: "{{ timeshift_list_result.stdout_lines }}" + when: timeshift_action == "list" + + - name: Restore from snapshot + ansible.builtin.command: timeshift --restore --snapshot "{{ timeshift_snapshot }}" --scripted # noqa command-instead-of-module + when: timeshift_action == "restore" + register: timeshift_restore_result + changed_when: false + + - name: Display restore result + ansible.builtin.debug: + msg: "{{ timeshift_restore_result.stdout_lines }}" + when: timeshift_action == "restore" diff --git a/roles/base/defaults/main.yml b/roles/base/defaults/main.yml index eb0f24a..56fee85 100644 --- a/roles/base/defaults/main.yml +++ b/roles/base/defaults/main.yml @@ -1,2 +1,8 @@ --- # defaults file for base + +# Fail2ban email configuration +# Set these in group_vars/all/main.yml or host_vars to enable email notifications +fail2ban_destemail: "" # Empty by default - no email notifications +fail2ban_sender: "" # Empty by default +fail2ban_action: "%(action_mwl)s" # Mail, whois, and log action diff --git a/roles/base/tasks/main.yml b/roles/base/tasks/main.yml index 57f34bc..22f1972 100644 --- a/roles/base/tasks/main.yml +++ b/roles/base/tasks/main.yml @@ -25,6 +25,9 @@ - jq - ripgrep - fd-find + # Power management (TLP for laptops) + - tlp + - tlp-rdw state: present - name: Install yq YAML processor @@ -68,3 +71,12 @@ community.general.locale_gen: name: "{{ locale | default('en_US.UTF-8') }}" state: present + +- name: Enable and start TLP service + ansible.builtin.systemd: + name: tlp + enabled: true + state: started + daemon_reload: true + become: true + when: "'tlp' in ansible_facts.packages" diff --git a/roles/base/templates/jail.local.j2 b/roles/base/templates/jail.local.j2 index fdf8e1d..c3b1449 100644 --- a/roles/base/templates/jail.local.j2 +++ b/roles/base/templates/jail.local.j2 @@ -6,10 +6,14 @@ findtime = 600 # Allow 3 failures before banning maxretry = 3 -# Email notifications (uncomment and configure if needed) -destemail = idobkin@gmail.com -sender = idobkin@gmail.com -action = %(action_mwl)s +# Email notifications (configured via fail2ban_destemail variable) +{% if fail2ban_destemail | default('') | length > 0 %} +destemail = {{ fail2ban_destemail }} +sender = {{ fail2ban_sender | default(fail2ban_destemail) }} +action = {{ fail2ban_action | default('%(action_mwl)s') }} +{% else %} +# Email notifications disabled (set fail2ban_destemail in group_vars/all/main.yml to enable) +{% endif %} [sshd] enabled = true diff --git a/roles/development/tasks/main.yml b/roles/development/tasks/main.yml index 86a03db..14dac73 100644 --- a/roles/development/tasks/main.yml +++ b/roles/development/tasks/main.yml @@ -30,7 +30,7 @@ fi register: nodesource_repo_check failed_when: false - changed_when: false + changed_when: false # noqa command-instead-of-module when: node_version_check.rc != 0 or not node_version_check.stdout.startswith('v22') - name: Check if NodeSource GPG key exists and is correct @@ -46,7 +46,11 @@ fi register: nodesource_key_check failed_when: false +<<<<<<< HEAD changed_when: false +======= + changed_when: false # noqa command-instead-of-module +>>>>>>> 5d3b339 (Fix: Resolve linting errors and improve firewall configuration) when: node_version_check.rc != 0 or not node_version_check.stdout.startswith('v22') - name: Remove incorrect NodeSource repository @@ -88,6 +92,15 @@ - node_version_check.rc != 0 or not node_version_check.stdout.startswith('v22') - nodesource_key_check.stdout in ["not_exists", "wrong_key"] +- name: Import NodeSource GPG key into apt keyring + ansible.builtin.apt_key: + file: /etc/apt/keyrings/nodesource.gpg + state: present + become: true + when: + - node_version_check.rc != 0 or not node_version_check.stdout.startswith('v22') + - nodesource_key_check.stdout in ["not_exists", "wrong_key"] + - name: Add NodeSource repository only if needed ansible.builtin.apt_repository: repo: "deb [signed-by=/etc/apt/keyrings/nodesource.gpg] https://deb.nodesource.com/node_22.x nodistro main" diff --git a/roles/monitoring/templates/jail.local.j2 b/roles/monitoring/templates/jail.local.j2 index fdf8e1d..c3b1449 100644 --- a/roles/monitoring/templates/jail.local.j2 +++ b/roles/monitoring/templates/jail.local.j2 @@ -6,10 +6,14 @@ findtime = 600 # Allow 3 failures before banning maxretry = 3 -# Email notifications (uncomment and configure if needed) -destemail = idobkin@gmail.com -sender = idobkin@gmail.com -action = %(action_mwl)s +# Email notifications (configured via fail2ban_destemail variable) +{% if fail2ban_destemail | default('') | length > 0 %} +destemail = {{ fail2ban_destemail }} +sender = {{ fail2ban_sender | default(fail2ban_destemail) }} +action = {{ fail2ban_action | default('%(action_mwl)s') }} +{% else %} +# Email notifications disabled (set fail2ban_destemail in group_vars/all/main.yml to enable) +{% endif %} [sshd] enabled = true diff --git a/roles/ssh/defaults/main.yml b/roles/ssh/defaults/main.yml index da89ffc..342fe86 100644 --- a/roles/ssh/defaults/main.yml +++ b/roles/ssh/defaults/main.yml @@ -2,8 +2,10 @@ # SSH server configuration ssh_port: 22 ssh_listen_addresses: ['0.0.0.0'] -ssh_permit_root_login: 'yes' -ssh_password_authentication: 'yes' +# Security defaults - hardened by default +# Override in group_vars for dev/desktop machines if needed +ssh_permit_root_login: 'prohibit-password' # Allow root only with keys, not passwords +ssh_password_authentication: 'no' # Disable password auth by default (use keys) ssh_pubkey_authentication: 'yes' ssh_max_auth_tries: 3 ssh_client_alive_interval: 300 diff --git a/roles/ssh/tasks/main.yml b/roles/ssh/tasks/main.yml index 15586e2..599941b 100644 --- a/roles/ssh/tasks/main.yml +++ b/roles/ssh/tasks/main.yml @@ -33,7 +33,16 @@ name: OpenSSH failed_when: false -- name: Enable UFW with deny default policy +- name: Set UFW default policy for incoming (deny) + community.general.ufw: + direction: incoming + policy: deny + +- name: Set UFW default policy for outgoing (allow) + community.general.ufw: + direction: outgoing + policy: allow + +- name: Enable UFW firewall community.general.ufw: state: enabled - policy: deny diff --git a/roles/timeshift/README.md b/roles/timeshift/README.md new file mode 100644 index 0000000..f995ae8 --- /dev/null +++ b/roles/timeshift/README.md @@ -0,0 +1,100 @@ +# Timeshift Role + +Manages Timeshift system snapshots for backup and rollback capabilities. + +## Purpose + +This role installs and configures Timeshift, a system restore utility for Linux. It can automatically create snapshots before playbook execution to enable easy rollback if something goes wrong. + +## Features + +- Installs Timeshift package +- Creates automatic snapshots before playbook runs +- Configurable snapshot retention +- Easy rollback capability + +## Variables + +### Installation +- `timeshift_install` (default: `true`) - Install Timeshift package + +### Snapshot Settings +- `timeshift_auto_snapshot` (default: `true`) - Automatically create snapshot before playbook execution +- `timeshift_snapshot_description` (default: `"Ansible playbook snapshot"`) - Description for snapshots +- `timeshift_snapshot_tags` (default: `["ansible", "pre-playbook"]`) - Tags for snapshots +- `timeshift_snapshot_type` (default: `"RSYNC"`) - Snapshot type: RSYNC or BTRFS + +### Retention +- `timeshift_keep_daily` (default: `7`) - Keep daily snapshots for N days +- `timeshift_keep_weekly` (default: `4`) - Keep weekly snapshots for N weeks +- `timeshift_keep_monthly` (default: `6`) - Keep monthly snapshots for N months + +### Location +- `timeshift_snapshot_location` (default: `"/timeshift"`) - Where to store snapshots + +## Usage + +### Basic Usage + +Add to your playbook: +```yaml +roles: + - { role: timeshift, tags: ['timeshift', 'snapshot'] } +``` + +### Disable Auto-Snapshot + +```yaml +roles: + - { role: timeshift, tags: ['timeshift'] } +``` + +In host_vars or group_vars: +```yaml +timeshift_auto_snapshot: false +``` + +### Manual Snapshot + +```bash +# On the target host +sudo timeshift --create --comments "Manual snapshot before changes" +``` + +### Rollback + +```bash +# List snapshots +sudo timeshift --list + +# Restore from snapshot +sudo timeshift --restore --snapshot 'YYYY-MM-DD_HH-MM-SS' + +# Or use the Makefile target +make timeshift-restore HOST=dev02 SNAPSHOT=2025-12-17_21-30-00 +``` + +## Integration with Playbooks + +The role is designed to be run early in playbooks to create snapshots before making changes: + +```yaml +roles: + - { role: timeshift, tags: ['timeshift', 'snapshot'] } # Create snapshot first + - { role: base } + - { role: development } + # ... other roles +``` + +## Dependencies + +- Debian/Ubuntu-based system +- Root/sudo access + +## Notes + +- Snapshots require significant disk space +- RSYNC snapshots are larger but work on any filesystem +- BTRFS snapshots are smaller but require BTRFS filesystem +- Snapshots exclude `/home` by default (configurable) + diff --git a/roles/timeshift/defaults/main.yml b/roles/timeshift/defaults/main.yml new file mode 100644 index 0000000..16b8d83 --- /dev/null +++ b/roles/timeshift/defaults/main.yml @@ -0,0 +1,21 @@ +--- +# Timeshift role defaults + +# Install Timeshift +timeshift_install: true + +# Timeshift snapshot settings +timeshift_snapshot_type: "RSYNC" # RSYNC or BTRFS +timeshift_snapshot_description: "Ansible playbook snapshot" +timeshift_snapshot_tags: ["ansible", "pre-playbook"] + +# Auto-create snapshot before playbook runs +timeshift_auto_snapshot: true + +# Retention settings +timeshift_keep_daily: 7 +timeshift_keep_weekly: 4 +timeshift_keep_monthly: 6 + +# Snapshot location (default: /timeshift) +timeshift_snapshot_location: "/timeshift" diff --git a/roles/timeshift/tasks/main.yml b/roles/timeshift/tasks/main.yml new file mode 100644 index 0000000..1d30f20 --- /dev/null +++ b/roles/timeshift/tasks/main.yml @@ -0,0 +1,52 @@ +--- +- name: Check if Timeshift is installed + ansible.builtin.command: timeshift --version + register: timeshift_check + failed_when: false + changed_when: false + +- name: Install Timeshift + ansible.builtin.apt: + name: timeshift + state: present + become: true + when: + - timeshift_install | default(true) | bool + - timeshift_check.rc != 0 + +- name: Create Timeshift snapshot directory + ansible.builtin.file: + path: "{{ timeshift_snapshot_location }}" + state: directory + mode: '0755' + become: true + when: timeshift_install | default(true) | bool + +- name: Create snapshot before playbook execution + ansible.builtin.command: > + timeshift --create + --comments "{{ timeshift_snapshot_description }}" + --tags {{ timeshift_snapshot_tags | join(',') }} + --scripted + become: true + register: timeshift_snapshot_result + when: + - timeshift_auto_snapshot | default(true) | bool + - timeshift_check.rc == 0 or timeshift_install | default(true) | bool + changed_when: "'Snapshot created successfully' in timeshift_snapshot_result.stdout or 'Created snapshot' in timeshift_snapshot_result.stdout" + failed_when: > + timeshift_snapshot_result.rc != 0 + and "'already exists' not in timeshift_snapshot_result.stderr | default('')" + and "'Snapshot created' not in timeshift_snapshot_result.stderr | default('')" + ignore_errors: true + +- name: Display snapshot information + ansible.builtin.debug: + msg: + - "Timeshift snapshot operation completed" + - "Output: {{ timeshift_snapshot_result.stdout | default('Check with: sudo timeshift --list') }}" + - "To list snapshots: sudo timeshift --list" + - "To restore: sudo timeshift --restore --snapshot 'SNAPSHOT_NAME'" + when: + - timeshift_auto_snapshot | default(true) | bool + - timeshift_snapshot_result is defined