Skip to content

lsst-it/puppet-openvpnas

 
 

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

62 Commits
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

openvpnas

CI Puppet Forge Puppet Forge Downloads License

Table of Contents

  1. Description
  2. Setup
  3. Usage
  4. Reference
  5. Limitations
  6. Development

Description

This module manages OpenVPN Access Server (AS) installation and configuration on RHEL-based systems. It provides comprehensive management capabilities including:

  • Repository management for official OpenVPN AS packages
  • Package version locking to prevent unwanted upgrades
  • Service management with enable/disable options
  • TLS certificate integration with Let's Encrypt or other providers
  • Configuration management through the sacli command-line interface
  • Bulk configuration import from JSON files
  • Idempotent operations with change detection

OpenVPN Access Server is the commercial VPN solution from OpenVPN Inc., offering a web-based administration interface and easier setup compared to the community edition.

OpenVPN Access Server Dashboard

OpenVPN Access Server 3.0.1 running on AlmaLinux 9 - Installed and managed via Puppet

Setup

What openvpnas affects

This module manages the following system components:

  • OpenVPN Access Server package (openvpn-as) installation
  • YUM repository configuration at /etc/yum.repos.d/openvpn-access-server.repo
  • Package version locks via YUM versionlock plugin
  • OpenVPN Access Server service (openvpnas)
  • Web UI TLS certificate symlinks at /usr/local/openvpn_as/etc/web-ssl/
  • Configuration database via sacli commands

Setup Requirements

This module has the following dependencies:

  • Puppet >= 7.0.0
  • puppetlabs/stdlib >= 9.0.0

When using version locking features:

  • puppet/yum >= 8.0.0

All dependencies are automatically installed when installing from Puppet Forge.

Beginning with openvpnas

The simplest use case is to install OpenVPN Access Server with default settings:

include openvpnas

This installs the package from your system's configured repositories without managing the OpenVPN AS repository or service.

Usage

Basic Installation

Install OpenVPN AS and enable the service:

class { 'openvpnas':
  manage_repo    => true,
  manage_service => true,
}

This configuration:

  • Configures the official OpenVPN AS yum repository
  • Installs the latest available openvpn-as package
  • Ensures the openvpnas service is running and enabled at boot

Repository Management

The module can manage the official OpenVPN AS repository. By default, it uses the RHEL 9 repository, but you can customize it:

class { 'openvpnas':
  manage_repo      => true,
  yumrepo_baseurl  => 'http://as-repository.openvpn.net/as/yum/rhel9/',
  yumrepo_id       => 'as-repo-rhel9',
  yumrepo_name     => 'openvpn-access-server',
  gpgkey_url       => 'https://as-repository.openvpn.net/as-repo-public.gpg',
}

If you have your own mirror or specific repository requirements, adjust these parameters accordingly.

Version Locking

Pin OpenVPN AS to a specific version to prevent automatic upgrades:

class { 'openvpnas':
  manage_repo        => true,
  version            => '2.13.1',
  versionlock_enable => true,
  versionlock_release => '1.el9',
}

Version locking is useful for:

  • Production stability where you need to control upgrade timing
  • Ensuring compatibility with specific configurations or integrations
  • Meeting compliance requirements for change control

The versionlock_release parameter corresponds to the RPM release string and typically follows the pattern 1.el9 for RHEL 9.

TLS Certificate Management

Integrate OpenVPN AS web UI with Let's Encrypt or other certificate providers:

class { 'openvpnas':
  manage_web_certs => true,
  cert_source_path => "/etc/letsencrypt/live/${facts['networking']['fqdn']}",
}

This creates symlinks in /usr/local/openvpn_as/etc/web-ssl/:

  • server.crt -> cert.pem (server certificate)
  • server.key -> privkey.pem (private key)
  • ca.crt -> fullchain.pem (certificate chain)

The module automatically notifies the service to restart when certificates change, ensuring the web UI always uses current certificates.

Example with Certbot integration:

# Manage Let's Encrypt certificate
class { 'letsencrypt':
  email => 'admin@example.com',
}

letsencrypt::certonly { $facts['networking']['fqdn']:
  domains => [$facts['networking']['fqdn']],
  plugin  => 'standalone',
}

# Configure OpenVPN AS to use the certificate
class { 'openvpnas':
  manage_repo      => true,
  manage_web_certs => true,
  cert_source_path => "/etc/letsencrypt/live/${facts['networking']['fqdn']}",
  require          => Letsencrypt::Certonly[$facts['networking']['fqdn']],
}

