This project provides a GitOps approach to managing firewall configurations using Terraform modules. Network developers can define firewall rules using simple YAML configuration files, which are then automatically converted to Terraform and applied via GitLab CI/CD.
- YAML-based Configuration: Simple, human-readable firewall rule definitions
- GitOps Workflow: Version-controlled infrastructure with automated deployments
- Multi-Environment Support: Separate configurations for dev, staging, and production
- Automated Validation: YAML schema validation and Terraform plan checks
- Security Scanning: Built-in security best practices validation
- Approval Workflows: Manual approval gates for production changes
- ✅ Palo Alto Networks (PAN-OS) - Full support for Panorama and standalone NGFW
- 🚧 Fortinet (planned for future release)
- 🚧 Check Point (planned for future release)
firewall-gitops/
├── clusters/ # Cluster-specific configurations
│ └── example/
│ ├── cluster.yaml # Cluster metadata and firewall settings
│ ├── objects.yaml # Single file with all objects/addresses/services (Option 1)
│ └── objects/ # OR multiple split files (Option 2)
│ ├── addresses.yaml # Address objects only
│ ├── services.yaml # Service objects only
│ ├── trust-zone.yaml # Rules for trust zone
│ └── dmz-zone.yaml # Rules and zone-specific objects
├── modules/ # Terraform modules
│ ├── palo-alto/ # Palo Alto Networks module
│ │ ├── main.tf
│ │ └── variables.tf
│ └── shared/ # Shared modules and utilities
├── terraform/ # Main Terraform configuration
│ ├── main.tf # YAML parser and module calls
│ └── variables.tf
├── scripts/ # Helper scripts
│ ├── validate_yaml.py # YAML validation script
│ └── deploy.sh # Local deployment script
├── schemas/ # JSON schemas for validation
│ ├── cluster.schema.json # Cluster configuration schema
│ ├── rules.schema.json # Rules configuration schema
│ └── README.md # Schema documentation
├── docs/ # Documentation
│ ├── configuration.md # Configuration guide
│ └── getting-started.md # Getting started guide
├── requirements.txt # Python dependencies
└── README.md
# Create cluster directory
mkdir -p clusters/my-cluster
# Copy example configurations
cp clusters/example/* clusters/my-cluster/
# Edit configurations for your environment
vim clusters/my-cluster/cluster.yaml
vim clusters/my-cluster/objects.yaml# Set up GitLab environment variables for state management
export GITLAB_PROJECT_ID="your-project-id"
export GITLAB_TOKEN="your-personal-access-token"
export GITLAB_API_URL="https://gitlab.com/api/v4"
export GITLAB_USERNAME="your-gitlab-username"# Install dependencies (use virtual environment)
python3 -m venv venv
source venv/bin/activate
pip install -r requirements.txt
# Validate YAML configuration
python scripts/validate_yaml.py# Local deployment (development)
./scripts/deploy.sh -c my-cluster -a plan
# Apply changes
./scripts/deploy.sh -c my-cluster -a apply -y- Create a feature branch for your changes
- Modify cluster configurations in YAML files
- Commit and push to GitLab
- Create a merge request - pipeline will validate automatically
- Merge to main - changes deploy automatically (with approval for production)
- Getting Started Guide - Detailed setup and usage instructions
- Configuration Guide - Complete YAML configuration reference
- Example Configurations - See
clusters/directory for working examples
- Terraform >= 1.0
- Python >= 3.8 (for validation scripts)
- Git for version control
- GitLab for CI/CD pipeline
- Palo Alto Networks: API access to Panorama or NGFW
- Permissions: Device group management (Panorama) or configuration management (NGFW)
paloaltonetworks/panos>= 2.0.5
You have two options for organizing your firewall configurations:
All addresses, services, and rules in one file:
clusters/my-cluster/
├── cluster.yaml
└── objects.yaml # Contains addresses, services, and rules
Split configurations across multiple files in a objects/ folder:
clusters/my-cluster/
├── cluster.yaml
└── objects/
├── addresses.yaml # Just addresses
├── services.yaml # Just services
├── trust-zone.yaml # Rules for trust zone
└── dmz-zone.yaml # Rules and zone-specific objects
Benefits of split configuration:
- Better organization for large rule sets
- Easier collaboration (fewer merge conflicts)
- Zone-based or team-based file separation
- Each file can contain any combination of addresses, services, and rules
- Terraform automatically merges all files during deployment
# clusters/my-cluster/objects.yaml
addresses:
- name: 'web-server'
ip_netmask: '192.168.1.100/32'
description: 'Web server address'
tags: ['web', 'server']
- name: 'app-servers'
ip_netmask: '10.1.1.0/24'
description: 'Application server subnet'
tags: ['app', 'backend']
services:
- name: 'web-service'
type: 'tcp'
destination_port: '80'
source_port: '1024-65535'
description: 'Web service HTTP'
tags: ['web', 'http']
- name: 'https-service'
type: 'tcp'
destination_port: '443'
source_port: '1024-65535'
description: 'Web service HTTPS'
tags: ['web', 'https']
rules:
- name: 'allow-web-traffic'
description: 'Allow HTTP traffic to web server'
source_zones: ['trust']
destination_zones: ['dmz']
source_addresses: ['any']
destination_addresses: ['web-server']
applications: ['web-browsing']
services: ['web-service']
action: 'allow'
log_end: true
- name: 'allow-https-traffic'
description: 'Allow HTTPS traffic to web server'
source_zones: ['trust']
destination_zones: ['dmz']
source_addresses: ['any']
destination_addresses: ['web-server']
applications: ['ssl']
services: ['https-service']
action: 'allow'
log_end: trueWhen using the objects/ folder approach, each file can contain addresses, services, or rules independently:
# clusters/my-cluster/objects/addresses.yaml
# This file contains ONLY address objects
addresses:
- name: 'web-server'
ip_netmask: '192.168.1.100/32'
description: 'Web server address'
tags: ['web', 'server']
- name: 'db-server'
ip_netmask: '192.168.2.50/32'
description: 'Database server'
tags: ['database', 'server']# clusters/my-cluster/objects/services.yaml
# This file contains ONLY service objects
services:
- name: 'web-service'
type: 'tcp'
destination_port: '80'
source_port: '1024-65535'
description: 'Web service HTTP'
tags: ['web', 'http']# clusters/my-cluster/objects/trust-zone.yaml
# This file contains ONLY rules
rules:
- name: 'allow-web-traffic'
source_zones: ['trust']
destination_zones: ['dmz']
source_addresses: ['any']
destination_addresses: ['web-server']
applications: ['web-browsing']
services: ['web-service']
action: 'allow'
log_end: true# clusters/my-cluster/objects/dmz-zone.yaml
# This file contains addresses, services, AND rules together
addresses:
- name: 'dmz-proxy'
ip_netmask: '10.0.1.10/32'
description: 'DMZ proxy server'
services:
- name: 'proxy-service'
type: 'tcp'
destination_port: '8080'
source_port: '1024-65535'
rules:
- name: 'allow-dmz-internet'
source_zones: ['dmz']
destination_zones: ['untrust']
source_addresses: ['dmz-proxy']
destination_addresses: ['any']
applications: ['web-browsing']
services: ['application-default']
action: 'allow'Note: Terraform will automatically merge all YAML files from the objects/ folder:
- All addresses from all files are combined into one list
- All services from all files are combined into one list
- All rule groups from all files are merged together
The schema supports multiple address object types based on Terraform variables:
addresses:
# IP with netmask
- name: 'subnet-example'
ip_netmask: '192.168.1.0/24'
description: 'Network subnet'
# IP range
- name: 'range-example'
ip_range: '192.168.1.10-192.168.1.20'
description: 'IP address range'
# FQDN
- name: 'domain-example'
fqdn: 'example.com'
description: 'Domain name'
# IP with wildcard mask
- name: 'wildcard-example'
ip_wildcard: '192.168.1.0/0.0.0.255'
description: 'Wildcard address'- JSON Schema Validation: Comprehensive validation using auto-generated schemas from Terraform variables
- Type Safety: Strict type checking for all configuration fields with proper null handling
- Input Validation: Regex patterns for IP addresses, ports, FQDNs, and other network objects
- Configuration Consistency: Ensures all required fields are present and valid
- Audit Trail: Full Git history of all configuration changes
- Principle of Least Privilege: Encourages minimal access patterns
The project includes comprehensive JSON schemas that are automatically generated from Terraform module variables:
- Address Objects: Support for
ip_netmask,ip_range,ip_wildcard, andfqdnwith validation - Service Objects: TCP/UDP services with port validation and source/destination port support
- Security Rules: Complete rule definitions with optional fields and security profiles
- Automatic Validation: All YAML files are validated against schemas before deployment
The GitLab CI pipeline includes:
- Validate - YAML syntax and JSON schema validation using
validate_yaml.py - Plan - Terraform plan for changed clusters
- Apply - Automated deployment (with approval for production)
- Security Scan - Security best practices validation
- Cleanup - Cleanup old plan files and artifacts
The JSON schemas are automatically generated from Terraform module variables. To regenerate schemas after updating Terraform variables:
# The schemas are based on these Terraform variables:
# - firewall_addresses (modules/palo-alto/variables.tf)
# - firewall_services (modules/palo-alto/variables.tf)
# - firewall_rules (modules/palo-alto/variables.tf)
# Validate updated schemas
source venv/bin/activate
python scripts/validate_yaml.pyThe project uses GitLab managed Terraform state with cluster-specific state names to enable independent management of multiple firewall clusters:
- All Environments: Uses GitLab managed Terraform state with naming pattern
firewall-gitops-{cluster_name} - State Storage: Terraform state is stored securely in GitLab's infrastructure
- Remote Backend: HTTP backend with GitLab's Terraform state API
Each cluster maintains its own state in GitLab, providing:
- Centralized Management: All state stored securely in GitLab
- Independent Deployments: Clusters deploy without conflicts
- Parallel Execution: Multiple clusters can be deployed simultaneously
- State Locking: GitLab provides automatic state locking
- Access Control: GitLab project permissions control state access
- Backup & Recovery: GitLab handles state backup and recovery
For local development, you need to configure GitLab access:
# Required environment variables for local development
export GITLAB_TOKEN="your-personal-access-token"
export GITLAB_API_URL="https://gitlab.com/api/v4"
export GITLAB_USERNAME="your-gitlab-username"
# Deploy using GitLab managed state
./scripts/deploy.sh -c development -a planPersonal Access Token Requirements:
- Scope:
api(for Terraform state management) - Role:
Developeror higher on the project - Find your project ID in GitLab: Project → Settings → General → Project ID
The CI/CD pipeline requires the following environment variables for PAN-OS connectivity:
Required Variables:
PANOS_HOSTNAME- Firewall or Panorama hostname/IPPANOS_USERNAME- Username for authenticationPANOS_PASSWORD- Password for authentication (or use API key)
Optional Variables:
PANOS_API_KEY- API key (alternative to username/password)PANOS_PROTOCOL- Protocol to use (default:https)PANOS_PORT- Port number (default:443)PANOS_TIMEOUT- Connection timeout in seconds (default:10)PANOS_SKIP_VERIFY_CERTIFICATE- Skip SSL verification (default:true)
- Fork the repository
- Create a feature branch
- Make your changes
- Add tests and documentation
- Submit a merge request
This project is licensed under the MIT License - see the LICENSE file for details.
- Issues: Create an issue in GitLab for bugs or feature requests
- Documentation: Check the
docs/directory for detailed guides - Examples: Reference the
clusters/directory for working configurations