* fix: Add no_log to tasks handling sensitive information
- Add no_log: true to OpenSSL commands that contain passwords/passphrases
- Add no_log: true to WireGuard key generation commands
- Add no_log: true to password/CA password generation tasks
- Add no_log: true to AWS credential handling tasks
- Add no_log: true to QR code generation that contains full configs
This prevents sensitive information like passwords, private keys, and
WireGuard configurations from being logged to syslog/journald.
Fixes#1617
* feat: Comprehensive privacy enhancements
- Add no_log directives to all cloud provider credential handling
- Set privacy-focused defaults (StrongSwan logging disabled, DNSCrypt syslog off)
- Implement privacy role with log rotation, history clearing, and log filtering
- Add Privacy Considerations section to README
- Make all privacy features configurable and enabled by default
This update significantly reduces Algo's logging footprint to enhance user privacy
while maintaining the ability to enable logging for debugging when needed.
* docs: Move privacy documentation from README to FAQ
- Remove Privacy Considerations section from README
- Add expanded 'Does Algo support zero logging?' question to FAQ
- Better placement alongside existing logging/monitoring questions
- More detailed explanation of privacy features and limitations
* fix: Remove invalid 'bool' filter from Jinja2 template
The privacy-monitor.sh.j2 template was using '| bool' which is not a valid
Jinja2 filter. The 'bool' is a built-in Python function, not a Jinja2 filter.
Fixed by removing the '| bool' filter and directly outputting the boolean
variables as they will be rendered correctly by Jinja2.
This resolves the template syntax error that was causing CI tests to fail:
"No filter named 'bool'" error in privacy monitoring script template.
🤖 Generated with [Claude Code](https://claude.ai/code)
Co-Authored-By: Claude <noreply@anthropic.com>
* Fix YAML linting issues in privacy role
* Fix linting warnings: shellcheck and ansible-lint issues
- Fixed all shellcheck warnings in test scripts:
- Quoted variables to prevent word splitting
- Replaced A && B || C constructs with proper if-then-else
- Changed unused loop variable to _
- Added shellcheck directives for FreeBSD rc.d script
- Fixed ansible-lint risky-file-permissions warnings:
- Added explicit file permissions for sensitive files (mode 0600)
- Added permissions for config files and certificates (mode 0644)
- Set proper permissions for directories (mode 0755)
- Fixed yamllint compatibility with ansible-lint:
- Added required octal-values configuration
- Quoted all octal mode values to prevent YAML misinterpretation
- Added comments-indentation: false as required
All tests pass and functionality remains unchanged.
* Remove algo.egg-info from version control
This directory is generated by Python package tools (pip/setuptools) and
should not be tracked in git. It's already listed in .gitignore but was
accidentally committed. The directory contains build metadata that is
regenerated when the package is installed.
* Restructure privacy documentation for clarity
- Simplified FAQ entry to be concise with link to README for details
- Added comprehensive Privacy and Logging section to README
- Clarified what IS logged by default vs what is not
- Explained two separate privacy settings (strongswan_log_level and privacy_enhancements_enabled)
- Added clear debugging instructions (need to change both settings)
- Removed confusing language about "enabling additional features"
- Made documentation more natural and less AI-generated sounding
🤖 Generated with [Claude Code](https://claude.ai/code)
Co-Authored-By: Claude <noreply@anthropic.com>
* Fix Ubuntu 22.04 iptables deployment issues and simplify config.cfg
Issues fixed:
1. Added base 'iptables' package to batch installation list (was missing, only iptables-persistent was included)
2. Fixed alternatives configuration for Ubuntu 22.04+ - only configure main iptables/ip6tables alternatives, not save/restore (they're handled as slaves)
Config.cfg improvements:
- Reduced from 308 to 198 lines (35% reduction)
- Moved privacy settings above "Advanced users only" line for better accessibility
- Clarified algo_no_log is for Ansible output, not server privacy
- Simplified verbose comments throughout
- Moved experimental performance options to commented section at end
- Better organized into logical sections
🤖 Generated with [Claude Code](https://claude.ai/code)
Co-Authored-By: Claude <noreply@anthropic.com>
* Add privacy features to README and improve feature descriptions
- Added privacy-focused feature bullet highlighting minimal logging and privacy enhancements
- Simplified IKEv2 bullet (removed redundant platform list)
- Updated helper scripts description to be more comprehensive
- Specified Ubuntu 22.04 LTS and automatic security updates
- Made feature list more concise and accurate
🤖 Generated with [Claude Code](https://claude.ai/code)
Co-Authored-By: Claude <noreply@anthropic.com>
* Fix logrotate duplicate entries error in privacy role
The privacy role was creating logrotate configs that duplicated the default
Ubuntu rsyslog logrotate rules, causing deployment failures with errors like
'duplicate log entry for /var/log/syslog'.
Changes:
- Disable default rsyslog logrotate config before applying privacy configs
- Consolidate system log rotation into single config file
- Add missingok flag to handle logs that may not exist on all systems
- Remove forced immediate rotation that was triggering the error
This ensures privacy-enhanced log rotation works without conflicts.
🤖 Generated with [Claude Code](https://claude.ai/code)
Co-Authored-By: Claude <noreply@anthropic.com>
* Fix 'history: not found' error in privacy role
The 'history -c' command was failing because history is a bash built-in
that doesn't exist in /bin/sh (Ubuntu's default shell for scripts).
Changes:
- Removed the 'Clear current session history' task since it's ineffective
in Ansible context (each task runs in a new shell)
- History files are already cleared by the existing file removal tasks
- Added explanatory comment about why session history clearing is omitted
This fixes the deployment failure while maintaining all effective history
clearing functionality.
🤖 Generated with [Claude Code](https://claude.ai/code)
Co-Authored-By: Claude <noreply@anthropic.com>
* Fix BPF JIT sysctl error in privacy role
The net.core.bpf_jit_enable sysctl parameter was failing on some systems
because BPF JIT support is not available in all kernel configurations.
Changes:
- Separated BPF JIT setting into its own task with ignore_errors
- Made BPF JIT disabling optional since it's not critical for privacy
- Added explanatory comments about kernel support variability
- Both runtime sysctl and persistent config now handle missing parameter
This allows deployments to succeed on systems without BPF JIT support
while still applying the setting where available.
🤖 Generated with [Claude Code](https://claude.ai/code)
Co-Authored-By: Claude <noreply@anthropic.com>
---------
Co-authored-by: Claude <noreply@anthropic.com>
* Fix AWS Lightsail deployment error by removing deprecated boto3 parameter
Remove the deprecated boto3 parameter from get_aws_connection_info() call
in the lightsail_region_facts module. This parameter has been non-functional
since amazon.aws collection 4.0.0 and was removed in recent versions bundled
with Ansible 11.x, causing deployment failures.
The function works correctly without this parameter as the module already
properly imports and validates boto3 availability.
Closes#14822🤖 Generated with [Claude Code](https://claude.ai/code)
Co-Authored-By: Claude <noreply@anthropic.com>
* Update uv.lock to fix Docker build failure
The lockfile was out of sync after the Ansible 11.8.0 to 11.9.0 upgrade.
This regenerates the lockfile to include:
- ansible 11.9.0 (was 11.8.0)
- ansible-core 2.18.8 (was 2.18.7)
This fixes the Docker build CI failure where uv sync --locked was failing
due to lockfile mismatch.
🤖 Generated with [Claude Code](https://claude.ai/code)
Co-Authored-By: Claude <noreply@anthropic.com>
* Fix Jinja spacing linter issues correctly
- Add spacing in lookup('env', 'VAR') calls
- Fix spacing around pipe operators within Jinja expressions only
- Preserve YAML block scalar syntax (prompt: |)
- Fix array indexing spacing within Jinja expressions
- All changes pass yamllint and ansible-lint tests
🤖 Generated with [Claude Code](https://claude.ai/code)
Co-Authored-By: Claude <noreply@anthropic.com>
* Add algo.egg-info to .gitignore
* Add unit test for AWS Lightsail boto3 parameter fix
- Tests that get_aws_connection_info() is called without boto3 parameter
- Verifies the module can be imported successfully
- Checks source code doesn't contain boto3=True
- Regression test specifically for issue #14822
- All 4 test cases pass
This ensures the fix remains in place and prevents regression.
🤖 Generated with [Claude Code](https://claude.ai/code)
Co-Authored-By: Claude <noreply@anthropic.com>
* Fix Python linting issues in test file
- Sort imports according to ruff standards
- Remove trailing whitespace from blank lines
- Remove unnecessary 'r' mode argument from open()
- Add trailing newline at end of file
All tests still pass after linting fixes.
🤖 Generated with [Claude Code](https://claude.ai/code)
Co-Authored-By: Claude <noreply@anthropic.com>
---------
Co-authored-by: Claude <noreply@anthropic.com>
* Fix DigitalOcean cloud-init compatibility issue causing SSH timeout on port 4160
This commit addresses the issue described in GitHub issue #14800 where DigitalOcean
deployments fail during the "Wait until SSH becomes ready..." step due to cloud-init
not processing the write_files directive correctly.
## Problem
- DigitalOcean's cloud-init shows "Unhandled non-multipart (text/x-not-multipart) userdata" warning
- write_files module gets skipped, leaving SSH on default port 22 instead of port 4160
- Algo deployment times out when trying to connect to port 4160
## Solution
Added proactive detection and remediation to the DigitalOcean role:
1. Check if SSH is listening on the expected port (4160) after droplet creation
2. If not, automatically apply the SSH configuration manually via SSH on port 22
3. Verify SSH is now listening on the correct port before proceeding
## Changes
- Added SSH port check with 30-second timeout
- Added fallback remediation block that:
- Connects via SSH on port 22 to apply Algo's SSH configuration
- Backs up the original sshd_config
- Applies the correct SSH settings (port 4160, security hardening)
- Restarts the SSH service
- Verifies the fix worked
This ensures DigitalOcean deployments succeed even when cloud-init fails to process
the user_data correctly, maintaining backward compatibility and reliability.
🤖 Generated with [Claude Code](https://claude.ai/code)
Co-Authored-By: Claude <noreply@anthropic.com>
* Implement cleaner fix for DigitalOcean cloud-init encoding issue
This replaces the previous workaround with two targeted fixes that address
the root cause of the "Unhandled non-multipart (text/x-not-multipart) userdata"
issue that prevents write_files from being processed.
## Root Cause
Cloud-init receives user_data as binary/bytes instead of UTF-8 string,
causing it to fail parsing and skip the write_files directive that
configures SSH on port 4160.
## Cleaner Solutions Implemented
### Fix 1: String Encoding (user_data | string)
- Added explicit string conversion to user_data template lookup
- Ensures DigitalOcean API receives proper UTF-8 string, not bytes
- Minimal change with maximum compatibility
### Fix 2: Use runcmd Instead of write_files
- Replaced write_files approach with runcmd shell commands
- Bypasses the cloud-init parsing issue entirely
- More reliable as it executes direct shell commands
- Includes automatic SSH config backup for safety
## Changes Made
- `roles/cloud-digitalocean/tasks/main.yml`: Added | string filter to user_data
- `files/cloud-init/base.yml`: Replaced write_files with runcmd approach
- Removed complex SSH detection/remediation workaround (no longer needed)
## Benefits
- ✅ Fixes root cause instead of working around symptoms
- ✅ Much simpler and more maintainable code
- ✅ Backward compatible - no API changes required
- ✅ Handles both potential failure modes (encoding + parsing)
- ✅ All tests pass, linters clean
This should resolve DigitalOcean SSH timeout issues while being much
cleaner than the previous workaround approach.
🤖 Generated with [Claude Code](https://claude.ai/code)
Co-Authored-By: Claude <noreply@anthropic.com>
* Fix cloud-init header format for DigitalOcean compatibility
The space in '# cloud-config' (introduced in PR #14775) breaks cloud-init
YAML parsing on DigitalOcean, causing SSH configuration to be skipped.
Cloud-init documentation requires '#cloud-config' without a space.
Fixes#14800🤖 Generated with [Claude Code](https://claude.ai/code)
Co-Authored-By: Claude <noreply@anthropic.com>
* Revert to write_files approach for SSH configuration
Using write_files is more maintainable and Ansible-native than runcmd.
The root cause was the cloud-config header format, not write_files itself.
🤖 Generated with [Claude Code](https://claude.ai/code)
Co-Authored-By: Claude <noreply@anthropic.com>
* Fix Ansible deprecation and variable warnings
- Replace deprecated network filters with ansible.utils equivalents:
- ipaddr → ansible.utils.ipaddr
- ipmath → ansible.utils.ipmath
- ipv4 → ansible.utils.ipv4
- ipv6 → ansible.utils.ipv6
- next_nth_usable → ansible.utils.next_nth_usable
- Fix reserved variable name: no_log → algo_no_log
- Fix SSH user groups warning by explicitly specifying groups parameter
Addresses deprecation warnings that would become errors after 2024-01-01.
All linter checks pass with only cosmetic warnings remaining.
🤖 Generated with [Claude Code](https://claude.ai/code)
Co-Authored-By: Claude <noreply@anthropic.com>
* Add comprehensive protection for cloud-config header format
- Add inline documentation explaining critical #cloud-config format requirement
- Exclude files/cloud-init/ from yamllint and ansible-lint to prevent automatic 'fixes'
- Create detailed README.md documenting the issue and protection measures
- Reference GitHub issue #14800 for future maintainers
This prevents regression of the critical cloud-init header format that
causes deployment failures when changed from '#cloud-config' to '# cloud-config'.
🤖 Generated with [Claude Code](https://claude.ai/code)
Co-Authored-By: Claude <noreply@anthropic.com>
* Add test for cloud-init header format to prevent regression
This test ensures the cloud-init header remains exactly ''#cloud-config''
without a space. The regression in PR #14775 that added a space broke
DigitalOcean deployments by causing cloud-init YAML parsing to fail,
resulting in SSH timeouts on port 4160.
Co-authored-by: Dan Guido <dguido@users.noreply.github.com>
* Refactor SSH config template and fix MOTD task permissions
- Use dedicated sshd_config template instead of inline content
- Add explicit become: true to MOTD task to fix permissions warning
🤖 Generated with [Claude Code](https://claude.ai/code)
Co-Authored-By: Claude <noreply@anthropic.com>
* Fix no_log variable references after renaming to algo_no_log
Update all remaining references from old 'no_log' variable to 'algo_no_log'
in WireGuard, SSH tunneling, and StrongSwan roles. This fixes deployment
failures caused by undefined variable references.
🤖 Generated with [Claude Code](https://claude.ai/code)
Co-Authored-By: Claude <noreply@anthropic.com>
* fix: Correct YAML indentation in cloud-init template for DigitalOcean
The indent filter was not indenting the first line of the sshd_config content,
causing invalid YAML structure that cloud-init couldn't parse. This resulted
in SSH timeouts during deployment as the port was never changed from 22 to 4160.
- Add first=True parameter to indent filter to ensure all lines are indented
- Remove extra indentation in base template to prevent double-indentation
- Add comprehensive test suite to validate template rendering and prevent regressions
Fixes deployment failures where cloud-init would show:
"Invalid format at line X: expected <block end>, but found '<scalar>'"
🤖 Generated with [Claude Code](https://claude.ai/code)
Co-Authored-By: Claude <noreply@anthropic.com>
---------
Co-authored-by: Claude <noreply@anthropic.com>
Co-authored-by: claude[bot] <209825114+claude[bot]@users.noreply.github.com>
Co-authored-by: Dan Guido <dguido@users.noreply.github.com>
sshd limits the number of authentication attempts permitted per
established connection.
The limit is set via the MaxAuthTries option and defaults to six
attempts.
Client SSH environments that define more than six SSH keys globally or
in the agent would exhaust authentication attempts before they reach the
algo-specified per-instance SSH private key.
SSH client allows "forgetting" existing keys per connection using the
IdentitiesOnly option.
A client only offers an explicitly defined key when this option is set.
* Bump ansible-core from 2.11.3 to 2.12.1
Bumps [ansible-core](https://github.com/ansible/ansible) from 2.11.3 to 2.12.1.
- [Release notes](https://github.com/ansible/ansible/releases)
- [Commits](https://github.com/ansible/ansible/compare/v2.11.3...v2.12.1)
---
updated-dependencies:
- dependency-name: ansible-core
dependency-type: direct:production
update-type: version-update:semver-minor
...
Signed-off-by: dependabot[bot] <support@github.com>
* Update requirements.txt
* python and cache for actions
* switch to python 3.8
* wait for lxc network
* no point to support 18.04 in tests
* cipher fix for openssl_privatekey
* cipher fix for openssl_privatekey
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
Co-authored-by: Jack Ivanov <17044561+jackivanov@users.noreply.github.com>
<!--- 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.
* Refactoring, booleans declaration and update users fix
* Make server_name more FQDN compatible
* Rename variables
* Define the default value for store_cakey
* Skip a prompt about the SSH user if deploying to localhost
* Disable reboot for non-cloud deployments
* Enable EC2 volume encryption by default
* Add default server value (localhost) for the local installation
Delete empty files
* Add default region to aws_region_facts
* Update docs
* EC2 credentials fix
* Warnings fix
* Update deploy-from-ansible.md
* Fix a typo
* Remove lightsail from the docs
* Disable EC2 encryption by default
* rename droplet to server
* Disable dependencies
* Disable tls_cipher_suite
* Convert wifi-exclude to a string. Update-users fix
* SSH access congrats fix
* 16.04 > 18.04
* Dont ask for the credentials if specified in the environment vars
* GCE server name fix
* Draft
works with ECDSA
RSA support for Windows
* update-users with local_openssl_tasks
* move prompts to the algo script
* additional directory for SSH keys
* move easyrsa_p12_export_password to pre_tasks
* update-users testing
* Fix hardcoded vars
* Delete the CA key
* Hardcoded IP. Fixes#219
* Some fixes