Configuration Management

OpenVPN AS configuration is managed through the sacli command-line tool. This module provides two methods for configuration:

Individual Configuration Keys

Configure specific settings using the config parameter:

class { 'openvpnas':
  manage_repo => true,
  config      => {
    'vpn.server.daemon.enable'     => true,
    'vpn.server.daemon.tcp.port'   => 443,
    'vpn.server.daemon.udp.port'   => 1194,
    'sa.company_name'              => 'Example Corporation',
    'host.name'                    => $facts['networking']['fqdn'],
    'cs.tls_version_min'           => '1.2',
    'cs.tls_version_min_strict'    => true,
  },
}

Each key-value pair is applied using sacli ConfigPut and automatically restarts the service if changes are detected.

Common configuration keys include:

  • vpn.server.daemon.enable: Enable/disable VPN daemon
  • vpn.server.daemon.tcp.port: TCP port for VPN connections
  • vpn.server.daemon.udp.port: UDP port for VPN connections
  • host.name: Hostname for certificates and web UI
  • sa.company_name: Company name displayed in web UI
  • cs.tls_version_min: Minimum TLS version
  • vpn.client.routing.reroute_gw: Enable/disable default gateway redirect

Consult the OpenVPN AS documentation for complete configuration reference.

Using the Define Type Directly

For more granular control, use the openvpnas::config::key define:

openvpnas::config::key { 'vpn.server.daemon.tcp.port':
  key   => 'vpn.server.daemon.tcp.port',
  value => 443,
}

openvpnas::config::key { 'enable-web-admin':
  key   => 'cs.admin_ui.allow_proxy',
  value => true,
}

This is useful when:

  • Managing configuration from multiple classes or modules
  • Conditionally applying configuration based on facts
  • Creating reusable configuration profiles

Bulk Configuration Import

For complex configurations or migrating settings between servers, use JSON import:

openvpnas::config::import { 'production-config':
  source => 'puppet:///modules/mymodule/openvpn-as-config.json',
}

The JSON file should contain the complete configuration database as exported by sacli ConfigQuery.

Example JSON structure:

{
  "vpn.server.daemon.enable": true,
  "vpn.server.daemon.tcp.port": 443,
  "host.name": "vpn.example.com",
  "sa.company_name": "Example Corp"
}

To export current configuration from a running server:

/usr/local/openvpn_as/scripts/sacli ConfigQuery > config.json

Optional parameter refresh_on_change controls whether to restart services after import (default: true):

openvpnas::config::import { 'staging-config':
  source            => 'puppet:///modules/mymodule/staging-config.json',
  refresh_on_change => false,
}

Complete Example

Production-ready configuration with all features:

# Configure OpenVPN AS with version locking, TLS, and custom settings
class { 'openvpnas':
  # Repository and package management
  manage_repo         => true,
  version             => '2.13.1',
  versionlock_enable  => true,

  # Service management
  manage_service      => true,

  # TLS certificate integration
  manage_web_certs    => true,
  cert_source_path    => "/etc/letsencrypt/live/${facts['networking']['fqdn']}",

  # Base configuration
  config              => {
    'host.name'                     => $facts['networking']['fqdn'],
    'sa.company_name'               => 'Example Corporation',
    'vpn.server.daemon.enable'      => true,
    'vpn.server.daemon.tcp.port'    => 443,
    'vpn.server.daemon.udp.port'    => 1194,
    'vpn.client.routing.reroute_gw' => true,
    'cs.tls_version_min'            => '1.2',
  },
}

# Import additional configuration
openvpnas::config::import { 'network-config':
  source => 'puppet:///modules/profiles/openvpn/network-settings.json',
}

FreeIPA/LDAP Integration

For environments using FreeIPA or LDAP for centralized authentication:

