* Refactor StrongSwan PKI automation with Ansible crypto modules
- Replace shell-based OpenSSL commands with community.crypto modules
- Remove custom OpenSSL config template and manual file management
- Upgrade Ansible to 11.8.0 in requirements.txt
- Improve idempotency, maintainability, and security of certificate and CRL handling
* Enhance nameConstraints with comprehensive exclusions
- Add email domain exclusions (.com, .org, .net, .gov, .edu, .mil, .int)
- Include private IPv4 network exclusions
- Add IPv6 null route exclusion
- Preserve all security constraints from original openssl.cnf.j2
- Note: Complex IPv6 conditional logic simplified for Ansible compatibility
Security: Maintains defense-in-depth certificate scope restrictions
* Refactor StrongSwan PKI with comprehensive security enhancements and hybrid testing
## StrongSwan PKI Modernization
- Migrated from shell-based OpenSSL commands to Ansible community.crypto modules
- Simplified complex Jinja2 templates while preserving all security properties
- Added clear, concise comments explaining security rationale and Apple compatibility
## Enhanced Security Implementation (Issues #75, #153)
- **Name constraints**: CA certificates restricted to specific IP/email domains
- **EKU role separation**: Server certs (serverAuth only) vs client certs (clientAuth only)
- **Domain exclusions**: Blocks public domains (.com, .org, etc.) and private IP ranges
- **Apple compatibility**: SAN extensions and PKCS#12 compatibility2022 encryption
- **Certificate revocation**: Automated CRL generation for removed users
## Comprehensive Test Suite
- **Hybrid testing**: Validates real certificates when available, config validation for CI
- **Security validation**: Verifies name constraints, EKU restrictions, role separation
- **Apple compatibility**: Tests SAN extensions and PKCS#12 format compliance
- **Certificate chain**: Validates CA signing and certificate validity periods
- **CI-compatible**: No deployment required, tests Ansible configuration directly
## Configuration Updates
- Updated CLAUDE.md: Ansible version rationale (stay current for security/performance)
- Streamlined comments: Removed duplicative explanations while preserving technical context
- Maintained all Issue #75/#153 security enhancements with modern Ansible approach
🤖 Generated with [Claude Code](https://claude.ai/code)
Co-Authored-By: Claude <noreply@anthropic.com>
* Fix linting issues across the codebase
## Python Code Quality (ruff)
- Fixed import organization and removed unused imports in test files
- Replaced `== True` comparisons with direct boolean checks
- Added noqa comments for intentional imports in test modules
## YAML Formatting (yamllint)
- Removed trailing spaces in openssl.yml comments
- All YAML files now pass yamllint validation (except one pre-existing long regex line)
## Code Consistency
- Maintained proper import ordering in test files
- Ensured all code follows project linting standards
- Ready for CI pipeline validation
🤖 Generated with [Claude Code](https://claude.ai/code)
Co-Authored-By: Claude <noreply@anthropic.com>
* Replace magic number with configurable certificate validity period
## Maintainability Improvement
- Replaced hardcoded `+3650d` (10 years) with configurable variable
- Added `certificate_validity_days: 3650` in vars section with clear documentation
- Applied consistently to both server and client certificate signing
## Benefits
- Single location to modify certificate validity period
- Supports compliance requirements for shorter certificate lifespans
- Improves code readability and maintainability
- Eliminates magic number duplication
## Backwards Compatibility
- Default remains 10 years (3650 days) - no behavior change
- Organizations can now easily customize certificate validity as needed
🤖 Generated with [Claude Code](https://claude.ai/code)
Co-Authored-By: Claude <noreply@anthropic.com>
* Update test to validate configurable certificate validity period
## Test Update
- Fixed test failure after replacing magic number with configurable variable
- Now validates both variable definition and usage patterns:
- `certificate_validity_days: 3650` (configurable parameter)
- `ownca_not_after: "+{{ certificate_validity_days }}d"` (variable usage)
## Improved Test Coverage
- Better validation: checks that validity is configurable, not hardcoded
- Maintains backwards compatibility verification (10-year default)
- Ensures proper Ansible variable templating is used
## Verified
- Config validation mode: All 6 tests pass ✓
- Validates the maintainability improvement from previous commit
🤖 Generated with [Claude Code](https://claude.ai/code)
Co-Authored-By: Claude <noreply@anthropic.com>
* Update to Python 3.11 minimum and fix IPv6 constraint format
- Update Python requirement from 3.10 to 3.11 to align with Ansible 11
- Pin Ansible collections in requirements.yml for stability
- Fix invalid IPv6 constraint format causing deployment failure
- Update ruff target-version to py311 for consistency
🤖 Generated with [Claude Code](https://claude.ai/code)
Co-Authored-By: Claude <noreply@anthropic.com>
* Fix x509_crl mode parameter and auto-fix Python linting
- Remove deprecated 'mode' parameter from x509_crl task
- Add separate file task to set CRL permissions (0644)
- Auto-fix Python datetime import (use datetime.UTC alias)
🤖 Generated with [Claude Code](https://claude.ai/code)
Co-Authored-By: Claude <noreply@anthropic.com>
* Fix final IPv6 constraint format in defaults template
- Update nameConstraints template in defaults/main.yml
- Change malformed IP:0:0:0:0:0:0:0:0/0:0:0:0:0:0:0:0 to correct IP:::/0
- This ensures both Ansible crypto modules and OpenSSL template use consistent IPv6 format
* Fix critical certificate generation issues for macOS/iOS VPN compatibility
This commit addresses multiple certificate generation bugs in the Ansible crypto
module implementation that were causing VPN authentication failures on Apple devices.
Fixes implemented:
1. **Basic Constraints Extension**: Added missing `CA:FALSE` constraints to both
server and client certificate CSRs. This was causing certificate chain validation
errors on macOS/iOS devices.
2. **Subject Key Identifier**: Added `create_subject_key_identifier: true` to CA
certificate generation to enable proper Authority Key Identifier creation in
signed certificates.
3. **Complete Name Constraints**: Fixed missing DNS and IPv6 constraints in CA
certificate that were causing size differences compared to legacy shell-based
generation. Now includes:
- DNS constraints for the deployment-specific domain
- IPv6 permitted addresses when IPv6 support is enabled
- Complete IPv6 exclusion ranges (fc00::/7, fe80::/10, 2001:db8::/32)
These changes bring the certificate format much closer to the working shell-based
implementation and should resolve most macOS/iOS VPN connectivity issues.
**Outstanding Issue**: Authority Key Identifier still incomplete - missing DirName
and serial components. The community.crypto module limitation may require
additional investigation or alternative approaches.
Certificate size improvements: Server certificates increased from ~750 to ~775 bytes,
CA certificates from ~1070 to ~1250 bytes, bringing them closer to the expected
~3000 byte target size.
🤖 Generated with [Claude Code](https://claude.ai/code)
Co-Authored-By: Claude <noreply@anthropic.com>
* Fix certificate generation and improve version parsing
This commit addresses multiple issues found during macOS certificate validation:
Certificate Generation Fixes:
- Add Basic Constraints (CA:FALSE) to server and client certificates
- Generate Subject Key Identifier for proper AKI creation
- Improve Name Constraints implementation for security
- Update community.crypto to version 3.0.3 for latest fixes
Code Quality Improvements:
- Clean up certificate comments and remove obsolete references
- Fix server certificate identification in tests
- Update datetime comparisons for cryptography library compatibility
- Fix Ansible version parsing in main.yml with proper regex handling
Testing:
- All certificate validation tests pass
- Ansible syntax checks pass
- Python linting (ruff) clean
- YAML linting (yamllint) clean
These changes restore macOS/iOS certificate compatibility while maintaining
security best practices and improving code maintainability.
🤖 Generated with [Claude Code](https://claude.ai/code)
Co-Authored-By: Claude <noreply@anthropic.com>
* Enhance security documentation with comprehensive inline comments
Add detailed technical explanations for critical PKI security features:
- Name Constraints: Defense-in-depth rationale and attack prevention
- Public domain/network exclusions: Impersonation attack prevention
- RFC 1918 private IP blocking: Lateral movement prevention
- IPv6 constraint strategy: ULA/link-local/documentation range handling
- Role separation enforcement: Server vs client EKU restrictions
- CA delegation prevention: pathlen:0 security implications
- Cross-deployment isolation: UUID-based certificate scope limiting
These comments provide essential context for maintainers to understand
the security importance of each configuration without referencing
external issue numbers, ensuring long-term maintainability.
🤖 Generated with [Claude Code](https://claude.ai/code)
Co-Authored-By: Claude <noreply@anthropic.com>
* Fix CI test failures in PKI certificate validation
Resolve Smart Test Selection workflow failures by fixing test validation logic:
**Certificate Configuration Fixes:**
- Remove unnecessary serverAuth/clientAuth EKUs from CA certificate
- CA now only has IPsec End Entity EKU for VPN-specific certificate issuance
- Maintains proper role separation between server and client certificates
**Test Validation Improvements:**
- Fix domain exclusion detection to handle both single and double quotes in YAML
- Improve EKU validation to check actual configuration lines, not comments
- Server/client certificate tests now correctly parse YAML structure
- Tests pass in both CI mode (config validation) and local mode (real certificates)
**Root Cause:**
The CI failures were caused by overly broad test assertions that:
1. Expected double-quoted strings but found single-quoted YAML
2. Detected EKU keywords in comments rather than actual configuration
3. Failed to properly parse YAML list structures
All security constraints remain intact - no actual security issues were present.
The certificate generation produces properly constrained certificates for VPN use.
🤖 Generated with [Claude Code](https://claude.ai/code)
Co-Authored-By: Claude <noreply@anthropic.com>
* Fix trailing space in openssl.yml for yamllint compliance
---------
Co-authored-by: Dan Guido <dan@trailofbits.com>
Co-authored-by: Claude <noreply@anthropic.com>
* Refactor WireGuard key management: generate all keys locally with Ansible modules
- Move all WireGuard key generation from remote hosts to local execution via Ansible modules
- Enhance x25519_pubkey module for robust, idempotent, and secure key handling
- Update WireGuard role tasks to use local key generation and management
- Improve error handling and support for check mode
* Improve x25519_pubkey module code quality and add integration tests
Code Quality Improvements:
- Fix import organization and Ruff linting errors
- Replace bare except clauses with practical error handling
- Simplify documentation while maintaining useful debugging info
- Use dictionary literals instead of dict() calls for better performance
New Integration Test:
- Add comprehensive WireGuard key generation test (test_wireguard_key_generation.py)
- Tests actual deployment scenarios matching roles/wireguard/tasks/keys.yml
- Validates mathematical correctness of X25519 key derivation
- Tests both file and string input methods used by Algo
- Includes consistency validation and WireGuard tool integration
- Addresses documented test gap in tests/README.md line 63-67
Test Coverage:
- Module import validation
- Raw private key file processing
- Base64 private key string processing
- Key derivation consistency checks
- Optional WireGuard tool validation (when available)
🤖 Generated with [Claude Code](https://claude.ai/code)
Co-Authored-By: Claude <noreply@anthropic.com>
* Trigger CI build for PR #14803
Testing x25519_pubkey module improvements and WireGuard key generation changes.
🤖 Generated with [Claude Code](https://claude.ai/code)
Co-Authored-By: Claude <noreply@anthropic.com>
* Fix yamllint error: add missing newline at end of keys.yml
Resolves: no new line character at the end of file (new-line-at-end-of-file)
🤖 Generated with [Claude Code](https://claude.ai/code)
Co-Authored-By: Claude <noreply@anthropic.com>
* Fix critical binary data corruption bug in x25519_pubkey module
Issue: Private keys with whitespace-like bytes (0x09, 0x0A, etc.) at edges
were corrupted by .strip() call on binary data, causing 32-byte keys to
become 31 bytes and deployment failures.
Root Cause:
- Called .strip() on raw binary data unconditionally
- X25519 keys containing whitespace bytes were truncated
- Error: "got 31 bytes" instead of expected 32 bytes
Fix:
- Only strip whitespace when processing base64 text data
- Preserve raw binary data integrity for 32-byte keys
- Maintain backward compatibility with both formats
Addresses deployment failure: "Private key file must be either base64
or exactly 32 raw bytes, got 31 bytes"
🤖 Generated with [Claude Code](https://claude.ai/code)
Co-Authored-By: Claude <noreply@anthropic.com>
* Add inline comments to prevent binary data corruption bug
Explain the base64/raw file detection logic with clear warnings about
the critical issue where .strip() on raw binary data corrupts X25519
keys containing whitespace-like bytes (0x09, 0x0A, etc.).
This prevents future developers from accidentally reintroducing the
'got 31 bytes' deployment error by misunderstanding the dual-format
key handling logic.
---------
Co-authored-by: Dan Guido <dan@trailofbits.com>
Co-authored-by: Claude <noreply@anthropic.com>
* X.509 Name Constraints
* nameConstraints to a random generated uuid
* Second level domain
* nameConstraints fixes
* critical in nameConstraints lost after last refactoring
* Update README.md
As noted in #1599 we don't have any instructions for CentOS 7. Closes#1599
* Update README.md
Co-Authored-By: David Myers <dem@myersnet.net>
* generate service IPs dynamically
* update cloud-init tests
* exclude ipsec and wireguard ranges from the random service ip
* Update docs
* @davidemyers: update wireguard docs for linux
* Move to netaddr filter
* AllowedIPs fix
* WireGuard IPs fix
* add the install script to support cloud-init and local one-shot deployments
* update travis-ci tests
* update docs
* enable no_log again
* update docs
<!--- Provide a general summary of your changes in the Title above -->
## Description
Renames the vpn role to strongswan, and split up the variables to support 2 separate VPNs. Closes#1330 and closes#1162
Configures Ansible to use python3 on the server side. Closes#1024
Removes unneeded playbooks, reorganises a lot of variables
Reorganises the `config` folder. Closes#1330
<details><summary>Here is how the config directory looks like now</summary>
<p>
```
configs/X.X.X.X/
|-- ipsec
| |-- apple
| | |-- desktop.mobileconfig
| | |-- laptop.mobileconfig
| | `-- phone.mobileconfig
| |-- manual
| | |-- cacert.pem
| | |-- desktop.p12
| | |-- desktop.ssh.pem
| | |-- ipsec_desktop.conf
| | |-- ipsec_desktop.secrets
| | |-- ipsec_laptop.conf
| | |-- ipsec_laptop.secrets
| | |-- ipsec_phone.conf
| | |-- ipsec_phone.secrets
| | |-- laptop.p12
| | |-- laptop.ssh.pem
| | |-- phone.p12
| | `-- phone.ssh.pem
| `-- windows
| |-- desktop.ps1
| |-- laptop.ps1
| `-- phone.ps1
|-- ssh-tunnel
| |-- desktop.pem
| |-- desktop.pub
| |-- laptop.pem
| |-- laptop.pub
| |-- phone.pem
| |-- phone.pub
| `-- ssh_config
`-- wireguard
|-- desktop.conf
|-- desktop.png
|-- laptop.conf
|-- laptop.png
|-- phone.conf
`-- phone.png
```

</p>
</details>
## Motivation and Context
This refactoring is focused to aim to the 1.0 release
## How Has This Been Tested?
Deployed to several cloud providers with various options enabled and disabled
## Types of changes
<!--- What types of changes does your code introduce? Put an `x` in all the boxes that apply: -->
- [x] Refactoring
## Checklist:
<!--- Go over all the following points, and put an `x` in all the boxes that apply. -->
<!--- If you're unsure about any of these, don't hesitate to ask. We're here to help! -->
- [x] I have read the **CONTRIBUTING** document.
- [x] My code follows the code style of this project.
- [x] My change requires a change to the documentation.
- [x] I have updated the documentation accordingly.
- [x] All new and existing tests passed.