Scaling Ansible Variable Management with Nested group_vars and host_vars

DevOpsAnsibleInfrastructure as CodeMulti-TenancyConfiguration Management

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:

  1. Read environment variables for customer/environment context
  2. Build the directory hierarchy to traverse
  3. Load YAML files in lexical order (hence 10-, 20- prefixes)
  4. Deep merge using configurable strategies
  5. 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.

Scaling Ansible Variable Management with Nested group_vars and host_vars - Patrick Paechnatz