# OpenVPN AS with FreeIPA authentication
class { 'openvpnas':
  manage_repo    => true,
  manage_service => true,
  config         => {
    # FreeIPA/LDAP authentication
    'auth.module.type'              => 'ldap',
    'auth.ldap.0.server.0.host'     => 'ipa.example.com',
    'auth.ldap.0.bind_dn'           => 'uid=openvpn-svc,cn=users,cn=accounts,dc=example,dc=com',
    'auth.ldap.0.bind_pw'           => 'service_account_password',
    'auth.ldap.0.users_base_dn'     => 'cn=users,cn=accounts,dc=example,dc=com',
    'auth.ldap.0.use_ssl'           => 'always',
    'auth.ldap.0.ssl_verify'        => 'host',
    'auth.ldap.0.timeout'           => '4',
    'auth.ldap.0.name'              => 'FreeIPA Authentication',

    # Network configuration
    'host.name'                     => $facts['networking']['fqdn'],
    'vpn.server.daemon.enable'      => true,
    'vpn.server.daemon.tcp.port'    => 443,
    'vpn.server.daemon.udp.port'    => 1194,

    # Routing - allow access to private networks
    'vpn.server.routing.private_access'    => 'nat',
    'vpn.server.routing.private_network.0' => '10.0.0.0/8',
    'vpn.server.routing.private_network.1' => '172.16.0.0/12',
    'vpn.server.routing.private_network.2' => '192.168.0.0/16',

    # Client routing
    'vpn.client.routing.reroute_gw'       => true,
    'vpn.client.routing.reroute_dns'      => true,

    # Security settings
    'cs.tls_version_min'                   => '1.2',
    'vpn.server.tls_cc_security'           => 'tls-crypt',
  },
}

Benefits of FreeIPA integration:

  • Users and groups managed centrally in FreeIPA
  • Single Sign-On (SSO) with Kerberos
  • Group-based VPN access policies
  • Simplified disaster recovery (only configuration backup needed)
  • Automatic user provisioning/deprovisioning

Backup strategy with LDAP:

# Only configuration backup needed (users are in FreeIPA)
sudo /usr/local/openvpn_as/scripts/sacli ConfigQuery > openvpn-config.json

# Optional: backup certificates
sudo tar -czf openvpn-certs.tar.gz /usr/local/openvpn_as/etc/web-ssl/

Reference

See REFERENCE.md for complete parameter documentation.

