Skip to content

Conversation

@jackivanov
Copy link
Collaborator

@jackivanov jackivanov commented Aug 3, 2025

Description

This PR updates WireGuard key management so that all private, public, and preshared keys are generated and handled locally on the Ansible control node using Ansible modules. Keys are never generated on remote servers, and public keys are only updated if their content changes. The process is now more secure, reliable, and idempotent.

Motivation and Context

Previously, WireGuard keys were generated on remote servers, which could expose private keys and make management harder. By generating all keys locally, we improve security (private keys never leave the control node), simplify troubleshooting, and ensure consistent, repeatable deployments. This also makes the setup easier to audit and maintain.

Fixes #14693

How Has This Been Tested?

I tested these changes by deploying a server to AWS Lightsail and connecting to it using WireGuard. The keys were generated locally, and the connection was successful. All Ansible tasks completed without errors, and the resulting configuration worked as expected.

Types of changes

  • New feature (non-breaking change which adds functionality)

Checklist:

  • I have read the CONTRIBUTING document.
  • My code follows the code style of this project.
  • My change requires a change to the documentation.
  • I have updated the documentation accordingly.
  • I have added tests to cover my changes.
  • All new and existing tests passed.

@claude
Copy link
Contributor

claude bot commented Aug 3, 2025

Claude finished @jackivanov's task —— View job


PR Review: Refactor WireGuard key management

This is a significant security improvement that moves WireGuard key generation from remote servers to the local control node. Overall, this is well-implemented with good test coverage, but I've identified several areas for consideration.

Review Checklist:

  • Read and analyze the new custom Ansible module (library/x25519_pubkey.py)
  • Review the refactored WireGuard tasks (roles/wireguard/tasks/keys.yml)
  • Examine the main task changes (roles/wireguard/tasks/main.yml)
  • Analyze the new unit tests (tests/unit/test_wireguard_key_generation.py)
  • Assess code quality and best practices
  • Evaluate security implications
  • Check for potential bugs or issues
  • Review performance considerations
  • Assess test coverage completeness

🔒 Security Assessment - EXCELLENT

Strengths:

  • Major security improvement: Private keys never leave the control node (library/x25519_pubkey.py:70-75)
  • Proper file permissions: Raw keys have 0600 mode (roles/wireguard/tasks/keys.yml:7,26)
  • Safe binary handling: Critical fix preventing key corruption by not stripping raw binary data (library/x25519_pubkey.py:70-75)
  • Input validation: Comprehensive validation of key format and length (library/x25519_pubkey.py:85-91)

🐛 Code Quality & Potential Issues

Strengths:

  • Idempotent operations: Public keys only updated when content changes (library/x25519_pubkey.py:113-117)
  • Comprehensive error handling: Proper exception handling with descriptive messages
  • Clear documentation: Well-documented module parameters and behavior

Areas of Concern:

  1. Exception Handling Too Broad (library/x25519_pubkey.py:123-124)

    except Exception as e:  # Too broad - could mask specific errors
        module.fail_json(msg=f"Failed to derive public key: {e}")

    Should catch specific exceptions like cryptography.exceptions.* to avoid masking programming errors.

  2. Inconsistent Error Handling (library/x25519_pubkey.py:87-88)

    except Exception as e:  # Generic exception

    vs.

    except (base64.binascii.Error, ValueError):  # Specific exceptions

    The base64 validation uses specific exceptions, but private key validation doesn't.

  3. Missing File Extension Handling
    The code assumes .raw files but doesn't validate file extensions, which could lead to confusion if wrong files are passed.

⚡ Performance Considerations

Good:

  • Local key generation: Eliminates network round-trips for key operations
  • Efficient file I/O: Reads files once and caches content
  • Conditional writes: Only writes public keys when they've changed

Potential Optimization:

  • Consider batching multiple key operations if this becomes a performance bottleneck with many users

🧪 Test Coverage Assessment - VERY GOOD

Comprehensive Testing (tests/unit/test_wireguard_key_generation.py):

  • ✅ Raw file input testing
  • ✅ Base64 string input testing
  • ✅ WireGuard compatibility validation
  • ✅ Key consistency verification
  • ✅ Proper mocking of Ansible module components

Test Quality Highlights:

  • Real WireGuard validation: Tests actually validate with wg tools when available (test_wireguard_key_generation.py:200-285)
  • Comprehensive edge cases: Tests both file and string inputs
  • Proper cleanup: Temporary files are properly cleaned up

Minor Test Improvement Suggestions:

  • Could add tests for error conditions (invalid key lengths, corrupted files)
  • Could test the idempotent behavior more explicitly

📝 Architecture & Design

Excellent Design Decisions:

  • Single responsibility: The x25519_pubkey module has one clear purpose
  • Flexible input: Supports both file paths and base64 strings
  • Integration: Seamlessly integrates with existing Ansible task structure

Task Structure (roles/wireguard/tasks/keys.yml):
The refactored tasks are much cleaner:

  • Generate raw keys → Convert to base64 → Derive public keys
  • Clear separation of concerns
  • Proper delegation to localhost

🔧 Minor Recommendations

  1. Add specific exception handling in library/x25519_pubkey.py:123:

    except (ValueError, TypeError, cryptography.exceptions.InvalidKey) as e:
        module.fail_json(msg=f"Failed to derive public key: {e}")
  2. Consider adding file extension validation to prevent user confusion

  3. Add docstring examples showing typical usage patterns

✅ Overall Assessment

This is a high-quality security improvement that addresses the original issue effectively. The implementation is robust, well-tested, and follows good security practices. The custom Ansible module is well-designed and the integration is seamless.

Recommendation: APPROVE - This significantly improves Algo's security posture while maintaining usability and reliability.

Key Achievements:

  • ✅ Private keys never leave control node
  • ✅ Comprehensive test coverage with real WireGuard validation
  • ✅ Idempotent operations
  • ✅ Backward compatible with existing workflows
  • ✅ Clear, maintainable code structure

dguido added a commit that referenced this pull request Aug 4, 2025
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>
jackivanov and others added 3 commits August 3, 2025 17:41
…ible 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
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>
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>
@dguido dguido force-pushed the feature/wireguard-local-keygen branch from afadef9 to 7bec66d Compare August 4, 2025 00:42
dguido and others added 3 commits August 3, 2025 17:46
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>
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>
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.
@dguido dguido merged commit 5214c5f into master Aug 4, 2025
20 checks passed
@dguido dguido deleted the feature/wireguard-local-keygen branch August 4, 2025 01:24
@dguido dguido restored the feature/wireguard-local-keygen branch August 5, 2025 03:14
@dguido dguido deleted the feature/wireguard-local-keygen branch August 5, 2025 03:50
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

algo installation failled to Save private keys

3 participants