Scaling Ansible Variable Management with Nested group_vars and host_vars
Why Flat Variables Break Down in Multi-Tenant IaC
Ansible's variable system is intentionally simple. For single-environment projects, group_vars and host_vars are usually sufficient.
Once an Ansible repository needs to support multiple customers, multiple environments, and security-sensitive configuration, the default flat model starts to show structural limits.
This article introduces rf_nested_vars, a production-grade Ansible vars plugin that enables nested variable hierarchies, explicit scoping, and deterministic deep-merge behavior — without changing playbooks or breaking Ansible's native semantics.
The Core Idea: Configuration as Layers, Not Files
global defaults
→ customer defaults
→ environment overrides
→ host overrides
Each layer extends the previous one using deep merges instead of destructive overwrites.
Directory Structure That Scales
group_vars/
all/
10-infrastructure.yml
20-security.yml
c_00000_acme/
dev/
all.yml
40-applications.yml
host_vars/
c_00000_acme/
dev/
srv-wireguard-01.yml
Enforced Scoping
export IAC_CUSTOMER=c_00000_acme
export IAC_ENV=dev
ansible-playbook site.yml
Only matching variable trees are loaded, preventing cross-tenant leakage.
Deep Merge Example
# Base configuration
applications:
wireguard:
enabled: true
port: 51820
Override:
# Environment override
applications:
wireguard:
port: 51830
Result:
# Final merged configuration
applications:
wireguard:
enabled: true
port: 51830
Real-World Benefits
1. Security Isolation
Variables are scoped by customer and environment. A playbook running for customer A cannot accidentally access customer B's secrets or configuration.
2. DRY Configuration
Common settings live in group_vars/all/. Customer-specific defaults in group_vars/{customer}/. Environment tweaks in group_vars/{customer}/{env}/. No duplication.
3. Predictable Behavior
Deep merges follow consistent rules. Lists can be replaced or extended. Dictionaries merge recursively. No surprises in production.
4. Audit Trail
Every variable can be traced to its source file. Debug mode shows the merge order and final result for each host.
Implementation Details
The plugin hooks into Ansible's variable loading pipeline at the correct stage to:
- Read environment variables for customer/environment context
- Build the directory hierarchy to traverse
- Load YAML files in lexical order (hence
10-,20-prefixes) - Deep merge using configurable strategies
- Return the final variable dictionary to Ansible
Production Patterns
Secret Management
# group_vars/c_00000_acme/prod/vault.yml
$ANSIBLE_VAULT;1.1;AES256
...
Vaulted files follow the same merge rules, keeping secrets close to their usage context.
Feature Flags
# group_vars/all/features.yml
features:
monitoring: true
backup: true
# group_vars/c_00000_acme/dev/features.yml
features:
debug: true
Network Configuration
# group_vars/c_00000_acme/all.yml
networks:
management:
cidr: 10.0.0.0/24
# group_vars/c_00000_acme/prod/networks.yml
networks:
management:
gateway: 10.0.0.1
dns:
- 10.0.0.2
- 10.0.0.3
Conclusion
rf_nested_vars enables safe, scalable, multi-tenant Ansible repositories with deterministic behavior and minimal duplication.
For teams managing infrastructure across multiple customers and environments, it transforms Ansible from a configuration management tool into a true multi-tenant platform.
The plugin is open source and has been battle-tested in production environments managing hundreds of hosts across dozens of customers.
rf_nested_vars has been successfully deployed across numerous enterprise customer projects, proving its value in real-world production environments.