The script is free. Peace of mind is not.
This repository delivers a reproducible hardening baseline, zero-trust access patterns, and optional containerized application bundles for managed infrastructure.
- Overview
- Features
- Value Snapshot for CTO/CFO
- FinOps Case Study (Nuntu)
- Field Validation Evidence
- Compliance & Standards
- Quick Start
- Operations with Make
- Architecture
- Docker & Deployment
- Configuration & Secrets
- Validation & Quality Gates
- Tests
- Security
- Changelog
- Contributing
- License
- Documentation Guide
- Contact & Support
Developmi Hardened is an Ansible-based infrastructure automation project focused on establishing a secure, auditable, and repeatable baseline across mixed-host environments.
It is designed to standardize the security posture of:
- Brain nodes for central services, ingress, and observability.
- Muscle nodes for workload execution and optional edge services.
- Application stacks under
apps/are operator-managed and deploy first-class via native Docker Compose (git pull+docker compose uponpublic_net); Portainer (Edge agent) is an optional manager whenenable_portainer: true(ADR-07).
The project aligns to NIST 800-53 controls and emphasizes secrets handling, least privilege, hardened networking, and operational repeatability.
- 🛡️ Security-first hardening with SSH restrictions, firewall controls, audit logging, CrowdSec integration, and Vault-backed secrets.
- 🔐 Zero-trust networking through Tailscale ACL-driven access and minimized public exposure.
- 🧱 Modular architecture using Ansible roles for security, Docker orchestration, observability, compliance, ingress, and Portainer edge operations.
- 📦 Optional application bundles for Chatwoot, Metabase, n8n, OpenWebUI, Twenty CRM, and Uptime Kuma.
- 📈 Operational visibility with exporter and observability stack support when capacity allows.
- 🧪 Validation gates executed through Make targets (uv-backed) for linting, syntax checks, and secret scanning.
- 🧭 Documented operating model with commands centralized in
docs/operations/OPERATIONS_RUNBOOK.md.
In less than 30 seconds:
- Cost Control: Designed for self-hosted operation on VPS/Bare Metal to avoid linear SaaS cost growth.
- Security Baseline: NIST-aligned hardening with zero-trust networking and auditable controls.
- Data Sovereignty: Sensitive workloads stay in infrastructure you control.
- Cloud-Exit Ready: Portable Ansible playbooks and provider-agnostic architecture reduce lock-in.
- Operational Predictability: Pull-based management model and Make-driven runbooks reduce change risk.
This project pattern has been applied to a real-world migration scenario (codenamed Nuntu) focused on sovereignty, security, and OpEx reduction.
- SaaS sprawl with linear OpEx growth by headcount.
- Data processed in third-party multi-tenant platforms.
- Vendor/API dependence creating operational fragility.
- Sovereign self-hosted stack on high-performance VPS fleet.
- Pull-based operations model (Portainer Edge pattern).
- Caddy + WAF perimeter with hardened default-deny posture.
- Security automation and compliance-oriented runbooks.
| Metric | Before (SaaS Sprawl) | After (Sovereign Self-Hosted) | Impact |
|---|---|---|---|
| Annual Software OpEx | $X (baseline) | $0.3X | -70% |
| Platform Uptime (Prod) | ~99.5% | 99.8% | Higher reliability |
| Data Sovereignty | 0% | 100% | Full control |
| WAF Efficacy | N/A | >99% block rate, <1% false positives | Enterprise-grade perimeter |
| Incident Response Time | Hours/Days | Minutes | Stronger resilience |
| Vendor Risk | Critical | Negligible | Supply-chain risk reduced |
Scope note: This case study is a field implementation narrative and not a vendor benchmark report. Results depend on workload, architecture, and governance discipline.
Current documented execution evidence in this repository corresponds to a lab/staging scope with:
- 1 Brain node
- 2 Muscle nodes
This is intentionally presented as operational proof-of-execution while broader fleet rollouts are scheduled.
This repository is not just "NIST-themed". It includes implementation-grounded compliance references with auditable mappings and evidence workflows.
- NIST SP 800-53: AC-2, CM-7, SC-7, SI-4, AU-12, and SC-28 (partial for full disk encryption).
- NIST SP 800-207 (Zero Trust): overlay-network control path, identity/tag-based access, and pull-based management pattern.
- CIS Level 1 (generic Ubuntu/Debian alignment): SSH baseline, firewall posture, brute-force mitigation, and audit telemetry.
- DORA/ENS contextual mapping: documented as technical-functional alignment for resilience and governance discussions.
- Compliance framework status and mapping: docs/compliance/COMPLIANCE-MAPPING-STATUS.md
- Reproducible evidence workflow: docs/compliance/evidence/EVIDENCE_MODEL.md
Important: This project provides implementation evidence and technical mappings. Formal certification readiness still requires organization-specific legal, scope, and auditor validation.
uvfor Python dependency and environment management.- Python 3.14 or newer.
- SSH access to the target hosts.
- Ansible Galaxy network access for collection installation.
- Docker Compose only if you plan to run optional app bundles.
git clone https://github.com/Developmi/hardened.git
cd hardened
make sync
make install-collectionsCreate or customize your inventory before deployment:
[brain]
brain-1 ansible_host=YOUR_PUBLIC_IP ansible_user=root public_ip=YOUR_PUBLIC_IP
[muscle]
muscle-1 ansible_host=YOUR_PUBLIC_IP ansible_user=ubuntu public_ip=YOUR_PUBLIC_IPPopulate the SOPS-encrypted secrets file and encrypt it before deployment (SOPS + age replaces the old Ansible Vault workflow; the Tailscale auth/ACL keys remain vaulted until expiry):
# 1. Generate the age keypair and back it up OFFLINE
age-keygen -o age/keys.txt
# 2. Replace the age1<PLACEHOLDER> recipient in .sops.yaml with your public key
# 3. Create + fill + encrypt the secrets file
make sops-init
make sops-encryptmake check-toolchain
make deploy-hardening
make deploy-engine
make deploy-edge BACKEND=caddy TARGET=<brain>
make deploy-portainer
make run PLAYBOOK=playbooks/l3/stack.yml TAGS='l3-observability,stack'Note: The canonical command surface lives in docs/operations/OPERATIONS_RUNBOOK.md. Use
maketargets instead of raw playbook calls when possible.
Make is the official command interface for this project. Day-to-day operations should run through Make targets.
make help
make sync
make install-collections
make check-toolchain
make deploy-hardening
make deploy-engine
make deploy-edge BACKEND=caddy TARGET=<brain>
make deploy-portainer
make run PLAYBOOK=playbooks/l3/stack.yml TAGS='l3-observability,stack'
make verify-tailscale
make verify-crowdsec
make verify-observabilitymake run PLAYBOOK=playbooks/site.yml TAGS='nist,sc-7'
make run PLAYBOOK=playbooks/site.yml SKIP_TAGS='tailscale,vpn'
make deploy-compliance
make nuke CONFIRM=DESTROY_ALL_INFRASTRUCTURE
make audit-fullOperational reference index:
- Primary runbook: docs/operations/OPERATIONS_RUNBOOK.md
- Production command-path controls: docs/operations/OPERATIONS_RUNBOOK.md
- Application deployment (via Portainer): docs/operations/OPERATIONS_RUNBOOK.md
.
├── playbooks/site.yml # Base hardening entry point
├── playbooks/l1/ # L1 - OS baseline
├── playbooks/l2/ # L2 - Compliance, hardening
├── playbooks/l3/ # L3 - Observability, exporters
├── playbooks/l4/ # L4 - Networking/Edge proxy
├── playbooks/l6/ # L6 - Runtime (Engine, Portainer, backups)
├── playbooks/ops/ # Operational playbooks (nuke, bootstrap, validate)
├── inventory/ # Target host inventory definitions
├── group_vars/ # Shared and group-specific variables
├── roles/ # Ansible roles for platform capabilities
├── apps/ # L5 application profiles (profile, vars)
├── docs/ # Operational, compliance, and project documentation
└── scripts/ # Bootstrap and monitoring helpers
flowchart LR
Operator[Operator] --> Make[Make Targets]
Make --> Ansible[Ansible Playbooks]
Ansible --> SOPS[Encrypted Secrets]
Ansible --> Hosts[Brain and Muscle Hosts]
Hosts --> Docker[Optional Docker Compose Bundles]
Hosts --> Security[Hardening, Compliance, and Monitoring]
The role structure is intentionally separated so security controls, Docker orchestration, observability, and ingress can evolve independently without coupling the baseline hardening path.
Docker is used for application stacks and observability services, not as the primary automation runtime.
All 8 application profiles (Chatwoot, Metabase, n8n, NocoDB, OpenWebUI, Twenty CRM, Uptime Kuma, FastAPI) deploy as Docker Compose stacks from structured profiles under apps/, rendered by the L6 runtime. Compose does not depend on Portainer (ADR-07): with the optional manager enabled (enable_portainer: true), the same stacks can be managed through Portainer's UI (Edge agent); with the default enable_portainer: false, a compose-only deploy needs zero portainer_* variables. See ARCHITECTURE.md §Application Profiles for the full schema.
- Prefer publishing services through the hardened ingress layer instead of exposing broad host ports.
- Use the provided SOPS workflow for sensitive runtime values.
- Application stacks are intended to run behind the project's reverse proxy and network segmentation model.
- App configuration is operator-managed: each app has a pinned
docker-compose.ymlplus a.env(template:apps/<name>/.env.example). The old Ansible-managedapps/<name>/vars.ymlwas removed (2026-07-31).
This project does not require a root .env.example. Runtime secrets are encrypted with SOPS + age and loaded transparently by the community.sops vars plugin from group_vars/all/secrets.sops.yml and group_vars/all/managers/portainer.sops.yml (the Tailscale auth/ACL keys remain in the Ansible Vault until expiry). Application-specific configuration is operator-managed via apps/<name>/.env, templated from apps/<name>/.env.example. See ARCHITECTURE.md §App Profiles for the profile schema.
# group_vars/all/secrets.yml.example (fill into secrets.sops.yml, then: make sops-encrypt)
vault_github_token: "GITHUB_TOKEN_GOES_HERE"
caddy_acme_email: "ops@example.com"
# Portainer edge keys live in group_vars/all/managers/portainer.sops.yml:
# portainer_edge_keys_by_node:
# brain-1: "PORTAINER_EDGE_KEY_FOR_BRAIN_1"
# muscle-1: "PORTAINER_EDGE_KEY_FOR_MUSCLE_1"These are required only when the observability stack is enabled:
observability_stack_host_ipobservability_grafana_admin_userobservability_grafana_admin_passwordobservability_grafana_root_url
Application variables are managed through the Ansible variable hierarchy (5-tier precedence). Each app has:
apps/<name>/docker-compose.yml- pinned compose stack; env viaapps/<name>/.env.example(operator-managed)apps/<name>/profile.yml- metadata (version, DB type, backup schedule, monitoring)
Apps deploy as Compose stacks (optionally managed via Portainer). See OPERATIONS_RUNBOOK.md §3 for the full deployment guide.
The repository is validated through uv-managed tooling and Ansible-native checks.
make sync
make install-collections
make check-toolchain
make lint PLAYBOOK=playbooks/site.yml
make precommit-runCurrent quality gates include:
- YAML formatting validation.
- Ansible playbook syntax checks.
- Role and playbook linting.
- Secret detection with a tracked baseline.
Operational note:
make lintis intentionally strict and should be used before changes are promoted to shared environments.
This project is validated through Make-driven quality gates. For production-grade role testing, use molecule or ansible-test with a local inventory:
make check-toolchain
make lint PLAYBOOK=playbooks/site.yml
make precommit-runCI pipeline: All playbooks pass syntax check and linting on every PR via GitHub Actions. A dedicated security-audit.yml workflow runs on version tags for release gating.
Note: Automated role-level integration testing (e.g., Molecule) is on the roadmap. Current validation focuses on syntax, linting, idempotency dry-runs, and secret scanning - all exercised through
maketargets and CI.
This project follows a coordinated disclosure policy. If you discover a vulnerability, do not open a public issue. See SECURITY.md for reporting instructions, supported versions, and response timelines.
See CHANGELOG.md for the full version history. The project follows Keep a Changelog and Semantic Versioning.
Contributions are welcome. Please read CONTRIBUTING.md before opening a pull request. This project follows Conventional Commits and the Developmi engineering standard.
Copyright © 2026 Miguel Lozano | Developmi. All rights reserved. Licensed under the MIT License.
For the full documentation index including architecture, compliance, operations, and project docs, see docs/README.md.
- Maintained by: Miguel Lozano | Developmi
- Role: Cloud & Infrastructure Engineer | FinOps & Bare Metal Specialist | AI Sovereignty Strategist under NIST/DORA Standards
- Philosophy: Security is not a feature; it is the baseline.
- Website: Developmi
- GitHub: Miguel-DevOps
- LinkedIn: Miguel Lozano
© 2026 Miguel Lozano | Developmi. All rights reserved.
- docs/README.md - Documentation index
- docs/architecture/ARCHITECTURE.md - System design and security layers
- docs/operations/OPERATIONS_RUNBOOK.md - Operational command reference
- docs/compliance/COMPLIANCE-MAPPING-STATUS.md - Compliance framework status and mapping
- CONTRIBUTING.md - Contribution guide (redirect)