Main Class Parameters

  • manage_repo: Boolean to enable repository management (default: false)
  • version: String specifying package version (default: undef for latest)
  • versionlock_enable: Boolean to enable version locking (default: false)
  • manage_service: Boolean to manage service state (default: true)
  • manage_web_certs: Boolean to manage TLS certificate symlinks (default: false)
  • cert_source_path: String path to certificate directory (default: Let's Encrypt path)
  • config: Hash of configuration key-value pairs (default: undef)

Defined Types

openvpnas::config::key

Manages individual configuration keys through sacli.

Parameters:

  • key: Configuration key name (required)
  • value: Configuration value - supports String, Integer, or Boolean (required)

openvpnas::config::import

Imports bulk configuration from JSON file.

Parameters:

  • source: Puppet file source path (required)
  • refresh_on_change: Boolean to restart service after import (default: true)

Limitations

Tested and supported platforms:

  • AlmaLinux 9
  • CentOS 9 Stream
  • Rocky Linux 9 (should work but not CI tested)

This module is designed specifically for OpenVPN Access Server, not the open-source OpenVPN Community Edition. The two products have different installation methods, configuration systems, and management tools.

Limitations and known issues:

  • Initial password for openvpn user must be set manually after first installation
  • Web UI will be unavailable until admin password is configured
  • Repository management currently only supports RHEL 9 family (configurable for other versions)
  • Configuration changes may require service restart which briefly interrupts VPN connections
  • TLS certificate management assumes Let's Encrypt directory structure

Development

This module follows Voxpupuli standards and best practices.

Contributing

Contributions are welcome. Please:

  1. Fork the repository
  2. Create a feature branch from main
  3. Write tests for new functionality
  4. Ensure all tests pass locally
  5. Submit a pull request with clear description

See CONTRIBUTING.md for detailed guidelines.

Running Tests

Install dependencies:

bundle install

Run all tests:

bundle exec rake test

Run specific test suites:

# Unit tests only
bundle exec rake spec

# Acceptance tests with Docker
bundle exec rake beaker

# Linting and syntax validation
bundle exec rake lint
bundle exec rake syntax
bundle exec rake rubocop

Generate reference documentation:

bundle exec rake strings:generate:reference

Testing on Windows with WSL2

You can quickly test this module on Windows using WSL2 with AlmaLinux 9. This is perfect for local development and testing before deploying to production.

Prerequisites

  • Windows 10/11 with WSL2 enabled
  • Docker Desktop (optional, not required for this method)

Step 1: Install AlmaLinux 9 on WSL2

# List available distributions
wsl --list --online

# Install AlmaLinux 9
wsl --install AlmaLinux-9

# Launch AlmaLinux
wsl -d AlmaLinux-9

During first launch, you'll be prompted to create a user account.

Step 2: Install Dependencies

Inside your AlmaLinux WSL instance:

# Install Puppet repository
sudo dnf install -y https://yum.puppet.com/puppet7-release-el-9.noarch.rpm

# Install Puppet Agent
sudo dnf install -y puppet-agent

# Add Puppet to PATH for current session
export PATH="/opt/puppetlabs/bin:$PATH"

Step 3: Clone and Install Module

# Clone the repository (or use your local Windows files via /mnt/c/)
cd ~
git clone https://github.com/cbarria/puppet-openvpnas.git
cd puppet-openvpnas

# Copy module to Puppet's module path
sudo mkdir -p /etc/puppetlabs/code/modules/openvpnas
sudo cp -r manifests /etc/puppetlabs/code/modules/openvpnas/
sudo cp -r data /etc/puppetlabs/code/modules/openvpnas/
sudo cp metadata.json /etc/puppetlabs/code/modules/openvpnas/
sudo cp hiera.yaml /etc/puppetlabs/code/modules/openvpnas/

Step 4: Apply the Module

# Apply with puppet apply
sudo /opt/puppetlabs/bin/puppet apply -e '
  class { "openvpnas":
    manage_repo    => true,
    manage_service => false,
  }
' --modulepath=/etc/puppetlabs/code/modules

Note: We set manage_service => false because systemd in WSL2 requires additional configuration. The package will install successfully, and you can test the configuration management features.

Step 5: Verify Installation

# Verify package is installed
rpm -q openvpn-as

# Check installed version
rpm -qi openvpn-as | head -20

# Verify OpenVPN AS files
ls -la /usr/local/openvpn_as/

# Start the service manually (if systemd is configured)
sudo systemctl start openvpnas

# Check service status
systemctl status openvpnas

# Test configuration query (requires service to be running)
sudo /usr/local/openvpn_as/scripts/sacli ConfigQuery

Step 6: Access Web Interface

If the service is running, you can access the web interface from Windows:

  • Admin UI: https://localhost:943/admin
  • User UI: https://localhost:943/

Default credentials:

  • Username: openvpn
  • Password: Set during first installation (check init.log)

Configuration Testing

Test configuration management features:

# Export current configuration
sudo /usr/local/openvpn_as/scripts/sacli ConfigQuery > /tmp/config-backup.json

# Apply configuration via Puppet
sudo /opt/puppetlabs/bin/puppet apply -e '
  class { "openvpnas":
    manage_repo => true,
    config      => {
      "host.name"                  => "test.local",
      "sa.company_name"            => "Test Company",
      "vpn.server.daemon.tcp.port" => 443,
    }
  }
' --modulepath=/etc/puppetlabs/code/modules

# Verify changes
sudo /usr/local/openvpn_as/scripts/sacli ConfigQuery | grep -E '(host\.name|sa\.company_name|tcp\.port)'

Troubleshooting

Issue: systemd not working in WSL2

# Check if systemd is enabled
cat /etc/wsl.conf

# Enable systemd (add to /etc/wsl.conf)
sudo tee /etc/wsl.conf > /dev/null <<EOF
[boot]
systemd=true
EOF

# Restart WSL from PowerShell
wsl --shutdown
wsl -d AlmaLinux-9

Issue: Cannot access web interface

  • Ensure Windows Firewall allows connections to port 943
  • Check if the service is actually running: sudo systemctl status openvpnas
  • View logs: sudo tail -f /usr/local/openvpn_as/init.log

Issue: "Permission denied" errors

  • Always use sudo for Puppet apply and sacli commands
  • Ensure you're using full paths: /usr/local/openvpn_as/scripts/sacli

Benefits of WSL2 Testing

  • Fast iteration: Test changes in seconds without VM overhead
  • Easy cleanup: Remove WSL instance and start fresh anytime
  • Realistic environment: AlmaLinux 9 matches production RHEL 9
  • Native integration: Access files from Windows, use Windows editors
  • No Docker required: Direct systemd integration (with configuration)

Code Quality

This module uses:

  • RSpec-Puppet for unit testing
  • Beaker for acceptance testing
  • Puppet Lint for Puppet code style
  • RuboCop for Ruby code style
  • GitHub Actions for continuous integration

All pull requests must pass CI checks before merging.

License

Apache-2.0 - See LICENSE file for details.

Authors

  • Carlos Barria

Support

For issues, questions, or contributions, please use the GitHub issue tracker.

About

Puppet Module that Installs and configures OpenVPN Access Server (AS)

Resources

License

Stars

Watchers

Forks

Releases

No releases published

Packages

No packages published

Languages

  • Ruby 52.5%
  • Puppet 47.5%