├── .editorconfig ├── .fixtures.yml ├── .github ├── CONTRIBUTING.md ├── ISSUE_TEMPLATE.md ├── PULL_REQUEST_TEMPLATE.md ├── labeler.yml ├── release.yml └── workflows │ ├── ci.yml │ ├── labeler.yml │ ├── prepare_release.yml │ └── release.yml ├── .gitignore ├── .msync.yml ├── .overcommit.yml ├── .pmtignore ├── .puppet-lint.rc ├── .rubocop.yml ├── .sync.yml ├── CHANGELOG.md ├── Gemfile ├── HISTORY.md ├── LICENSE ├── README.md ├── REFERENCE.md ├── Rakefile ├── data ├── defaults.yaml ├── family │ ├── Archlinux.yaml │ ├── Debian.yaml │ ├── FreeBSD.yaml │ ├── RedHat.yaml │ └── Solaris.yaml └── os │ └── Rocky.yaml ├── hiera.yaml ├── lib └── facter │ └── easyrsa.rb ├── manifests ├── ca.pp ├── client.pp ├── client_specific_config.pp ├── config.pp ├── init.pp ├── install.pp ├── revoke.pp ├── server.pp └── service.pp ├── metadata.json ├── spec ├── acceptance │ └── openvpn_spec.rb ├── classes │ ├── openvpn_config_spec.rb │ ├── openvpn_init_spec.rb │ ├── openvpn_install_spec.rb │ └── openvpn_service_spec.rb ├── defines │ ├── openvpn_ca_spec.rb │ ├── openvpn_client_spec.rb │ ├── openvpn_client_specific_config_spec.rb │ ├── openvpn_revoke_spec.rb │ └── openvpn_server_spec.rb ├── setup_acceptance_node.pp ├── spec_helper.rb └── spec_helper_acceptance.rb └── templates ├── client.erb ├── client_external_auth.erb ├── client_specific_config.erb ├── etc-default-openvpn.erb ├── etc-rc.d-openvpn.erb ├── ldap.erb ├── server.erb └── vars-30.epp /.editorconfig: -------------------------------------------------------------------------------- 1 | # editorconfig.org 2 | 3 | # Managed by modulesync - DO NOT EDIT 4 | # https://voxpupuli.org/docs/updating-files-managed-with-modulesync/ 5 | 6 | root = true 7 | 8 | [*] 9 | charset = utf-8 10 | end_of_line = lf 11 | indent_size = 2 12 | tab_width = 2 13 | indent_style = space 14 | insert_final_newline = true 15 | trim_trailing_whitespace = true 16 | -------------------------------------------------------------------------------- /.fixtures.yml: -------------------------------------------------------------------------------- 1 | fixtures: 2 | repositories: 3 | stdlib: "https://github.com/puppetlabs/puppetlabs-stdlib" 4 | concat: "https://github.com/puppetlabs/puppetlabs-concat" 5 | -------------------------------------------------------------------------------- /.github/CONTRIBUTING.md: -------------------------------------------------------------------------------- 1 | # Contribution guidelines 2 | 3 | ## Table of contents 4 | 5 | * [Contributing](#contributing) 6 | * [Writing proper commits - short version](#writing-proper-commits-short-version) 7 | * [Writing proper commits - long version](#writing-proper-commits-long-version) 8 | * [Dependencies](#dependencies) 9 | * [Note for OS X users](#note-for-os-x-users) 10 | * [The test matrix](#the-test-matrix) 11 | * [Syntax and style](#syntax-and-style) 12 | * [Running the unit tests](#running-the-unit-tests) 13 | * [Unit tests in docker](#unit-tests-in-docker) 14 | * [Integration tests](#integration-tests) 15 | 16 | This module has grown over time based on a range of contributions from 17 | people using it. If you follow these contributing guidelines your patch 18 | will likely make it into a release a little more quickly. 19 | 20 | ## Contributing 21 | 22 | Please note that this project is released with a Contributor Code of Conduct. 23 | By participating in this project you agree to abide by its terms. 24 | [Contributor Code of Conduct](https://voxpupuli.org/coc/). 25 | 26 | * Fork the repo. 27 | * Create a separate branch for your change. 28 | * We only take pull requests with passing tests, and documentation. [GitHub Actions](https://docs.github.com/en/actions) run the tests for us. You can also execute them locally. This is explained [in a later section](#the-test-matrix). 29 | * Checkout [our docs](https://voxpupuli.org/docs/reviewing_pr/) we use to review a module and the [official styleguide](https://puppet.com/docs/puppet/6.0/style_guide.html). They provide some guidance for new code that might help you before you submit a pull request. 30 | * Add a test for your change. Only refactoring and documentation changes require no new tests. If you are adding functionality or fixing a bug, please add a test. 31 | * Squash your commits down into logical components. Make sure to rebase against our current master. 32 | * Push the branch to your fork and submit a pull request. 33 | 34 | Please be prepared to repeat some of these steps as our contributors review your code. 35 | 36 | Also consider sending in your profile code that calls this component module as an acceptance test or provide it via an issue. This helps reviewers a lot to test your use case and prevents future regressions! 37 | 38 | ## Writing proper commits - short version 39 | 40 | * Make commits of logical units. 41 | * Check for unnecessary whitespace with "git diff --check" before committing. 42 | * Commit using Unix line endings (check the settings around "crlf" in git-config(1)). 43 | * Do not check in commented out code or unneeded files. 44 | * The first line of the commit message should be a short description (50 characters is the soft limit, excluding ticket number(s)), and should skip the full stop. 45 | * Associate the issue in the message. The first line should include the issue number in the form "(#XXXX) Rest of message". 46 | * The body should provide a meaningful commit message, which: 47 | *uses the imperative, present tense: `change`, not `changed` or `changes`. 48 | * includes motivation for the change, and contrasts its implementation with the previous behavior. 49 | * Make sure that you have tests for the bug you are fixing, or feature you are adding. 50 | * Make sure the test suites passes after your commit: 51 | * When introducing a new feature, make sure it is properly documented in the README.md 52 | 53 | ## Writing proper commits - long version 54 | 55 | 1. Make separate commits for logically separate changes. 56 | 57 | Please break your commits down into logically consistent units 58 | which include new or changed tests relevant to the rest of the 59 | change. The goal of doing this is to make the diff easier to 60 | read for whoever is reviewing your code. In general, the easier 61 | your diff is to read, the more likely someone will be happy to 62 | review it and get it into the code base. 63 | 64 | If you are going to refactor a piece of code, please do so as a 65 | separate commit from your feature or bug fix changes. 66 | 67 | We also really appreciate changes that include tests to make 68 | sure the bug is not re-introduced, and that the feature is not 69 | accidentally broken. 70 | 71 | Describe the technical detail of the change(s). If your 72 | description starts to get too long, that is a good sign that you 73 | probably need to split up your commit into more finely grained 74 | pieces. 75 | 76 | Commits which plainly describe the things which help 77 | reviewers check the patch and future developers understand the 78 | code are much more likely to be merged in with a minimum of 79 | bike-shedding or requested changes. Ideally, the commit message 80 | would include information, and be in a form suitable for 81 | inclusion in the release notes for the version of Puppet that 82 | includes them. 83 | 84 | Please also check that you are not introducing any trailing 85 | whitespace or other "whitespace errors". You can do this by 86 | running "git diff --check" on your changes before you commit. 87 | 88 | 2. Sending your patches 89 | 90 | To submit your changes via a GitHub pull request, we _highly_ 91 | recommend that you have them on a topic branch, instead of 92 | directly on `master`. 93 | It makes things much easier to keep track of, especially if 94 | you decide to work on another thing before your first change 95 | is merged in. 96 | 97 | GitHub has some pretty good 98 | [general documentation](http://help.github.com/) on using 99 | their site. They also have documentation on 100 | [creating pull requests](http://help.github.com/send-pull-requests/). 101 | 102 | In general, after pushing your topic branch up to your 103 | repository on GitHub, you can switch to the branch in the 104 | GitHub UI and click "Pull Request" towards the top of the page 105 | in order to open a pull request. 106 | 107 | 108 | 3. Update the related GitHub issue. 109 | 110 | If there is a GitHub issue associated with the change you 111 | submitted, then you should update the ticket to include the 112 | location of your branch, along with any other commentary you 113 | may wish to make. 114 | 115 | ## Dependencies 116 | 117 | The testing and development tools have a bunch of dependencies, 118 | all managed by [bundler](http://bundler.io/) according to the 119 | [Puppet support matrix](http://docs.puppetlabs.com/guides/platforms.html#ruby-versions). 120 | 121 | By default the tests use a baseline version of Puppet. 122 | 123 | If you have Ruby 2.x or want a specific version of Puppet, 124 | you must set an environment variable such as: 125 | 126 | ```sh 127 | export PUPPET_GEM_VERSION="~> 6.1.0" 128 | ``` 129 | 130 | You can install all needed gems for spec tests into the modules directory by 131 | running: 132 | 133 | ```sh 134 | bundle config set --local path '.vendor/' 135 | bundle config set --local without 'development system_tests release' 136 | bundle install --jobs "$(nproc)" 137 | ``` 138 | 139 | If you also want to run acceptance tests: 140 | 141 | ```sh 142 | bundle config set --local path '.vendor/' 143 | bundle config set --local without 'development release' 144 | bundle config set --local with 'system_tests' 145 | bundle install --jobs "$(nproc)" 146 | ``` 147 | 148 | Our all in one solution if you don't know if you need to install or update gems: 149 | 150 | ```sh 151 | bundle config set --local path '.vendor/' 152 | bundle config set --local without 'development release' 153 | bundle config set --local with 'system_tests' 154 | bundle install --jobs "$(nproc)" 155 | bundle update 156 | bundle clean 157 | ``` 158 | 159 | As an alternative to the `--jobs "$(nproc)` parameter, you can set an 160 | environment variable: 161 | 162 | ```sh 163 | BUNDLE_JOBS="$(nproc)" 164 | ``` 165 | 166 | ### Note for OS X users 167 | 168 | `nproc` isn't a valid command under OS x. As an alternative, you can do: 169 | 170 | ```sh 171 | --jobs "$(sysctl -n hw.ncpu)" 172 | ``` 173 | 174 | ## The test matrix 175 | 176 | ### Syntax and style 177 | 178 | The test suite will run [Puppet Lint](http://puppet-lint.com/) and 179 | [Puppet Syntax](https://github.com/gds-operations/puppet-syntax) to 180 | check various syntax and style things. You can run these locally with: 181 | 182 | ```sh 183 | bundle exec rake lint 184 | bundle exec rake validate 185 | ``` 186 | 187 | It will also run some [Rubocop](http://batsov.com/rubocop/) tests 188 | against it. You can run those locally ahead of time with: 189 | 190 | ```sh 191 | bundle exec rake rubocop 192 | ``` 193 | 194 | ### Running the unit tests 195 | 196 | The unit test suite covers most of the code, as mentioned above please 197 | add tests if you're adding new functionality. If you've not used 198 | [rspec-puppet](http://rspec-puppet.com/) before then feel free to ask 199 | about how best to test your new feature. 200 | 201 | To run the linter, the syntax checker and the unit tests: 202 | 203 | ```sh 204 | bundle exec rake test 205 | ``` 206 | 207 | To run your all the unit tests 208 | 209 | ```sh 210 | bundle exec rake spec 211 | ``` 212 | 213 | To run a specific spec test set the `SPEC` variable: 214 | 215 | ```sh 216 | bundle exec rake spec SPEC=spec/foo_spec.rb 217 | ``` 218 | 219 | #### Unit tests in docker 220 | 221 | Some people don't want to run the dependencies locally or don't want to install 222 | ruby. We ship a Dockerfile that enables you to run all unit tests and linting. 223 | You only need to run: 224 | 225 | ```sh 226 | docker build . 227 | ``` 228 | 229 | Please ensure that a docker daemon is running and that your user has the 230 | permission to talk to it. You can specify a remote docker host by setting the 231 | `DOCKER_HOST` environment variable. it will copy the content of the module into 232 | the docker image. So it will not work if a Gemfile.lock exists. 233 | 234 | ### Integration tests 235 | 236 | The unit tests just check the code runs, not that it does exactly what 237 | we want on a real machine. For that we're using 238 | [beaker](https://github.com/puppetlabs/beaker). 239 | 240 | This fires up a new virtual machine (using vagrant) and runs a series of 241 | simple tests against it after applying the module. You can run this 242 | with: 243 | 244 | ```sh 245 | BEAKER_PUPPET_COLLECTION=puppet7 BEAKER_setfile=debian11-64 bundle exec rake beaker 246 | ``` 247 | 248 | or 249 | 250 | ```sh 251 | BEAKER_PUPPET_COLLECTION=none BEAKER_setfile=archlinux-64 bundle exec rake beaker 252 | ``` 253 | 254 | This latter example will use the distribution's own version of Puppet. 255 | 256 | You can replace the string `debian11` with any common operating system. 257 | The following strings are known to work: 258 | 259 | * ubuntu2004 260 | * ubuntu2204 261 | * debian11 262 | * debian12 263 | * centos9 264 | * archlinux 265 | * almalinux8 266 | * almalinux9 267 | * fedora36 268 | 269 | For more information and tips & tricks, see [voxpupuli-acceptance's documentation](https://github.com/voxpupuli/voxpupuli-acceptance#running-tests). 270 | 271 | The source of this file is in our [modulesync_config](https://github.com/voxpupuli/modulesync_config/blob/master/moduleroot/.github/CONTRIBUTING.md.erb) 272 | repository. 273 | -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE.md: -------------------------------------------------------------------------------- 1 | 10 | 11 | ## Affected Puppet, Ruby, OS and module versions/distributions 12 | 13 | - Puppet: 14 | - Ruby: 15 | - Distribution: 16 | - Module version: 17 | 18 | ## How to reproduce (e.g Puppet code you use) 19 | 20 | ## What are you seeing 21 | 22 | ## What behaviour did you expect instead 23 | 24 | ## Output log 25 | 26 | ## Any additional information you'd like to impart 27 | -------------------------------------------------------------------------------- /.github/PULL_REQUEST_TEMPLATE.md: -------------------------------------------------------------------------------- 1 | 9 | #### Pull Request (PR) description 10 | 13 | 14 | #### This Pull Request (PR) fixes the following issues 15 | 21 | -------------------------------------------------------------------------------- /.github/labeler.yml: -------------------------------------------------------------------------------- 1 | --- 2 | # Managed by modulesync - DO NOT EDIT 3 | # https://voxpupuli.org/docs/updating-files-managed-with-modulesync/ 4 | 5 | skip-changelog: 6 | - head-branch: ['^release-*', 'release'] 7 | -------------------------------------------------------------------------------- /.github/release.yml: -------------------------------------------------------------------------------- 1 | --- 2 | # Managed by modulesync - DO NOT EDIT 3 | # https://voxpupuli.org/docs/updating-files-managed-with-modulesync/ 4 | 5 | # https://docs.github.com/en/repositories/releasing-projects-on-github/automatically-generated-release-notes 6 | 7 | changelog: 8 | exclude: 9 | labels: 10 | - duplicate 11 | - invalid 12 | - modulesync 13 | - question 14 | - skip-changelog 15 | - wont-fix 16 | - wontfix 17 | 18 | categories: 19 | - title: Breaking Changes 🛠 20 | labels: 21 | - backwards-incompatible 22 | 23 | - title: New Features 🎉 24 | labels: 25 | - enhancement 26 | 27 | - title: Bug Fixes 🐛 28 | labels: 29 | - bug 30 | 31 | - title: Documentation Updates 📚 32 | labels: 33 | - documentation 34 | - docs 35 | 36 | - title: Dependency Updates ⬆️ 37 | labels: 38 | - dependencies 39 | 40 | - title: Other Changes 41 | labels: 42 | - "*" 43 | -------------------------------------------------------------------------------- /.github/workflows/ci.yml: -------------------------------------------------------------------------------- 1 | --- 2 | # Managed by modulesync - DO NOT EDIT 3 | # https://voxpupuli.org/docs/updating-files-managed-with-modulesync/ 4 | 5 | name: CI 6 | 7 | # yamllint disable-line rule:truthy 8 | on: 9 | pull_request: {} 10 | push: 11 | branches: 12 | - main 13 | - master 14 | 15 | concurrency: 16 | group: ${{ github.ref_name }} 17 | cancel-in-progress: true 18 | 19 | jobs: 20 | puppet: 21 | name: Puppet 22 | uses: voxpupuli/gha-puppet/.github/workflows/beaker.yml@v3 23 | with: 24 | beaker_hosts: 'vpnserver:ma;vpnclienta:a' 25 | -------------------------------------------------------------------------------- /.github/workflows/labeler.yml: -------------------------------------------------------------------------------- 1 | --- 2 | # Managed by modulesync - DO NOT EDIT 3 | # https://voxpupuli.org/docs/updating-files-managed-with-modulesync/ 4 | 5 | name: "Pull Request Labeler" 6 | 7 | # yamllint disable-line rule:truthy 8 | on: 9 | pull_request_target: {} 10 | 11 | jobs: 12 | labeler: 13 | permissions: 14 | contents: read 15 | pull-requests: write 16 | runs-on: ubuntu-latest 17 | steps: 18 | - uses: actions/labeler@v5 19 | -------------------------------------------------------------------------------- /.github/workflows/prepare_release.yml: -------------------------------------------------------------------------------- 1 | --- 2 | # Managed by modulesync - DO NOT EDIT 3 | # https://voxpupuli.org/docs/updating-files-managed-with-modulesync/ 4 | 5 | name: 'Prepare Release' 6 | 7 | on: 8 | workflow_dispatch: 9 | inputs: 10 | version: 11 | description: 'Module version to be released. Must be a valid semver string without leading v. (1.2.3)' 12 | required: false 13 | 14 | jobs: 15 | release_prep: 16 | uses: 'voxpupuli/gha-puppet/.github/workflows/prepare_release.yml@v3' 17 | with: 18 | version: ${{ github.event.inputs.version }} 19 | allowed_owner: 'voxpupuli' 20 | secrets: 21 | # Configure secrets here: 22 | # https://docs.github.com/en/actions/security-guides/encrypted-secrets 23 | github_pat: '${{ secrets.PCCI_PAT_RELEASE_PREP }}' 24 | -------------------------------------------------------------------------------- /.github/workflows/release.yml: -------------------------------------------------------------------------------- 1 | --- 2 | # Managed by modulesync - DO NOT EDIT 3 | # https://voxpupuli.org/docs/updating-files-managed-with-modulesync/ 4 | 5 | name: Release 6 | 7 | # yamllint disable-line rule:truthy 8 | on: 9 | push: 10 | tags: 11 | - '*' 12 | 13 | jobs: 14 | release: 15 | name: Release 16 | uses: voxpupuli/gha-puppet/.github/workflows/release.yml@v3 17 | with: 18 | allowed_owner: 'voxpupuli' 19 | secrets: 20 | # Configure secrets here: 21 | # https://docs.github.com/en/actions/security-guides/encrypted-secrets 22 | username: ${{ secrets.PUPPET_FORGE_USERNAME }} 23 | api_key: ${{ secrets.PUPPET_FORGE_API_KEY }} 24 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # Managed by modulesync - DO NOT EDIT 2 | # https://voxpupuli.org/docs/updating-files-managed-with-modulesync/ 3 | 4 | /pkg/ 5 | /Gemfile.lock 6 | /Gemfile.local 7 | /vendor/ 8 | /.vendor/ 9 | /spec/fixtures/manifests/ 10 | /spec/fixtures/modules/ 11 | /.vagrant/ 12 | /.bundle/ 13 | /.ruby-version 14 | /coverage/ 15 | /log/ 16 | /.idea/ 17 | /.dependencies/ 18 | /.librarian/ 19 | /Puppetfile.lock 20 | *.iml 21 | .*.sw? 22 | /.yardoc/ 23 | /Guardfile 24 | bolt-debug.log 25 | .rerun.json 26 | -------------------------------------------------------------------------------- /.msync.yml: -------------------------------------------------------------------------------- 1 | --- 2 | # Managed by modulesync - DO NOT EDIT 3 | # https://voxpupuli.org/docs/updating-files-managed-with-modulesync/ 4 | 5 | modulesync_config_version: '9.7.0' 6 | -------------------------------------------------------------------------------- /.overcommit.yml: -------------------------------------------------------------------------------- 1 | # Managed by modulesync - DO NOT EDIT 2 | # https://voxpupuli.org/docs/updating-files-managed-with-modulesync/ 3 | # 4 | # Hooks are only enabled if you take action. 5 | # 6 | # To enable the hooks run: 7 | # 8 | # ``` 9 | # bundle exec overcommit --install 10 | # # ensure .overcommit.yml does not harm to you and then 11 | # bundle exec overcommit --sign 12 | # ``` 13 | # 14 | # (it will manage the .git/hooks directory): 15 | # 16 | # Examples howto skip a test for a commit or push: 17 | # 18 | # ``` 19 | # SKIP=RuboCop git commit 20 | # SKIP=PuppetLint git commit 21 | # SKIP=RakeTask git push 22 | # ``` 23 | # 24 | # Don't invoke overcommit at all: 25 | # 26 | # ``` 27 | # OVERCOMMIT_DISABLE=1 git commit 28 | # ``` 29 | # 30 | # Read more about overcommit: https://github.com/brigade/overcommit 31 | # 32 | # To manage this config yourself in your module add 33 | # 34 | # ``` 35 | # .overcommit.yml: 36 | # unmanaged: true 37 | # ``` 38 | # 39 | # to your modules .sync.yml config 40 | --- 41 | PreCommit: 42 | RuboCop: 43 | enabled: true 44 | description: 'Runs rubocop on modified files only' 45 | command: ['bundle', 'exec', 'rubocop'] 46 | RakeTarget: 47 | enabled: true 48 | description: 'Runs lint on modified files only' 49 | targets: 50 | - 'lint' 51 | command: ['bundle', 'exec', 'rake'] 52 | YamlSyntax: 53 | enabled: true 54 | JsonSyntax: 55 | enabled: true 56 | TrailingWhitespace: 57 | enabled: true 58 | 59 | PrePush: 60 | RakeTarget: 61 | enabled: true 62 | description: 'Run rake targets' 63 | targets: 64 | - 'validate' 65 | - 'test' 66 | - 'rubocop' 67 | command: ['bundle', 'exec', 'rake'] 68 | -------------------------------------------------------------------------------- /.pmtignore: -------------------------------------------------------------------------------- 1 | # Managed by modulesync - DO NOT EDIT 2 | # https://voxpupuli.org/docs/updating-files-managed-with-modulesync/ 3 | 4 | /docs/ 5 | /pkg/ 6 | /Gemfile 7 | /Gemfile.lock 8 | /Gemfile.local 9 | /vendor/ 10 | /.vendor/ 11 | /spec/ 12 | /Rakefile 13 | /.vagrant/ 14 | /.bundle/ 15 | /.ruby-version 16 | /coverage/ 17 | /log/ 18 | /.idea/ 19 | /.dependencies/ 20 | /.github/ 21 | /.librarian/ 22 | /Puppetfile.lock 23 | /Puppetfile 24 | *.iml 25 | /.editorconfig 26 | /.fixtures.yml 27 | /.gitignore 28 | /.msync.yml 29 | /.overcommit.yml 30 | /.pmtignore 31 | /.rspec 32 | /.rspec_parallel 33 | /.rubocop.yml 34 | /.sync.yml 35 | .*.sw? 36 | /.yardoc/ 37 | /.yardopts 38 | /Dockerfile 39 | /HISTORY.md 40 | -------------------------------------------------------------------------------- /.puppet-lint.rc: -------------------------------------------------------------------------------- 1 | # Managed by modulesync - DO NOT EDIT 2 | # https://voxpupuli.org/docs/updating-files-managed-with-modulesync/ 3 | 4 | --fail-on-warnings 5 | --no-parameter_documentation-check 6 | --no-parameter_types-check 7 | -------------------------------------------------------------------------------- /.rubocop.yml: -------------------------------------------------------------------------------- 1 | --- 2 | # Managed by modulesync - DO NOT EDIT 3 | # https://voxpupuli.org/docs/updating-files-managed-with-modulesync/ 4 | 5 | inherit_gem: 6 | voxpupuli-test: rubocop.yml 7 | -------------------------------------------------------------------------------- /.sync.yml: -------------------------------------------------------------------------------- 1 | --- 2 | spec/spec_helper_acceptance.rb: 3 | unmanaged: false 4 | .github/workflows/ci.yml: 5 | with: 6 | beaker_hosts: 'vpnserver:ma;vpnclienta:a' 7 | -------------------------------------------------------------------------------- /Gemfile: -------------------------------------------------------------------------------- 1 | # Managed by modulesync - DO NOT EDIT 2 | # https://voxpupuli.org/docs/updating-files-managed-with-modulesync/ 3 | 4 | source ENV['GEM_SOURCE'] || 'https://rubygems.org' 5 | 6 | group :test do 7 | gem 'voxpupuli-test', '~> 10.0', :require => false 8 | gem 'puppet_metadata', '~> 5.0', :require => false 9 | end 10 | 11 | group :development do 12 | gem 'guard-rake', :require => false 13 | gem 'overcommit', '>= 0.39.1', :require => false 14 | end 15 | 16 | group :system_tests do 17 | gem 'voxpupuli-acceptance', '~> 3.5', :require => false 18 | end 19 | 20 | group :release do 21 | gem 'voxpupuli-release', '~> 3.0', :require => false 22 | end 23 | 24 | gem 'rake', :require => false 25 | gem 'facter', ENV['FACTER_GEM_VERSION'], :require => false, :groups => [:test] 26 | 27 | puppetversion = ENV['PUPPET_GEM_VERSION'] || [">= 7.24", "< 9"] 28 | gem 'puppet', puppetversion, :require => false, :groups => [:test] 29 | 30 | # vim: syntax=ruby 31 | -------------------------------------------------------------------------------- /HISTORY.md: -------------------------------------------------------------------------------- 1 | ## 4.0.1 (2016-09-25) 2 | 3 | * Fix namespecific_rclink variable warning for non BSD systems ([#214](https://github.com/luxflux/puppet-openvpn/pull/214)) 4 | 5 | ## 4.0.0 6 | 7 | * Workaround for [MODULES-2874](https://tickets.puppetlabs.com/browse/MODULES-2874) ([#201](https://github.com/luxflux/puppet-openvpn/pull/201)) 8 | * Fix for [external CA handling with exported resources](https://github.com/luxflux/puppet-openvpn/pull/200) ([#201](https://github.com/luxflux/puppet-openvpn/pull/201)) 9 | * Drop Support for Puppet 3.x ([#212](https://github.com/luxflux/puppet-openvpn/pull/212)) 10 | 11 | ## 3.1.0 12 | 13 | * Support for FreeBSD ([#180](https://github.com/luxflux/puppet-openvpn/pull/180)) 14 | * Support for port-share ([#182](https://github.com/luxflux/puppet-openvpn/issues/182)/[#185](https://github.com/luxflux/puppet-openvpn/pull/185)) 15 | * Support for pre-shared keys ([#186](https://github.com/luxflux/puppet-openvpn/pull/186)) 16 | * Support LDAP anonymous binds ([#189](https://github.com/luxflux/puppet-openvpn/pull/189)) 17 | * Fix `.ovpn` files generation ([#190](https://github.com/luxflux/puppet-openvpn/pull/190)) 18 | * Support for external CAs ([#192](https://github.com/luxflux/puppet-openvpn/pull/192)) 19 | * Small Typo fix ([#192](https://github.com/luxflux/puppet-openvpn/pull/193)) 20 | * Fix support for Amazon Linux ([#194](https://github.com/luxflux/puppet-openvpn/pull/194)) 21 | * Client `pull` option ([#195](https://github.com/luxflux/puppet-openvpn/pull/195)) 22 | * Allow `remote_host` to be an array of servers ([#195](https://github.com/luxflux/puppet-openvpn/pull/195)) 23 | * More robust Shared CA handling ([#191](https://github.com/luxflux/puppet-openvpn/pull/191), [#196](https://github.com/luxflux/puppet-openvpn/pull/196)) 24 | 25 | ## 3.0.0 26 | 27 | * Support for Ubuntu 15.04 ([#168](https://github.com/luxflux/puppet-openvpn/pull/168)) 28 | * Support for specifying TLS-Cipher ([#169](https://github.com/luxflux/puppet-openvpn/pull/169)) 29 | * Support for specifying custom certificate expiry ([#169](https://github.com/luxflux/puppet-openvpn/pull/169)) 30 | * Support for README in download configs ([#169](https://github.com/luxflux/puppet-openvpn/pull/169)) 31 | * Support for Tunnelblick configurations ([#169](https://github.com/luxflux/puppet-openvpn/pull/169)) 32 | * Fix certificate revocation in Ubuntu Precise ([#169](https://github.com/luxflux/puppet-openvpn/pull/169)) 33 | * Use concat for ovpn generation ([#176](https://github.com/luxflux/puppet-openvpn/pull/176)) 34 | 35 | ## 2.9.0 36 | 37 | This will be the last version of version 2.x with new features. 38 | 39 | * Support to send ipv6 routes ([#153](https://github.com/luxflux/puppet-openvpn/pull/153), [#154](https://github.com/luxflux/puppet-openvpn/pull/154)) 40 | * Support for `nobind` param for server in client mode ([#156](https://github.com/luxflux/puppet-openvpn/pull/156)) 41 | * Fixing autostart_all behaviour ([#163](https://github.com/luxflux/puppet-openvpn/pull/163)) 42 | * Add systemd support for Debian >= 8.0 ([#161](https://github.com/luxflux/puppet-openvpn/pull/161)) 43 | * Support for Archlinux ([#162](https://github.com/luxflux/puppet-openvpn/pull/162)) 44 | * Support to enable/disable service management([#158](https://github.com/luxflux/puppet-openvpn/pull/158)) 45 | * Fix installation for older Redhat based systems ([#165](https://github.com/luxflux/puppet-openvpn/pull/165)) 46 | * Add ability to specify custom options for clients ([#167](https://github.com/luxflux/puppet-openvpn/pull/167)) 47 | 48 | ## 2.8.0 49 | 50 | * Support for systems without `lsb-release` package ([#134](https://github.com/luxflux/puppet-openvpn/pull/134)) 51 | * Support for Amazon EC2 OS ([#134](https://github.com/luxflux/puppet-openvpn/pull/134)) 52 | * Move default log path for status log to `/var/log/openvpn` ([#139](https://github.com/luxflux/puppet-openvpn/pull/139)) 53 | * Support for `format` parameter ([#138](https://github.com/luxflux/puppet-openvpn/pull/138)) 54 | * Ability to configure autostart management on debian ([#144](https://github.com/luxflux/puppet-openvpn/pull/144)) 55 | * Fix ordering in `/etc/default/openvpn` with puppet future parser ([#142](https://github.com/luxflux/puppet-openvpn/issues/142) 56 | * Support for TLS auth when server acts as client ([#147](https://github.com/luxflux/puppet-openvpn/pull/147)) 57 | * Support for customer server options ([#147](https://github.com/luxflux/puppet-openvpn/pull/147)) 58 | * Allow disabling `ns-cert-type server` for server-clients ([#147](https://github.com/luxflux/puppet-openvpn/pull/147)) 59 | * Fix pam plugin path on RedHat/CentOS ([#148](https://github.com/luxflux/puppet-openvpn/pull/148)) 60 | 61 | ## 2.7.1 62 | 63 | * Fix server in client mode ([#137](https://github.com/luxflux/puppet-openvpn/pull/137)) 64 | 65 | ## 2.7.0 66 | 67 | * Support for removing a client specific conf file ([#115](https://github.com/luxflux/puppet-openvpn/pull/115)) 68 | * Support for `rcvbuf` and `sndbuf` ([#116](https://github.com/luxflux/puppet-openvpn/pull/116)) 69 | * Fix RedHat and CentOS package selection ([#97](https://github.com/luxflux/puppet-openvpn/pull/97)) 70 | * Support for TLS and x509-name verification ([#118](https://github.com/luxflux/puppet-openvpn/pull/118)) 71 | * Fix unset client cipher producing invalid configs ([#129](https://github.com/luxflux/puppet-openvpn/pull/129)) 72 | * Support to share a CA between multiple server instances ([#112](https://github.com/luxflux/puppet-openvpn/pull/112)) 73 | * Support for systemd ([#127](https://github.com/luxflux/puppet-openvpn/pull/127)) 74 | 75 | ## 2.6.0 76 | 77 | * Support for setting `up` and/or `down` scripts for clients ([#89](https://github.com/luxflux/puppet-openvpn/pull/89)) 78 | * Fixing the permissions of the created directories and files ([#90](https://github.com/luxflux/puppet-openvpn/pull/90), [#92](https://github.com/luxflux/puppet-openvpn/pull/92), [#94](https://github.com/luxflux/puppet-openvpn/pull/94), [#102](https://github.com/luxflux/puppet-openvpn/pull/102)) 79 | * Refactor templates to use instance variables instead of `scope.lookupvar` ([#100](https://github.com/luxflux/puppet-openvpn/pull/100)) 80 | * Add client mode server ([#100](https://github.com/luxflux/puppet-openvpn/pull/100)) 81 | * Move CA management into its own defined type ([#100](https://github.com/luxflux/puppet-openvpn/pull/100)) 82 | * Fix LDAP-Support on Debian Wheezy ([#103](https://github.com/luxflux/puppet-openvpn/pull/103)) 83 | * Support for status-version ([#108](https://github.com/luxflux/puppet-openvpn/pull/108)) 84 | * Change layout of downloadable client config to prevent overriding other client configurations when extracting the tarball ([#104](https://github.com/luxflux/puppet-openvpn/pull/104)) 85 | * Add `ns-cert-type server` for server-clients ([#109](https://github.com/luxflux/puppet-openvpn/pull/109)) 86 | 87 | ## 2.5.0 88 | 89 | * Do not include deprecated `concat::setup` anymore ([#71](https://github.com/luxflux/puppet-openvpn/pull/71)) 90 | * Only warn about pam deprecation if it's used ([#72](https://github.com/luxflux/puppet-openvpn/pull/72)) 91 | * Ability to specify a `down` script ([#75](https://github.com/luxflux/puppet-openvpn/pull/75)) 92 | * Support for `client-cert-not-required` in server config ([#76](https://github.com/luxflux/puppet-openvpn/pull/76)) 93 | * Support for `auth-retry` in client config ([#76](https://github.com/luxflux/puppet-openvpn/pull/76)) 94 | * Support for `setenv` in client config ([#79](https://github.com/luxflux/puppet-openvpn/pull/79)) 95 | * Support for `setenv_safe` in client config ([#79](https://github.com/luxflux/puppet-openvpn/pull/79)) 96 | * Support for `cipher` in client config ([#80](https://github.com/luxflux/puppet-openvpn/pull/80)) 97 | * Support for `push route` in client specific config ([#80](https://github.com/luxflux/puppet-openvpn/pull/80)) 98 | 99 | ## 2.4.0 100 | 101 | ### Bugfixes 102 | * Fix Ubuntu Trusty support ([#64](https://github.com/luxflux/puppet-openvpn/pull/64)) 103 | 104 | ### New Features 105 | * Basic support to hand out IPv6 addresses ([#66](https://github.com/luxflux/puppet-openvpn/pull/66)) 106 | * Ability to specify the common name of a server ([#65](https://github.com/luxflux/puppet-openvpn/pull/65)) 107 | * Options for KEY_EXPIRE, CA_EXPIRE, KEY_NAME, KEY_OU, KEY_CN easy-rsa vars. ([#58](https://github.com/luxflux/puppet-openvpn/pull/58), [#70](https://github.com/luxflux/puppet-openvpn/pull/70)) 108 | * Options for cipher, verb, persist-key, persist-tun server directives. ([#58](https://github.com/luxflux/puppet-openvpn/pull/58), [#70](https://github.com/luxflux/puppet-openvpn/pull/70)) 109 | 110 | 111 | ## Before 112 | 113 | * A lot of stuff I don't know anymore :disappointed: 114 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | 2 | Apache License 3 | Version 2.0, January 2004 4 | http://www.apache.org/licenses/ 5 | 6 | TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION 7 | 8 | 1. Definitions. 9 | 10 | "License" shall mean the terms and conditions for use, reproduction, 11 | and distribution as defined by Sections 1 through 9 of this document. 12 | 13 | "Licensor" shall mean the copyright owner or entity authorized by 14 | the copyright owner that is granting the License. 15 | 16 | "Legal Entity" shall mean the union of the acting entity and all 17 | other entities that control, are controlled by, or are under common 18 | control with that entity. For the purposes of this definition, 19 | "control" means (i) the power, direct or indirect, to cause the 20 | direction or management of such entity, whether by contract or 21 | otherwise, or (ii) ownership of fifty percent (50%) or more of the 22 | outstanding shares, or (iii) beneficial ownership of such entity. 23 | 24 | "You" (or "Your") shall mean an individual or Legal Entity 25 | exercising permissions granted by this License. 26 | 27 | "Source" form shall mean the preferred form for making modifications, 28 | including but not limited to software source code, documentation 29 | source, and configuration files. 30 | 31 | "Object" form shall mean any form resulting from mechanical 32 | transformation or translation of a Source form, including but 33 | not limited to compiled object code, generated documentation, 34 | and conversions to other media types. 35 | 36 | "Work" shall mean the work of authorship, whether in Source or 37 | Object form, made available under the License, as indicated by a 38 | copyright notice that is included in or attached to the work 39 | (an example is provided in the Appendix below). 40 | 41 | "Derivative Works" shall mean any work, whether in Source or Object 42 | form, that is based on (or derived from) the Work and for which the 43 | editorial revisions, annotations, elaborations, or other modifications 44 | represent, as a whole, an original work of authorship. For the purposes 45 | of this License, Derivative Works shall not include works that remain 46 | separable from, or merely link (or bind by name) to the interfaces of, 47 | the Work and Derivative Works thereof. 48 | 49 | "Contribution" shall mean any work of authorship, including 50 | the original version of the Work and any modifications or additions 51 | to that Work or Derivative Works thereof, that is intentionally 52 | submitted to Licensor for inclusion in the Work by the copyright owner 53 | or by an individual or Legal Entity authorized to submit on behalf of 54 | the copyright owner. For the purposes of this definition, "submitted" 55 | means any form of electronic, verbal, or written communication sent 56 | to the Licensor or its representatives, including but not limited to 57 | communication on electronic mailing lists, source code control systems, 58 | and issue tracking systems that are managed by, or on behalf of, the 59 | Licensor for the purpose of discussing and improving the Work, but 60 | excluding communication that is conspicuously marked or otherwise 61 | designated in writing by the copyright owner as "Not a Contribution." 62 | 63 | "Contributor" shall mean Licensor and any individual or Legal Entity 64 | on behalf of whom a Contribution has been received by Licensor and 65 | subsequently incorporated within the Work. 66 | 67 | 2. Grant of Copyright License. Subject to the terms and conditions of 68 | this License, each Contributor hereby grants to You a perpetual, 69 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable 70 | copyright license to reproduce, prepare Derivative Works of, 71 | publicly display, publicly perform, sublicense, and distribute the 72 | Work and such Derivative Works in Source or Object form. 73 | 74 | 3. Grant of Patent License. Subject to the terms and conditions of 75 | this License, each Contributor hereby grants to You a perpetual, 76 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable 77 | (except as stated in this section) patent license to make, have made, 78 | use, offer to sell, sell, import, and otherwise transfer the Work, 79 | where such license applies only to those patent claims licensable 80 | by such Contributor that are necessarily infringed by their 81 | Contribution(s) alone or by combination of their Contribution(s) 82 | with the Work to which such Contribution(s) was submitted. If You 83 | institute patent litigation against any entity (including a 84 | cross-claim or counterclaim in a lawsuit) alleging that the Work 85 | or a Contribution incorporated within the Work constitutes direct 86 | or contributory patent infringement, then any patent licenses 87 | granted to You under this License for that Work shall terminate 88 | as of the date such litigation is filed. 89 | 90 | 4. Redistribution. You may reproduce and distribute copies of the 91 | Work or Derivative Works thereof in any medium, with or without 92 | modifications, and in Source or Object form, provided that You 93 | meet the following conditions: 94 | 95 | (a) You must give any other recipients of the Work or 96 | Derivative Works a copy of this License; and 97 | 98 | (b) You must cause any modified files to carry prominent notices 99 | stating that You changed the files; and 100 | 101 | (c) You must retain, in the Source form of any Derivative Works 102 | that You distribute, all copyright, patent, trademark, and 103 | attribution notices from the Source form of the Work, 104 | excluding those notices that do not pertain to any part of 105 | the Derivative Works; and 106 | 107 | (d) If the Work includes a "NOTICE" text file as part of its 108 | distribution, then any Derivative Works that You distribute must 109 | include a readable copy of the attribution notices contained 110 | within such NOTICE file, excluding those notices that do not 111 | pertain to any part of the Derivative Works, in at least one 112 | of the following places: within a NOTICE text file distributed 113 | as part of the Derivative Works; within the Source form or 114 | documentation, if provided along with the Derivative Works; or, 115 | within a display generated by the Derivative Works, if and 116 | wherever such third-party notices normally appear. The contents 117 | of the NOTICE file are for informational purposes only and 118 | do not modify the License. You may add Your own attribution 119 | notices within Derivative Works that You distribute, alongside 120 | or as an addendum to the NOTICE text from the Work, provided 121 | that such additional attribution notices cannot be construed 122 | as modifying the License. 123 | 124 | You may add Your own copyright statement to Your modifications and 125 | may provide additional or different license terms and conditions 126 | for use, reproduction, or distribution of Your modifications, or 127 | for any such Derivative Works as a whole, provided Your use, 128 | reproduction, and distribution of the Work otherwise complies with 129 | the conditions stated in this License. 130 | 131 | 5. Submission of Contributions. Unless You explicitly state otherwise, 132 | any Contribution intentionally submitted for inclusion in the Work 133 | by You to the Licensor shall be under the terms and conditions of 134 | this License, without any additional terms or conditions. 135 | Notwithstanding the above, nothing herein shall supersede or modify 136 | the terms of any separate license agreement you may have executed 137 | with Licensor regarding such Contributions. 138 | 139 | 6. Trademarks. This License does not grant permission to use the trade 140 | names, trademarks, service marks, or product names of the Licensor, 141 | except as required for reasonable and customary use in describing the 142 | origin of the Work and reproducing the content of the NOTICE file. 143 | 144 | 7. Disclaimer of Warranty. Unless required by applicable law or 145 | agreed to in writing, Licensor provides the Work (and each 146 | Contributor provides its Contributions) on an "AS IS" BASIS, 147 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or 148 | implied, including, without limitation, any warranties or conditions 149 | of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A 150 | PARTICULAR PURPOSE. You are solely responsible for determining the 151 | appropriateness of using or redistributing the Work and assume any 152 | risks associated with Your exercise of permissions under this License. 153 | 154 | 8. Limitation of Liability. In no event and under no legal theory, 155 | whether in tort (including negligence), contract, or otherwise, 156 | unless required by applicable law (such as deliberate and grossly 157 | negligent acts) or agreed to in writing, shall any Contributor be 158 | liable to You for damages, including any direct, indirect, special, 159 | incidental, or consequential damages of any character arising as a 160 | result of this License or out of the use or inability to use the 161 | Work (including but not limited to damages for loss of goodwill, 162 | work stoppage, computer failure or malfunction, or any and all 163 | other commercial damages or losses), even if such Contributor 164 | has been advised of the possibility of such damages. 165 | 166 | 9. Accepting Warranty or Additional Liability. While redistributing 167 | the Work or Derivative Works thereof, You may choose to offer, 168 | and charge a fee for, acceptance of support, warranty, indemnity, 169 | or other liability obligations and/or rights consistent with this 170 | License. However, in accepting such obligations, You may act only 171 | on Your own behalf and on Your sole responsibility, not on behalf 172 | of any other Contributor, and only if You agree to indemnify, 173 | defend, and hold each Contributor harmless for any liability 174 | incurred by, or claims asserted against, such Contributor by reason 175 | of your accepting any such warranty or additional liability. 176 | 177 | END OF TERMS AND CONDITIONS 178 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # OpenVPN Puppet module 2 | 3 | [![Build Status](https://github.com/voxpupuli/puppet-openvpn/workflows/CI/badge.svg)](https://github.com/voxpupuli/puppet-openvpn/actions?query=workflow%3ACI) 4 | [![Release](https://github.com/voxpupuli/puppet-openvpn/actions/workflows/release.yml/badge.svg)](https://github.com/voxpupuli/puppet-openvpn/actions/workflows/release.yml) 5 | [![License](https://img.shields.io/github/license/voxpupuli/puppet-openvpn.svg)](https://github.com/voxpupuli/puppet-openvpn/blob/master/LICENSE) 6 | [![Puppet Forge](https://img.shields.io/puppetforge/v/puppet/openvpn.svg)](https://forge.puppetlabs.com/puppet/openvpn) 7 | [![Puppet Forge - downloads](https://img.shields.io/puppetforge/dt/puppet/openvpn.svg)](https://forge.puppetlabs.com/puppet/openvpn) 8 | [![Puppet Forge - endorsement](https://img.shields.io/puppetforge/e/puppet/openvpn.svg)](https://forge.puppetlabs.com/puppet/openvpn) 9 | [![Puppet Forge - scores](https://img.shields.io/puppetforge/f/puppet/openvpn.svg)](https://forge.puppetlabs.com/puppet/openvpn) 10 | 11 | Puppet module to manage OpenVPN servers and clients. 12 | 13 | ## Features 14 | 15 | * Client-specific rules and access policies 16 | * Generated client configurations and SSL-Certificates 17 | * Downloadable client configurations and SSL-Certificates for easy client configuration 18 | * Support for multiple server instances 19 | * Support for LDAP-Authentication 20 | * Support for server instance in client mode 21 | * Support for TLS 22 | 23 | ## Supported OS 24 | 25 | * Ubuntu 26 | * Debian 27 | * CentOS 28 | * RedHat 29 | * Solaris 30 | 31 | ## Dependencies 32 | - [puppetlabs-concat 3.0.0+](https://github.com/puppetlabs/puppetlabs-concat) 33 | - [puppetlabs-stdlib 4.25.0+](https://github.com/puppetlabs/puppetlabs-stdlib) 34 | 35 | ## Puppet 36 | 37 | The supported Puppet versions are listed in the [metadata.json](metadata.json) 38 | 39 | ## REFERENCES 40 | 41 | Please see [REFERENCE.md](https://github.com/voxpupuli/puppet-openvpn/blob/master/REFERENCE.md) for more details. 42 | 43 | ## Example with hiera 44 | 45 | ```yaml 46 | --- 47 | classes: 48 | - openvpn 49 | 50 | openvpn::servers: 51 | 'winterthur': 52 | country: 'CH' 53 | province: 'ZH' 54 | city: 'Winterthur' 55 | organization: 'example.org' 56 | email: 'root@example.org' 57 | server: '10.200.200.0 255.255.255.0' 58 | 59 | openvpn::client_defaults: 60 | server: 'winterthur' 61 | 62 | openvpn::clients: 63 | 'client1': {} 64 | 'client2': {} 65 | 'client3': {} 66 | 67 | openvpn::client_specific_configs: 68 | 'client1': 69 | server: 'winterthur' 70 | ifconfig: '10.200.200.50 10.200.200.51' 71 | 72 | openvpn::revokes: 73 | 'client3': 74 | server: 'winterthur' 75 | ``` 76 | 77 | Don't forget the sysctl directive ```net.ipv4.ip_forward```! 78 | 79 | ## Encryption Choices 80 | 81 | This module provides certain default parameters for the openvpn encryption settings. 82 | 83 | These settings have been applied in line with current "best practices" but no 84 | guarantee is given for their saftey and they could change in future. 85 | 86 | You should double check these settings yourself to make sure they are suitable for your needs and in line with current best practices. 87 | 88 | ## Example for automating client deployment to nodes managed by Puppet 89 | 90 | Exporting the configurations for a client in the VPN server manifest: 91 | ``` 92 | openvpn::deploy::export { 'client1': 93 | server => 'winterthur', 94 | } 95 | ``` 96 | Installation, configuration and starting the OpenVPN client in a configured node manifest: 97 | ``` 98 | openvpn::deploy::client { 'client1': 99 | server => 'winterthur', 100 | } 101 | ``` 102 | 103 | ## Experimenting and developing in Vagrant 104 | 105 | This project includes a Vagrantfile which allows you to easily develop this 106 | module or try it out. The prerequisites are [Vagrant](https://www.vagrantup.com/) 107 | and [VirtualBox](https://www.virtualbox.org/). 108 | 109 | To bring up the OpenVPN server VM: 110 | 111 | vagrant up server_ubuntu 112 | 113 | To bring up the OpenVPN client VM: 114 | 115 | vagrant up client_ubuntu 116 | 117 | Client's OpenVPN configuration is generated on the server, but it needs to be 118 | deployed to the client manually as exported resources are not available in 119 | Vagrant. To get the client config from server: 120 | 121 | vagrant ssh server_ubuntu 122 | sudo -i 123 | cp /etc/openvpn/winterthur/download-configs/client1.ovpn /vagrant/ 124 | exit 125 | 126 | To copy it to the client: 127 | 128 | vagrant ssh client_ubuntu 129 | sudo -i 130 | mv /vagrant/client1.ovpn /etc/openvpn/client/client1.conf 131 | 132 | To connect directly with OpenVPN: 133 | 134 | openvpn --config /etc/openvpn/client/client1.conf 135 | 136 | To connect with systemd: 137 | 138 | systemctl start openvpn-client@client1 139 | 140 | To test connectivity between client and server: 141 | 142 | ping 10.200.200.1 143 | 144 | ##### References 145 | 146 | * The readme file of [github.com/Angristan/OpenVPN-install](https://github.com/Angristan/OpenVPN-install/tree/f47fc795d5e2d53f74431aadc58ef9de5784103a) outlines some of reasoning behind 147 | such choices. 148 | 149 | * The OpenVPN documentation about the [SWEET32](https://community.openvpn.net/openvpn/wiki/SWEET32) attack gives some reasons and 150 | recommendations for which ciphers to use. 151 | 152 | * The OpenVPN [hardening documentation](https://community.openvpn.net/openvpn/wiki/Hardening) also gives further examples 153 | 154 | ### ssl_key_size 155 | 156 | The default key size is now set to `2048` bits. 157 | This setting also affects the size of the dhparam file. 158 | 159 | ##### Why 160 | 161 | > 2048 bits is OK, but both [NSA](https://cryptome.org/2016/01/CNSA-Suite-and-Quantum-Computing-FAQ.pdf) and [ANSSI](https://www.ssi.gouv.fr/uploads/2015/01/RGS_v-2-0_B1.pdf) recommend at least a 3072 bits for a future-proof key. As the size of the key will have an impact on speed, I leave the choice to use 2048, 3072 or 4096 bits RSA key. 4096 bits is what's most used and recommened today, but 3072 bits is still good. 162 | 163 | 164 | ### Cipher 165 | 166 | The default data channel cipher is now set to `AES-256-GCM` 167 | 168 | ##### Why 169 | 170 | OpenVPN was setting its default value to `BF-CBC`. In newer versions of OpenVPN 171 | it warns that this is no longer a secure cipher. 172 | The OpenVPN documentation recommends using this setting. 173 | 174 | ### tls_cipher 175 | 176 | The default tls_cipher option is now set to: `TLS-DHE-RSA-WITH-AES-256-GCM-SHA384:TLS-DHE-RSA-WITH-AES-256-CBC-SHA256:TLS-DHE-RSA-WITH-AES-128-GCM-SHA256:TLS-DHE-RSA-WITH-AES-128-CBC-SHA256` 177 | 178 | ##### Why 179 | 180 | Details of these ciphers and their uses can be found in the documentation links above. 181 | 182 | ## Contributions 183 | 184 | This module is maintained by [Vox Pupuli](https://voxpupuli.org/). Voxpupuli 185 | welcomes new contributions to this module, especially those that include 186 | documentation and rspec tests. We are happy to provide guidance if necessary. 187 | 188 | Please see [CONTRIBUTING](.github/CONTRIBUTING.md) for more details. 189 | 190 | ### Authors 191 | 192 | * Raffael Schmid 193 | * Vox Pupuli Team 194 | * List of contributors https://github.com/voxpupuli/puppet-openvpn/graphs/contributors 195 | -------------------------------------------------------------------------------- /Rakefile: -------------------------------------------------------------------------------- 1 | # Managed by modulesync - DO NOT EDIT 2 | # https://voxpupuli.org/docs/updating-files-managed-with-modulesync/ 3 | 4 | # Attempt to load voxpupuli-test (which pulls in puppetlabs_spec_helper), 5 | # otherwise attempt to load it directly. 6 | begin 7 | require 'voxpupuli/test/rake' 8 | rescue LoadError 9 | begin 10 | require 'puppetlabs_spec_helper/rake_tasks' 11 | rescue LoadError 12 | end 13 | end 14 | 15 | # load optional tasks for acceptance 16 | # only available if gem group releases is installed 17 | begin 18 | require 'voxpupuli/acceptance/rake' 19 | rescue LoadError 20 | end 21 | 22 | # load optional tasks for releases 23 | # only available if gem group releases is installed 24 | begin 25 | require 'voxpupuli/release/rake_tasks' 26 | rescue LoadError 27 | # voxpupuli-release not present 28 | else 29 | GCGConfig.user = 'voxpupuli' 30 | GCGConfig.project = 'puppet-openvpn' 31 | end 32 | 33 | desc "Run main 'test' task and report merged results to coveralls" 34 | task test_with_coveralls: [:test] do 35 | if Dir.exist?(File.expand_path('../lib', __FILE__)) 36 | require 'coveralls/rake/task' 37 | Coveralls::RakeTask.new 38 | Rake::Task['coveralls:push'].invoke 39 | else 40 | puts 'Skipping reporting to coveralls. Module has no lib dir' 41 | end 42 | end 43 | 44 | # vim: syntax=ruby 45 | -------------------------------------------------------------------------------- /data/defaults.yaml: -------------------------------------------------------------------------------- 1 | openvpn::autostart_all: true 2 | openvpn::manage_service: true 3 | openvpn::etc_directory: '/etc' 4 | openvpn::group: 'nobody' 5 | openvpn::link_openssl_cnf: true 6 | openvpn::pam_module_path: ~ 7 | openvpn::namespecific_rclink: false 8 | openvpn::default_easyrsa_ver: '3.0' 9 | openvpn::easyrsa_source: '/usr/share/easy-rsa/' 10 | openvpn::additional_packages: ['easy-rsa'] 11 | openvpn::ldap_auth_plugin_location: ~ 12 | openvpn::server_service_name: 'openvpn' 13 | openvpn::server_directory: '/etc/openvpn' 14 | -------------------------------------------------------------------------------- /data/family/Archlinux.yaml: -------------------------------------------------------------------------------- 1 | openvpn::etc_directory: '/etc' 2 | openvpn::additional_packages: ['easy-rsa'] 3 | openvpn::easyrsa_source: '/etc/easy-rsa/' 4 | openvpn::group: 'network' 5 | openvpn::ldap_auth_plugin_location: ~ 6 | openvpn::pam_module_path: /usr/lib/openvpn/plugins/openvpn-plugin-auth-pam.so 7 | openvpn::link_openssl_cnf: false 8 | openvpn::namespecific_rclink: false 9 | openvpn::server_directory: '/etc/openvpn/server' 10 | openvpn::server_service_name: 'openvpn-server' 11 | openvpn::server::user: 'openvpn' 12 | openvpn::server::group: 'network' 13 | -------------------------------------------------------------------------------- /data/family/Debian.yaml: -------------------------------------------------------------------------------- 1 | openvpn::etc_directory: '/etc' 2 | openvpn::group: 'nogroup' 3 | openvpn::link_openssl_cnf: true 4 | openvpn::namespecific_rclink: false 5 | openvpn::default_easyrsa_ver: '3.0' 6 | openvpn::additional_packages: ['easy-rsa','openvpn-auth-ldap'] 7 | openvpn::easyrsa_source: '/usr/share/easy-rsa/' 8 | openvpn::ldap_auth_plugin_location: '/usr/lib/openvpn/openvpn-auth-ldap.so' 9 | openvpn::pam_module_path: '/usr/lib/openvpn/openvpn-plugin-auth-pam.so' 10 | openvpn::server_directory: '/etc/openvpn/server' 11 | openvpn::server_service_name: 'openvpn-server' 12 | -------------------------------------------------------------------------------- /data/family/FreeBSD.yaml: -------------------------------------------------------------------------------- 1 | openvpn::etc_directory: '/usr/local/etc' 2 | openvpn::group: 'nogroup' 3 | openvpn::link_openssl_cnf: true 4 | openvpn::pam_module_path: '/usr/local/lib/openvpn/openvpn-auth-pam.so' 5 | openvpn::easyrsa_source: '/usr/local/share/easy-rsa' 6 | openvpn::namespecific_rclink: true 7 | openvpn::server_directory: '/usr/local/etc/openvpn' 8 | -------------------------------------------------------------------------------- /data/family/RedHat.yaml: -------------------------------------------------------------------------------- 1 | openvpn::etc_directory: '/etc' 2 | openvpn::group: 'nobody' 3 | openvpn::link_openssl_cnf: true 4 | openvpn::pam_module_path: '/usr/lib64/openvpn/plugin/lib/openvpn-auth-pam.so' 5 | openvpn::namespecific_rclink: false 6 | openvpn::easyrsa_source: '/usr/share/easy-rsa/3' 7 | openvpn::server_directory: '/etc/openvpn/server' 8 | openvpn::server_service_name: 'openvpn-server' 9 | -------------------------------------------------------------------------------- /data/family/Solaris.yaml: -------------------------------------------------------------------------------- 1 | openvpn::etc_directory: '/opt/local/etc' 2 | openvpn::server_directory: '/opt/local/etc/openvpn' 3 | openvpn::group: 'nogroup' 4 | openvpn::easyrsa_source: '/opt/local/share/examples/easyrsa' 5 | -------------------------------------------------------------------------------- /data/os/Rocky.yaml: -------------------------------------------------------------------------------- 1 | openvpn::pam_module_path: '/usr/lib64/openvpn/plugins/openvpn-auth-pam.so' -------------------------------------------------------------------------------- /hiera.yaml: -------------------------------------------------------------------------------- 1 | --- 2 | version: 5 3 | 4 | defaults: 5 | datadir: 'data' 6 | data_hash: yaml_data 7 | 8 | hierarchy: 9 | - name: 'OS Major Release Overrides' 10 | path: "family/%{facts.os.family}/%{facts.os.release.major}.yaml" 11 | - name: 'Operating System' 12 | path: "os/%{facts.os.name}.yaml" 13 | - name: 'Operating System Family' 14 | path: "family/%{facts.os.family}.yaml" 15 | - name: 'Defaults' 16 | path: 'defaults.yaml' 17 | -------------------------------------------------------------------------------- /lib/facter/easyrsa.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | 3 | Facter.add(:easyrsa) do 4 | confine kernel: 'Linux' 5 | setcode do 6 | binary = case Facter.value[:os]['family'] 7 | when 'RedHat' 8 | '/usr/share/easy-rsa/3/easyrsa' 9 | when 'Debian' 10 | '/usr/share/easy-rsa/easyrsa' 11 | when 'FreeBSD' 12 | '/usr/local/share/easy-rsa/easyrsa' 13 | when 'Solaris' 14 | '/opt/local/bin/easyrsa' 15 | else 16 | '' 17 | end 18 | 19 | if File.exist? binary 20 | data = Facter::Core::Execution.execute("#{binary} help") 21 | version = '3.0' if data.gsub!(%r{Easy-RSA 3 usage}, '') 22 | elsif Facter::Util::Resolution.which('easyrsa') 23 | data = Facter::Core::Execution.execute('easyrsa help') 24 | version = '3.0' if data.gsub!(%r{Easy-RSA 3 usage}, '') 25 | end 26 | version = nil if version.nil? 27 | version 28 | end 29 | end 30 | -------------------------------------------------------------------------------- /manifests/ca.pp: -------------------------------------------------------------------------------- 1 | # @summary This define creates the openvpn ca and ssl certificates 2 | # 3 | # @param dn_mode EasyRSA X509 DN mode. 4 | # @param country Country to be used for the SSL certificate 5 | # @param province Province to be used for the SSL certificate 6 | # @param city City to be used for the SSL certificate 7 | # @param organization Organization to be used for the SSL certificate 8 | # @param email Email address to be used for the SSL certificate 9 | # @param common_name Common name to be used for the SSL certificate 10 | # @param group User to drop privileges to after startup 11 | # @param ssl_key_algo SSL Key Algo. ec can enable elliptic curve support. ed uses ed25519 keys 12 | # @param ssl_key_size Length of SSL keys (in bits) generated by this module, used if ssl_key_algo is rsa 13 | # @param ssl_key_curve Define the named curve for the ssl keys, used if ssl_key_algo is ec, ed 14 | # @param key_expire The number of days to certify the server certificate for 15 | # @param ca_expire The number of days to certify the CA certificate for 16 | # @param digest Cryptographic digest to use 17 | # @param key_name Value for name_default variable in openssl.cnf and KEY_NAME in vars 18 | # @param key_ou Value for organizationalUnitName_default variable in openssl.cnf and KEY_OU in vars 19 | # @param key_cn Value for commonName_default variable in openssl.cnf and KEY_CN in vars 20 | # @param tls_auth Determins if a tls key is generated 21 | # @param tls_static_key Determins if a tls key is generated 22 | # @example 23 | # openvpn::ca { 24 | # 'my_user': 25 | # server => 'contractors', 26 | # remote_host => 'vpn.mycompany.com' 27 | # } 28 | # 29 | define openvpn::ca ( 30 | Enum['org','cn_only'] $dn_mode = 'org', 31 | Optional[String] $country = undef, 32 | Optional[String] $province = undef, 33 | Optional[String] $city = undef, 34 | Optional[String] $organization = undef, 35 | Optional[String] $email = undef, 36 | String $common_name = 'server', 37 | Optional[String] $group = undef, 38 | Enum['rsa', 'ec', 'ed'] $ssl_key_algo = 'rsa', 39 | Integer $ssl_key_size = 2048, 40 | String $ssl_key_curve = 'secp384r1', 41 | Integer $ca_expire = 3650, 42 | Integer $key_expire = 3650, 43 | Integer $crl_days = 30, 44 | Enum['md5','sha1','sha256','sha224','sha384','sha512'] $digest = 'sha512', 45 | Optional[String] $key_cn = undef, 46 | Optional[String] $key_name = undef, 47 | Optional[String] $key_ou = undef, 48 | Boolean $tls_auth = false, 49 | Boolean $tls_static_key = false, 50 | ) { 51 | if $tls_auth { 52 | warning('Parameter $tls_auth is deprecated. Use $tls_static_key instead.') 53 | } 54 | 55 | include openvpn 56 | $group_to_set = $group ? { 57 | undef => $openvpn::group, 58 | default => $group 59 | } 60 | 61 | File { 62 | group => $group_to_set, 63 | selinux_ignore_defaults => true, 64 | } 65 | 66 | $server_directory = $openvpn::server_directory 67 | 68 | ensure_resource('file', "${server_directory}/${name}", { 69 | ensure => directory, 70 | mode => '0750' 71 | }) 72 | 73 | file { "${server_directory}/${name}/easy-rsa" : 74 | ensure => directory, 75 | recurse => true, 76 | links => 'follow', 77 | source_permissions => 'use', 78 | group => 0, 79 | source => "file:${openvpn::easyrsa_source}", 80 | require => File["${server_directory}/${name}"], 81 | } 82 | 83 | file { "${server_directory}/${name}/easy-rsa/revoked": 84 | ensure => directory, 85 | mode => '0750', 86 | recurse => true, 87 | require => File["${server_directory}/${name}/easy-rsa"], 88 | } 89 | 90 | if $facts['os']['family'] == 'Archlinux' { 91 | file { "${server_directory}/${name}/easy-rsa/easyrsa": 92 | ensure => link, 93 | target => '/bin/easyrsa', 94 | require => File["${server_directory}/${name}/easy-rsa"], 95 | } 96 | } 97 | 98 | case $openvpn::easyrsa_version { 99 | '3.0': { 100 | file { "${server_directory}/${name}/easy-rsa/vars": 101 | ensure => file, 102 | mode => '0550', 103 | content => epp('openvpn/vars-30.epp', 104 | { 105 | 'server_directory' => $server_directory, 106 | 'openvpn_server' => $name, 107 | 'ssl_key_algo' => $ssl_key_algo, 108 | 'ssl_key_curve' => $ssl_key_curve, 109 | 'ssl_key_size' => $ssl_key_size, 110 | 'ca_expire' => $ca_expire, 111 | 'key_expire' => $key_expire, 112 | 'crl_days' => $crl_days, 113 | 'dn_mode' => $dn_mode, 114 | 'digest' => $digest, 115 | 'country' => $country, 116 | 'province' => $province, 117 | 'city' => $city, 118 | 'organization' => $organization, 119 | 'email' => $email, 120 | 'key_cn' => $key_cn, 121 | 'key_ou' => $key_ou, 122 | } 123 | ), 124 | require => File["${server_directory}/${name}/easy-rsa"], 125 | } 126 | 127 | if $openvpn::link_openssl_cnf { 128 | File["${server_directory}/${name}/easy-rsa/openssl.cnf"] { 129 | ensure => link, 130 | target => "${server_directory}/${name}/easy-rsa/openssl-easyrsa.cnf", 131 | before => Exec["initca ${name}"], 132 | } 133 | } 134 | 135 | $_initca_environment = $dn_mode ? { 136 | 'cn_only' => ["EASYRSA_REQ_CN=${common_name} CA"], 137 | default => [], 138 | } 139 | 140 | exec { "initca ${name}": 141 | command => "./easyrsa --batch --pki-dir=${server_directory}/${name}/easy-rsa/keys init-pki && ./easyrsa --batch build-ca nopass", 142 | cwd => "${server_directory}/${name}/easy-rsa", 143 | creates => "${server_directory}/${name}/easy-rsa/keys/ca.crt", 144 | environment => $_initca_environment, 145 | provider => 'shell', 146 | require => File["${server_directory}/${name}/easy-rsa/vars"], 147 | } 148 | 149 | if ($ssl_key_algo == 'rsa') { 150 | exec { "generate dh param ${name}": 151 | command => './easyrsa --batch gen-dh', 152 | timeout => 20000, 153 | cwd => "${server_directory}/${name}/easy-rsa", 154 | creates => "${server_directory}/${name}/easy-rsa/keys/dh.pem", 155 | provider => 'shell', 156 | require => Exec["generate server cert ${name}"], 157 | } 158 | } 159 | 160 | exec { "generate server cert ${name}": 161 | command => "./easyrsa build-server-full '${common_name}' nopass", 162 | cwd => "${server_directory}/${name}/easy-rsa", 163 | creates => "${server_directory}/${name}/easy-rsa/keys/private/${common_name}.key", 164 | provider => 'shell', 165 | require => Exec["initca ${name}"], 166 | } 167 | 168 | file { "${server_directory}/${name}/easy-rsa/keys/ca.crt": 169 | mode => '0640', 170 | require => Exec["initca ${name}"], 171 | } 172 | 173 | exec { "create crl.pem on ${name}": 174 | command => './easyrsa gen-crl', 175 | cwd => "${server_directory}/${name}/easy-rsa", 176 | creates => "${server_directory}/${name}/easy-rsa/keys/crl.pem", 177 | provider => 'shell', 178 | require => Exec["generate server cert ${name}"], 179 | } 180 | -> exec { "copy created crl.pem to ${name} keys directory": 181 | command => "cp ${server_directory}/${name}/easy-rsa/keys/crl.pem ${server_directory}/${name}/crl.pem", 182 | creates => "${server_directory}/${name}/crl.pem", 183 | provider => 'shell', 184 | } 185 | 186 | if $facts['os']['family'] == 'Archlinux' { 187 | file { [ 188 | "${server_directory}/${name}/easy-rsa/keys/issued", 189 | "${server_directory}/${name}/easy-rsa/keys/issued/${common_name}.crt", 190 | ]: 191 | mode => '0640', 192 | owner => 'openvpn', 193 | group => $openvpn::group, 194 | require => Exec["generate server cert ${name}"], 195 | } 196 | 197 | file { [ 198 | "${server_directory}/${name}/easy-rsa/keys/private", 199 | "${server_directory}/${name}/easy-rsa/keys/private/${common_name}.key", 200 | ]: 201 | mode => '0640', 202 | owner => 'openvpn', 203 | group => $openvpn::group, 204 | require => Exec["generate server cert ${name}"], 205 | } 206 | 207 | file { [ 208 | "${server_directory}/${name}/easy-rsa/keys", 209 | "${server_directory}/${name}/easy-rsa/keys/dh.pem", 210 | ]: 211 | mode => '0640', 212 | owner => 'openvpn', 213 | group => $openvpn::group, 214 | require => Exec["generate dh param ${name}"], 215 | } 216 | } 217 | } 218 | default: { 219 | fail("unexepected value for EasyRSA version, got '${openvpn::easyrsa_version}', expect 3.0.") 220 | } 221 | } 222 | 223 | file { "${server_directory}/${name}/easy-rsa/openssl.cnf": 224 | require => File["${server_directory}/${name}/easy-rsa"], 225 | } 226 | 227 | file { "${server_directory}/${name}/keys": 228 | ensure => link, 229 | target => "${server_directory}/${name}/easy-rsa/keys", 230 | mode => '0640', 231 | require => File["${server_directory}/${name}/easy-rsa"], 232 | } 233 | 234 | file { "${server_directory}/${name}/crl.pem": 235 | mode => '0640', 236 | require => Exec["create crl.pem on ${name}"], 237 | } 238 | 239 | if $tls_static_key { 240 | exec { "generate tls key for ${name}": 241 | command => 'openvpn --genkey --secret keys/ta.key', 242 | cwd => "${server_directory}/${name}/easy-rsa", 243 | creates => "${server_directory}/${name}/easy-rsa/keys/ta.key", 244 | provider => 'shell', 245 | require => Exec["generate server cert ${name}"], 246 | } 247 | } 248 | } 249 | -------------------------------------------------------------------------------- /manifests/client.pp: -------------------------------------------------------------------------------- 1 | # 2 | # @summary This define creates client certs for a specified server as well as a tarball that can be directly imported into clients 3 | # 4 | # @param server Name of the corresponding openvpn endpoint 5 | # @param compression Which compression algorithm to use. This parameter is deprecated in OpenVPN 2.5. 6 | # @param dev Device method 7 | # @param mute Set log mute level 8 | # @param mute_replay_warnings Silence duplicate packet warnings (common on wireless networks) 9 | # @param nobind Whether or not to bind to a specific port number 10 | # @param persist_key Try to retain access to resources that may be unavailable because of privilege downgrades 11 | # @param persist_tun Try to retain access to resources that may be unavailable because of privilege downgrades 12 | # @param port The port the openvpn server service is running on 13 | # @param proto What IP protocol is being used. 14 | # @param remote_host The IP or hostname of the openvpn server service. 15 | # @param cipher Cipher to use for packet encryption 16 | # @param tls_cipher TLS Ciphers to use 17 | # @param resolv_retry How many seconds should the openvpn client try to resolve the server's hostname 18 | # @param auth_retry Controls how OpenVPN responds to username/password verification errors such as the client-side response to an AUTH_FAILED message from the server or verification failure of the private key password. 19 | # @param verb Level of logging verbosity 20 | # @param pam DEPRECATED: Boolean, Enable/Disable. 21 | # @param authuserpass Set if username and password required 22 | # @param tls_auth Activates tls-auth to Add an additional layer of HMAC authentication on top of the TLS control channel to protect against DoS attacks. This has to be set to the same value as on the Server 23 | # @param tls_crypt Encrypt and authenticate all control channel packets with the key from keyfile. (See --tls-auth for more background.) 24 | # @param x509_name Common name of openvpn server to make an x509-name verification 25 | # @param setenv Set a custom environmental variable name=value to pass to script. 26 | # @param setenv_safe Set a custom environmental variable OPENVPN_name=value to pass to script. This directive is designed to be pushed by the server to clients, and the prepending of "OPENVPN_" to the environmental variable is a safety precaution to prevent a LD_PRELOAD style attack from a malicious or compromised server. 27 | # @param up Script which we want to run when openvpn client is connecting 28 | # @param down Script which we want to run when openvpn client is disconneting 29 | # @param sndbuf Set the TCP/UDP socket send buffer size. 30 | # @param rcvbuf Set the TCP/UDP socket receive buffer size. 31 | # @param shared_ca The name of an openssl::ca resource to use. 32 | # @param custom_options Hash of additional options that you want to append to the configuration file. 33 | # @param expire Set a custom expiry time to pass to script. Value is the number of days the certificate is valid for. 34 | # @param readme Text to place in a README file which is included in download-configs archive. 35 | # @param pull Allow server to push options like dns or routes 36 | # @param server_extca_enabled Turn this on if you are using an external CA solution, like FreeIPA. Use this in Combination with exported_ressourced, since they don't have Access to the Serverconfig 37 | # @param remote_cert_tls Enable or disable use of remote-cert-tls used with client configuration 38 | # 39 | # @example 40 | # openvpn::client { 41 | # 'my_user': 42 | # server => 'contractors', 43 | # remote_host => 'vpn.mycompany.com' 44 | # } 45 | # 46 | define openvpn::client ( 47 | String $server, 48 | Optional[String[1]] $compression = undef, 49 | Enum['tap', 'tun'] $dev = 'tun', 50 | Integer $mute = 20, 51 | Boolean $mute_replay_warnings = true, 52 | Boolean $nobind = true, 53 | Boolean $persist_key = true, 54 | Boolean $persist_tun = true, 55 | String $port = '1194', 56 | Enum['tcp','udp'] $proto = 'tcp', 57 | Variant[String, Array[String]] $remote_host = $facts['networking']['fqdn'], 58 | String $resolv_retry = 'infinite', 59 | Enum['none', 'nointeract', 'interact'] $auth_retry = 'none', 60 | String $verb = '3', 61 | Boolean $pam = false, 62 | String $cipher = 'AES-256-GCM', 63 | String $tls_cipher = 'TLS-DHE-RSA-WITH-AES-256-GCM-SHA384:TLS-DHE-RSA-WITH-AES-256-CBC-SHA256:TLS-DHE-RSA-WITH-AES-128-GCM-SHA256:TLS-DHE-RSA-WITH-AES-128-CBC-SHA256', 64 | Boolean $authuserpass = false, 65 | Hash $setenv = {}, 66 | Hash $setenv_safe = {}, 67 | Optional[String[1]] $up = undef, 68 | Optional[String[1]] $down = undef, 69 | Boolean $tls_auth = false, 70 | Boolean $tls_crypt = false, 71 | Optional[String] $x509_name = undef, 72 | Optional[Integer] $sndbuf = undef, 73 | Optional[Integer] $rcvbuf = undef, 74 | Optional[String] $shared_ca = undef, 75 | Hash $custom_options = {}, 76 | Optional[Integer] $expire = undef, 77 | Optional[String] $readme = undef, 78 | Boolean $pull = false, 79 | Boolean $server_extca_enabled = false, 80 | Boolean $remote_cert_tls = true, 81 | ) { 82 | if $pam { 83 | warning('Using $pam is deprecated. Use $authuserpass instead!') 84 | } 85 | 86 | Openvpn::Server[$server] 87 | -> Openvpn::Client[$name] 88 | 89 | $extca_enabled = pick(getparam(Openvpn::Server[$server], 'extca_enabled'), $server_extca_enabled) 90 | if $extca_enabled { fail('cannot currently create client configs when corresponding openvpn::server is extca_enabled') } 91 | if $tls_auth and $tls_crypt { fail('tls_auth and tls_crypt are mutually exclusive') } 92 | 93 | $ca_name = pick($shared_ca, $server) 94 | Openvpn::Ca[$ca_name] 95 | -> Openvpn::Client[$name] 96 | 97 | $server_directory = $openvpn::server_directory 98 | 99 | if $expire { 100 | if is_integer($expire) { 101 | case $openvpn::easyrsa_version { 102 | '3.0': { 103 | $env_expire = "EASYRSA_CERT_EXPIRE=${expire} EASYRSA_NO_VARS=1" 104 | } 105 | default: { 106 | fail("unexepected value for EasyRSA version, got '${openvpn::easyrsa_version}', expect 3.0.") 107 | } 108 | } 109 | } else { 110 | warning("Custom expiry time ignored: only integer is accepted but ${expire} is given.") 111 | } 112 | } else { 113 | $env_expire = '' 114 | } 115 | 116 | case $openvpn::easyrsa_version { 117 | '3.0': { 118 | exec { "generate certificate for ${name} in context of ${ca_name}": 119 | command => "${env_expire} ./easyrsa --batch build-client-full ${name} nopass", 120 | cwd => "${server_directory}/${ca_name}/easy-rsa", 121 | creates => "${server_directory}/${ca_name}/easy-rsa/keys/issued/${name}.crt", 122 | provider => 'shell'; 123 | } 124 | 125 | file { "${server_directory}/${server}/download-configs/${name}/keys/${name}/${name}.crt": 126 | ensure => link, 127 | target => "${server_directory}/${ca_name}/easy-rsa/keys/issued/${name}.crt", 128 | require => Exec["generate certificate for ${name} in context of ${ca_name}"], 129 | } 130 | 131 | file { "${server_directory}/${server}/download-configs/${name}/keys/${name}/${name}.key": 132 | ensure => link, 133 | target => "${server_directory}/${ca_name}/easy-rsa/keys/private/${name}.key", 134 | require => Exec["generate certificate for ${name} in context of ${ca_name}"], 135 | } 136 | } 137 | default: { 138 | fail("unexepected value for EasyRSA version, got '${openvpn::easyrsa_version}', expect 3.0.") 139 | } 140 | } 141 | 142 | file { 143 | [ 144 | "${server_directory}/${server}/download-configs/${name}", 145 | "${server_directory}/${server}/download-configs/${name}/keys", 146 | "${server_directory}/${server}/download-configs/${name}/keys/${name}", 147 | ]: 148 | ensure => directory, 149 | } 150 | 151 | file { "${server_directory}/${server}/download-configs/${name}/keys/${name}/ca.crt": 152 | ensure => link, 153 | target => "${server_directory}/${ca_name}/easy-rsa/keys/ca.crt", 154 | require => Exec["generate certificate for ${name} in context of ${ca_name}"], 155 | } 156 | 157 | if $tls_auth or $tls_crypt { 158 | file { "${server_directory}/${server}/download-configs/${name}/keys/${name}/ta.key": 159 | ensure => link, 160 | target => "${server_directory}/${server}/easy-rsa/keys/ta.key", 161 | require => Exec["generate certificate for ${name} in context of ${server}"], 162 | before => [ 163 | Exec["tar the thing ${server} with ${name}"], 164 | Concat["${server_directory}/${server}/download-configs/${name}.ovpn"], 165 | ], 166 | notify => Exec["tar the thing ${server} with ${name}"], 167 | } 168 | } 169 | 170 | if $readme { 171 | file { "${server_directory}/${server}/download-configs/${name}/README": 172 | ensure => file, 173 | owner => root, 174 | group => root, 175 | mode => '0444', 176 | content => $readme, 177 | notify => Exec["tar the thing ${server} with ${name}"]; 178 | } 179 | } 180 | 181 | file { 182 | "${server_directory}/${server}/download-configs/${name}.tblk": 183 | ensure => directory; 184 | 185 | "${server_directory}/${server}/download-configs/${name}.tblk/${name}.ovpn": 186 | ensure => link, 187 | target => "${server_directory}/${server}/download-configs/${name}.ovpn", 188 | require => [ 189 | Concat["${server_directory}/${server}/download-configs/${name}.ovpn"], 190 | File["${server_directory}/${server}/download-configs/${name}.tblk"], 191 | ], 192 | before => Exec["tar the thing ${server} with ${name}"]; 193 | } 194 | 195 | file { "${server_directory}/${server}/download-configs/${name}/${name}.conf": 196 | owner => root, 197 | group => 0, 198 | mode => '0444', 199 | content => template('openvpn/client.erb', 'openvpn/client_external_auth.erb'), 200 | } 201 | 202 | exec { "tar the thing ${server} with ${name}": 203 | cwd => "${server_directory}/${server}/download-configs/", 204 | command => "/bin/rm ${name}.tar.gz; tar --exclude=\\*.conf.d -chzvf ${name}.tar.gz ${name} ${name}.tblk", 205 | refreshonly => true, 206 | require => [ 207 | File["${server_directory}/${server}/download-configs/${name}/${name}.conf"], 208 | File["${server_directory}/${server}/download-configs/${name}/keys/${name}/ca.crt"], 209 | File["${server_directory}/${server}/download-configs/${name}/keys/${name}/${name}.key"], 210 | File["${server_directory}/${server}/download-configs/${name}/keys/${name}/${name}.crt"], 211 | Concat["${server_directory}/${server}/download-configs/${name}.ovpn"], 212 | File["${server_directory}/${server}/download-configs/${name}.tblk"], 213 | File["${server_directory}/${server}/download-configs/${name}.tblk/${name}.ovpn"], 214 | ], 215 | } 216 | 217 | file { "${server_directory}/${server}/download-configs/${name}.tar.gz": 218 | ensure => file, 219 | replace => 'no', 220 | require => Exec["tar the thing ${server} with ${name}"], 221 | } 222 | 223 | concat { "${server_directory}/${server}/download-configs/${name}.ovpn": 224 | mode => '0400', 225 | notify => Exec["tar the thing ${server} with ${name}"], 226 | require => [ 227 | File["${server_directory}/${server}/download-configs/${name}/keys/${name}/ca.crt"], 228 | File["${server_directory}/${server}/download-configs/${name}/keys/${name}/${name}.key"], 229 | File["${server_directory}/${server}/download-configs/${name}/keys/${name}/${name}.crt"], 230 | ], 231 | } 232 | 233 | concat::fragment { "${server_directory}/${server}/download-configs/${name}.ovpn/client_config": 234 | target => "${server_directory}/${server}/download-configs/${name}.ovpn", 235 | content => template('openvpn/client.erb'), 236 | order => '01', 237 | } 238 | 239 | concat::fragment { "${server_directory}/${server}/download-configs/${name}.ovpn/ca_open_tag": 240 | target => "${server_directory}/${server}/download-configs/${name}.ovpn", 241 | content => "# Authentication \n\n", 242 | order => '02', 243 | } 244 | 245 | concat::fragment { "${server_directory}/${server}/download-configs/${name}.ovpn/ca": 246 | target => "${server_directory}/${server}/download-configs/${name}.ovpn", 247 | source => "${server_directory}/${server}/download-configs/${name}/keys/${name}/ca.crt", 248 | order => '03', 249 | } 250 | 251 | concat::fragment { "${server_directory}/${server}/download-configs/${name}.ovpn/ca_close_tag": 252 | target => "${server_directory}/${server}/download-configs/${name}.ovpn", 253 | content => "\n", 254 | order => '04', 255 | } 256 | 257 | concat::fragment { "${server_directory}/${server}/download-configs/${name}.ovpn/key_open_tag": 258 | target => "${server_directory}/${server}/download-configs/${name}.ovpn", 259 | content => "\n", 260 | order => '05', 261 | } 262 | 263 | concat::fragment { "${server_directory}/${server}/download-configs/${name}.ovpn/key": 264 | target => "${server_directory}/${server}/download-configs/${name}.ovpn", 265 | source => "${server_directory}/${server}/download-configs/${name}/keys/${name}/${name}.key", 266 | order => '06', 267 | } 268 | 269 | concat::fragment { "${server_directory}/${server}/download-configs/${name}.ovpn/key_close_tag": 270 | target => "${server_directory}/${server}/download-configs/${name}.ovpn", 271 | content => "\n", 272 | order => '07', 273 | } 274 | 275 | concat::fragment { "${server_directory}/${server}/download-configs/${name}.ovpn/cert_open_tag": 276 | target => "${server_directory}/${server}/download-configs/${name}.ovpn", 277 | content => "\n", 278 | order => '08', 279 | } 280 | 281 | concat::fragment { "${server_directory}/${server}/download-configs/${name}.ovpn/cert": 282 | target => "${server_directory}/${server}/download-configs/${name}.ovpn", 283 | source => "${server_directory}/${server}/download-configs/${name}/keys/${name}/${name}.crt", 284 | order => '09', 285 | } 286 | 287 | concat::fragment { "${server_directory}/${server}/download-configs/${name}.ovpn/cert_close_tag": 288 | target => "${server_directory}/${server}/download-configs/${name}.ovpn", 289 | content => "\n", 290 | order => '10', 291 | } 292 | 293 | if $tls_auth { 294 | concat::fragment { "/etc/openvpn/${server}/download-configs/${name}.ovpn/tls_auth_open_tag": 295 | target => "${server_directory}/${server}/download-configs/${name}.ovpn", 296 | content => "\n", 297 | order => '11', 298 | } 299 | 300 | concat::fragment { "${server_directory}/${server}/download-configs/${name}.ovpn/tls_auth": 301 | target => "${server_directory}/${server}/download-configs/${name}.ovpn", 302 | source => "${server_directory}/${server}/download-configs/${name}/keys/${name}/ta.key", 303 | order => '12', 304 | } 305 | 306 | concat::fragment { "${server_directory}/${server}/download-configs/${name}.ovpn/tls_auth_close_tag": 307 | target => "${server_directory}/${server}/download-configs/${name}.ovpn", 308 | content => "\nkey-direction 1\n", 309 | order => '13', 310 | } 311 | } 312 | elsif $tls_crypt { 313 | concat::fragment { "/etc/openvpn/${server}/download-configs/${name}.ovpn/tls_crypt_open_tag": 314 | target => "${server_directory}/${server}/download-configs/${name}.ovpn", 315 | content => "\n", 316 | order => '11', 317 | } 318 | 319 | concat::fragment { "${server_directory}/${server}/download-configs/${name}.ovpn/tls_crypt": 320 | target => "${server_directory}/${server}/download-configs/${name}.ovpn", 321 | source => "${server_directory}/${server}/download-configs/${name}/keys/${name}/ta.key", 322 | order => '12', 323 | } 324 | 325 | concat::fragment { "${server_directory}/${server}/download-configs/${name}.ovpn/tls_crypt_close_tag": 326 | target => "${server_directory}/${server}/download-configs/${name}.ovpn", 327 | content => "\n", 328 | order => '13', 329 | } 330 | } 331 | } 332 | -------------------------------------------------------------------------------- /manifests/client_specific_config.pp: -------------------------------------------------------------------------------- 1 | # @summary This define configures options which will be pushed by the server to a specific client only. 2 | 3 | # This feature is explained here: http://openvpn.net/index.php/open-source/documentation/howto.html#policy 4 | # All the parameters are explained in the openvpn documentation http://openvpn.net/index.php/open-source/documentation/howto.html#policy 5 | # 6 | # @param server Name of the corresponding openvpn endpoint 7 | # @param iroute Array of iroute combinations. 8 | # @param iroute_ipv6 Array of IPv6 iroute combinations. 9 | # @param route Array of route combinations pushed to client. 10 | # @param route_ipv6 Array of route-ipv6 combinations pushed to client. 11 | # @param ifconfig IP configuration to push to the client. 12 | # @param ifconfig_ipv6 IPv6 configuration to push to the client. 13 | # @param dhcp_options DHCP options to push to the client. 14 | # @param redirect_gateway Redirect all traffic to gateway 15 | # @param custom_options Hash of additional options to append to the configuration file. 16 | # @param ensure Sets the client specific configuration file status (present or absent) 17 | # @param manage_client_configs Manage dependencies on Openvpn::Client ressources 18 | # 19 | # @example 20 | # openvpn::client_specific_config { 21 | # 'vpn_client': 22 | # server => 'contractors', 23 | # iroute => ['10.0.1.0 255.255.255.0'], 24 | # ifconfig => '10.10.10.1 10.10.10.2', 25 | # dhcp_options => ['DNS 8.8.8.8'] 26 | # } 27 | define openvpn::client_specific_config ( 28 | String[1] $server, 29 | Enum['present', 'absent'] $ensure = present, 30 | Array[String[1]] $iroute = [], 31 | Array[String[1]] $iroute_ipv6 = [], 32 | Array[String[1]] $route = [], 33 | Array[String[1]] $route_ipv6 = [], 34 | Optional[String[1]] $ifconfig = undef, 35 | Optional[String[1]] $ifconfig_ipv6 = undef, 36 | Array[String[1]] $dhcp_options = [], 37 | Boolean $redirect_gateway = false, 38 | Hash $custom_options = {}, 39 | Boolean $manage_client_configs = true, 40 | ) { 41 | if $manage_client_configs { 42 | Openvpn::Server[$server] 43 | -> Openvpn::Client[$name] 44 | -> Openvpn::Client_specific_config[$name] 45 | } else { 46 | Openvpn::Server[$server] 47 | -> Openvpn::Client_specific_config[$name] 48 | } 49 | 50 | file { "${openvpn::server_directory}/${server}/client-configs/${name}": 51 | ensure => $ensure, 52 | content => template('openvpn/client_specific_config.erb'), 53 | } 54 | } 55 | -------------------------------------------------------------------------------- /manifests/config.pp: -------------------------------------------------------------------------------- 1 | # 2 | # @summary This class sets up the openvpn enviornment as well as the default config file 3 | # 4 | class openvpn::config { 5 | if $facts['os']['family'] == 'Debian' { 6 | concat { '/etc/default/openvpn': 7 | owner => root, 8 | group => 0, 9 | mode => '0644', 10 | warn => true, 11 | } 12 | 13 | concat::fragment { 'openvpn.default.header': 14 | content => template('openvpn/etc-default-openvpn.erb'), 15 | target => '/etc/default/openvpn', 16 | order => '01', 17 | } 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /manifests/init.pp: -------------------------------------------------------------------------------- 1 | # 2 | # @summary This module installs the openvpn service, configures vpn endpoints, generates client certificates, and generates client config files 3 | # 4 | # @param autostart_all Whether openvpn instances should be started automatically on boot. 5 | # @param manage_service Whether the openvpn service should be managed by puppet. 6 | # @param etc_directory Path of the configuration directory. 7 | # @param group File group of the generated config files. 8 | # @param link_openssl_cnf Link easy-rsa/openssl.cnf to easy-rsa/openssl-1.0.0.cnf 9 | # @param pam_module_path Path to openvpn-auth-pam.so 10 | # @param namespecific_rclink Enable namespecific rclink's (BSD-style) 11 | # @param default_easyrsa_ver Expected version of easyrsa. 12 | # @param easyrsa_source Location of easyrsa. 13 | # @param additional_packages Additional packages 14 | # @param ldap_auth_plugin_location Path to the ldap auth pam module 15 | # @param client_defaults Hash of defaults for clients passed to openvpn::client defined type. 16 | # @param clients Hash of clients passed to openvpn::client defined type. 17 | # @param client_specific_config_defaults Hash of defaults for client specific configurations passed to openvpn::client_specific_config defined type. 18 | # @param client_specific_configs Hash of client specific configurations passed to openvpn::client_specific_config defined type. 19 | # @param revoke_defaults Hash of defaults for revokes passed to openvpn::revoke defined type. 20 | # @param revokes Hash of revokes passed to openvpn::revoke defined type. 21 | # @param server_defaults Hash of defaults for servers passed to openvpn::server defined type. 22 | # @param servers Hash of servers passed to openvpn::server defined type. 23 | # @param server_directory Path of the server configuration. This is usually `/etc_directory/openvpn`, but RHEL/CentOS 8 uses `/etc_directory/openvpn/server` 24 | # @param server_service_name Name of the openvpn server service. This is usually `openvpn`, but RHEL/CentOS 8 uses `openvpn-server`. 25 | # 26 | # @example 27 | # class { 'openvpn': 28 | # autostart_all => true, 29 | # } 30 | # 31 | class openvpn ( 32 | Boolean $autostart_all, 33 | Boolean $manage_service, 34 | Stdlib::Absolutepath $etc_directory, 35 | String[1] $group, 36 | Boolean $link_openssl_cnf, 37 | Optional[Stdlib::Absolutepath] $pam_module_path, 38 | Boolean $namespecific_rclink, 39 | Pattern[/^[23]\.0$/] $default_easyrsa_ver, 40 | Stdlib::Unixpath $easyrsa_source, 41 | Variant[String[1], Array[String[1]]] $additional_packages, 42 | Optional[Stdlib::Absolutepath] $ldap_auth_plugin_location, 43 | String[1] $server_service_name, 44 | Optional[Stdlib::Absolutepath] $server_directory, 45 | 46 | Hash $client_defaults = {}, 47 | Hash $clients = {}, 48 | Hash $client_specific_config_defaults = {}, 49 | Hash $client_specific_configs = {}, 50 | Hash $revoke_defaults = {}, 51 | Hash $revokes = {}, 52 | Hash $server_defaults = {}, 53 | Hash $servers = {}, 54 | ) { 55 | $easyrsa_version = $facts['easyrsa'] ? { 56 | undef => $default_easyrsa_ver, 57 | default => $facts['easyrsa'], 58 | } 59 | 60 | include openvpn::install 61 | include openvpn::config 62 | 63 | Class['openvpn::install'] 64 | -> Class['openvpn::config'] 65 | -> Class['openvpn'] 66 | 67 | if $facts['service_provider'] != 'systemd' { 68 | class { 'openvpn::service': 69 | subscribe => [Class['openvpn::config'], Class['openvpn::install']], 70 | } 71 | 72 | if empty($servers) { 73 | Class['openvpn::service'] -> Class['openvpn'] 74 | } 75 | } 76 | 77 | $clients.each |$name, $params| { 78 | openvpn::client { 79 | default: 80 | * => $client_defaults; 81 | $name: 82 | * => $params; 83 | } 84 | } 85 | 86 | $client_specific_configs.each |$name, $params| { 87 | openvpn::client_specific_config { 88 | default: 89 | * => $client_specific_config_defaults; 90 | $name: 91 | * => $params; 92 | } 93 | } 94 | 95 | $revokes.each |$name, $params| { 96 | openvpn::revoke { 97 | default: 98 | * => $revoke_defaults; 99 | $name: 100 | * => $params; 101 | } 102 | } 103 | 104 | $servers.each |$name, $params| { 105 | openvpn::server { 106 | default: 107 | * => $server_defaults; 108 | $name: 109 | * => $params; 110 | } 111 | } 112 | } 113 | -------------------------------------------------------------------------------- /manifests/install.pp: -------------------------------------------------------------------------------- 1 | # 2 | # @summary This module installs the openvpn service, configures vpn endpoints, generates client certificates, and generates client config files 3 | # 4 | class openvpn::install { 5 | include openvpn 6 | 7 | stdlib::ensure_packages(['openvpn']) 8 | if $openvpn::additional_packages { 9 | stdlib::ensure_packages($openvpn::additional_packages) 10 | } 11 | 12 | if $facts['os']['family'] == 'Archlinux' { 13 | File { 14 | owner => 'openvpn', 15 | group => $openvpn::group, 16 | } 17 | } 18 | 19 | file { 20 | ["${openvpn::etc_directory}/openvpn", "${openvpn::etc_directory}/openvpn/keys", '/var/log/openvpn',]: 21 | ensure => directory, 22 | require => Package['openvpn']; 23 | } 24 | } 25 | -------------------------------------------------------------------------------- /manifests/revoke.pp: -------------------------------------------------------------------------------- 1 | # 2 | # @summary This define creates a revocation on a certificate for a specified server. 3 | # 4 | # @param server Name of the corresponding openvpn endpoint 5 | # @example 6 | # openvpn::client { 7 | # 'my_user': 8 | # server => 'contractors' 9 | # } 10 | # @example 11 | # openvpn::revoke { 12 | # 'my_user': 13 | # server => 'contractors' 14 | # } 15 | # 16 | define openvpn::revoke ( 17 | String $server, 18 | ) { 19 | Openvpn::Server[$server] 20 | -> Openvpn::Revoke[$name] 21 | 22 | Openvpn::Client[$name] 23 | -> Openvpn::Revoke[$name] 24 | 25 | $server_directory = $openvpn::server_directory 26 | 27 | $revocation_command = $openvpn::easyrsa_version ? { 28 | '3.0' => "./easyrsa --batch revoke ${name}; echo \"exit $?\" | grep -qE '(error 23|exit (0|2))'", 29 | default => fail("unexepected value for EasyRSA version, got '${openvpn::easyrsa_version}', expect 3.0."), 30 | } 31 | 32 | $renew_command = $openvpn::easyrsa_version ? { 33 | '3.0' => './easyrsa --batch gen-crl', 34 | default => fail("unexepected value for EasyRSA version, got '${openvpn::easyrsa_version}', expect 3.0."), 35 | } 36 | 37 | file { "${server_directory}/${server}/easy-rsa/revoked/${name}": 38 | ensure => file, 39 | require => Exec["revoke certificate for ${name} in context of ${server}"], 40 | } 41 | 42 | exec { "revoke certificate for ${name} in context of ${server}": 43 | command => $revocation_command, 44 | cwd => "${server_directory}/${server}/easy-rsa", 45 | provider => 'shell', 46 | notify => Exec["renew crl.pem on ${server} because of revocation of ${name}"], 47 | creates => "${server_directory}/${server}/easy-rsa/revoked/${name}", 48 | } 49 | 50 | exec { "renew crl.pem on ${server} because of revocation of ${name}": 51 | command => $renew_command, 52 | cwd => "${server_directory}/${server}/easy-rsa", 53 | provider => 'shell', 54 | refreshonly => true, 55 | } 56 | 57 | if ($openvpn::easyrsa_version == '3.0') { 58 | exec { "copy renewed crl.pem to ${server} keys directory because of revocation of ${name}": 59 | command => "cp ${server_directory}/${server}/easy-rsa/keys/crl.pem ${server_directory}/${server}/crl.pem", 60 | subscribe => Exec["renew crl.pem on ${server} because of revocation of ${name}"], 61 | provider => 'shell', 62 | refreshonly => true, 63 | } 64 | } 65 | } 66 | -------------------------------------------------------------------------------- /manifests/server.pp: -------------------------------------------------------------------------------- 1 | # 2 | # @summary This define creates the openvpn server instance which can run in server or client mode. 3 | # 4 | # @param dn_mode EasyRSA X509 DN mode. 5 | # @param country Country to be used for the SSL certificate, mandatory for server mode. 6 | # @param province Province to be used for the SSL certificate, mandatory for server mode. 7 | # @param city City to be used for the SSL certificate, mandatory for server mode. 8 | # @param organization Organization to be used for the SSL certificate, mandatory for server mode. 9 | # @param email Email address to be used for the SSL certificate, mandatory for server mode. 10 | # @param remote List of OpenVPN endpoints to connect to. 11 | # @param remote_random_hostname OpenVPN will prepend a random string (6 bytes, 12 hex characters) to hostname to prevent DNS caching. For example, "foo.example.com" would be modified to ".foo.example.com". 12 | # @param remote_random When multiple ${remote} address/ports are specified, initially randomize the order of the list as a kind of basic load-balancing measure. 13 | # @param common_name Common name to be used for the SSL certificate 14 | # @param compression Which compression algorithm to use. This parameter is deprecated in OpenVPN 2.5. 15 | # @param dev TUN/TAP virtual network device 16 | # @param user Group to drop privileges to after startup 17 | # @param group User to drop privileges to after startup 18 | # @param ipp Persist ifconfig information to a file to retain client IP addresses between sessions 19 | # @param duplicate_cn Allow multiple connections on one cn 20 | # @param local Interface for openvpn to bind to. 21 | # @param logfile Logfile for this openvpn server 22 | # @param manage_logfile_directory Manage the directory that the logfile is located in 23 | # @param logdirectory_user The owner user of the logfile directory 24 | # @param logdirectory_group The owner group of the logfile directory 25 | # @param port The port the openvpn server service is running on# 26 | # @param portshare The address and port to which non openvpn request shall be forwared, e.g. 127.0.0.1 8443 27 | # @param proto What IP protocol is being used. 28 | # @param status_log Logfile for periodic dumps of the vpn service status 29 | # @param status_version Choose the status file format version number. 30 | # @param server Network to assign client addresses out of. Required in tun mode, not in tap mode 31 | # @param server_ipv6 IPv6 network to assign client addresses out of 32 | # @param server_bridge Server configuration to comply with existing DHCP server 33 | # @param push Options to push out to the client. This can include routes, DNS servers, DNS search domains, and many other options. 34 | # @param route Add route to routing table after connection is established. Multiple routes can be specified. 35 | # @param route_ipv6 Add IPv6 route to routing table after connection is established. Multiple routes can be specified. 36 | # @param keepalive Add keepalive directive (ping and ping-restart) to server. Should match the form "n m". 37 | # @param ssl_key_algo SSL Key Algo. ec can enable elliptic curve support. ed uses ed25519 keys 38 | # @param ssl_key_size Length of SSL keys (in bits) generated by this module, used if ssl_key_algo is rsa 39 | # @param ssl_key_curve Define the named curve for the ssl keys, used if ssl_key_algo is ec, ed 40 | # @param ecdh_curve Define the named curve for ECDH key exchange, used if ssl_key_algo is ec, ed 41 | # @param topology Define the network topology type 42 | # @param c2c Enable client to client visibility 43 | # @param tcp_nodelay Enable/Disable. 44 | # @param ccd_exclusive Enable/Disable. 45 | # @param pam Enable/Disable. 46 | # @param pam_module_arguments Arguments to pass to the PAM module. For FreeIPA, set this to "openvpn login USERNAME password PASSWORD" and create HBAC Service "openvpn". 47 | # @param management Enable management interface 48 | # @param management_ip IP address where the management interface will listen 49 | # @param management_port Port where the management interface will listen 50 | # @param up Script which we want to run when openvpn server starts. If the path to the scirpt does not contain a slash, it will be assumed to be in `openvpn/${name}/scripts` directory. 51 | # @param down Script which we want to run when openvpn server stops. If the path to the scirpt does not contain a slash, it will be assumed to be in `openvpn/${name}/scripts` directory. 52 | # @param client_connect Script which we want to run when a client connects. If the path to the scirpt does not contain a slash, it will be assumed to be in `openvpn/${name}/scripts` directory. 53 | # @param client_disconnect Script which we want to run when a client disconnects. If the path to the scirpt does not contain a slash, it will be assumed to be in `openvpn/${name}/scripts` directory. 54 | # @param username_as_common_name If true then set username-as-common-name 55 | # @param client_cert_not_required If true then set client-cert-not-required 56 | # @param ldap_enabled If ldap is enabled, do stuff 57 | # @param ldap_server URL of LDAP server. ie. ldap://URL:PORT 58 | # @param ldap_binddn LDAP DN to bind as# 59 | # @param ldap_bindpass LDAP password for ldapbinddn 60 | # @param ldap_u_basedn Place in the LDAP tree to look for users 61 | # @param ldap_u_filter User SearchFilter for LDAP accounts 62 | # @param ldap_g_basedn Place in the LDAP tree to look for groups 63 | # @param ldap_gmember If defined use group block in ldap.conf 64 | # @param ldap_g_filter Group SearchFilter for LDAP accounts 65 | # @param ldap_memberatr Attribute for MemberAttribute. Used with ldapfilter 66 | # @param ldap_tls_enable Enable TLS for the LDAP authentication 67 | # @param ldap_tls_ca_cert_file LDAP TLS authentication: path to the CA certificate. 68 | # @param ldap_tls_ca_cert_dir LDAP TLS authentication: path to the CA certificates. 69 | # @param ldap_tls_client_cert_file LDAP TLS authentication: path to the tls client certificate 70 | # @param ldap_tls_client_key_file LDAP TLS authentication: path to the tls client key 71 | # @param verb Level of logging verbosity 72 | # @param cipher Cipher to use for packet encryption 73 | # @param tls_cipher TLS Ciphers to use 74 | # @param persist_key Try to retain access to resources that may be unavailable because of privilege downgrades 75 | # @param persist_tun Try to retain access to resources that may be unavailable because of privilege downgrades 76 | # @param key_expire The number of days to certify the server certificate for 77 | # @param crl_days The number of days the client revocation list will be valid for after generating 78 | # @param digest Cryptographic digest to use 79 | # @param ca_expire The number of days to certify the CA certificate for 80 | # @param key_name Value for name_default variable in openssl.cnf and KEY_NAME in vars 81 | # @param key_ou Value for organizationalUnitName_default variable in openssl.cnf and KEY_OU in vars 82 | # @param key_cn Value for commonName_default variable in openssl.cnf and KEY_CN in vars 83 | # @param tls_auth Activates tls-auth to Add an additional layer of HMAC authentication on top of the TLS control channel to protect against DoS attacks. 84 | # @param tls_crypt Encrypt and authenticate all control channel packets with the key from keyfile. (See --tls-auth for more background.) 85 | # @param tls_server If proto not tcp it lets you choose if the parameter tls-server is set or not. 86 | # @param tls_client Allows you to set this server up as a tls-client connection. 87 | # @param server_poll_timeout Value for timeout before trying the next server. 88 | # @param ping_timer_rem Do not start clocking timeouts until a remote peer connects. 89 | # @param sndbuf Set the TCP/UDP socket send buffer size. 90 | # @param rcvbuf Set the TCP/UDP socket receive buffer size. 91 | # @param shared_ca Name of a openssl::ca resource to use config with 92 | # @param crl_verify Enable CRL checking. Disabling this is not recommended. 93 | # @param crl_auto_renew Enables automatic renewing of crl.pem. 94 | # @param crl_renew_schedule_period Sets the "period" Parameter of the schedule for renewing the CRL. Since changing the expiry of 30 days is not possible with easy-rsa2, twice a month should be good 95 | # @param crl_renew_schedule_repeat Sets the "repeat" Parameter of the schedule for renewing the CRL. Since changing the expiry of 30 days is not possible with easy-rsa2, twice a month should be good 96 | # @param extca_enabled Turn this on if you are using an external CA solution, like FreeIPA. Once enabled, you must configure the remaining extca_* parameters. 97 | # @param extca_ca_cert_file External CA: Path to the CA certificate. 98 | # @param extca_ca_crl_file External CA: Path to the CA's CRL file. For FreeIPA-based CAs, CRLs expire every four hours, which means you may need your own solution for maintaining a local copy of your CA's CRL. Otherwise, you can set crl_verify to false (not recommended). 99 | # @param extca_server_cert_file External CA: Path to the external CA issued OpenVPN server certificate. 100 | # @param extca_server_key_file External CA: Path to the key file that corresponds to $extca_server_cert_file 101 | # @param extca_dh_file External CA: Path to your Dillie-Hellman parameter file. You will need to create one yourself. Make sure key-size matches the public key size of your CA-issued server certificate. Like this: openssl dhparam -out /path/to/dh.pem 2048 Note: This is only required if you are enabling $tls_server. 102 | # @param extca_tls_auth_key_file External CA: If you are enabling $extca_enabled and $tls_auth, you will also need to create the tls-auth key file and specify its location here. The file can be created like this: openvpn --genkey --secret /path/to/ta.key. Note: you will need to distribute this file to your clients as well. 103 | # @param autostart Enable autostart for server if openvpn::autostart_all is false. 104 | # @param remote_cert_tls Enable or disable use of remote-cert-tls for the session. Generally used with client configuration 105 | # @param nobind Whether or not to bind to a specific port number.# 106 | # @param secret A pre-shared static key. 107 | # @param scripts Hash of scripts to copy with this instance. 108 | # For example, to put a script in `/etc/openvpn/test-site/scripts/add-tap-to-bridge.sh` and use it as an `up` script 109 | # ``` puppet 110 | # openvpn::server { 'test-site': 111 | # .... 112 | # up => 'add-tap-to-bridge.sh', 113 | # scripts => { 114 | # "add-tap-to-bridge.sh" => { 115 | # source => 'puppet:///path/to/add-tap-to-bridge.sh', 116 | # }, 117 | # }, 118 | # } 119 | # ``` 120 | # 121 | # @param custom_options Hash of additional options to append to the configuration file. 122 | # 123 | # @example install 124 | # openvpn::server { 'winterthur': 125 | # country => 'CH', 126 | # province => 'ZH', 127 | # city => 'Winterthur', 128 | # organization => 'example.org', 129 | # email => 'root@example.org', 130 | # server => '10.200.200.0 255.255.255.0', 131 | # } 132 | # 133 | # @example a server in client mode 134 | # file { 135 | # '/etc/openvpn/zurich/keys/ca.crt': 136 | # source => 'puppet:///path/to/ca.crt'; 137 | # '/etc/openvpn/zurich/keys/zurich.crt': 138 | # source => 'puppet:///path/to/zurich.crt'; 139 | # '/etc/openvpn/zurich/keys/zurich.key': 140 | # source => 'puppet:///path/to/zurich.key'; 141 | # } 142 | # openvpn::server { 'zurich': 143 | # remote => [ 'mgmtnet3.nine.ch 1197', 'mgmtnet2.nine.ch 1197' ], 144 | # require => [ File['/etc/openvpn/zurich/keys/ca.crt'], 145 | # File['/etc/openvpn/zurich/keys/zurich.crt'], 146 | # File['/etc/openvpn/zurich/keys/zurich.key'] ]; 147 | # } 148 | # 149 | define openvpn::server ( 150 | Enum['org','cn_only'] $dn_mode = 'org', 151 | Optional[String[1]] $country = undef, 152 | Optional[String[1]] $province = undef, 153 | Optional[String[1]] $city = undef, 154 | Optional[String[1]] $organization = undef, 155 | Optional[String[1]] $email = undef, 156 | Optional[Array] $remote = undef, 157 | Boolean $remote_random_hostname = false, 158 | Boolean $remote_random = false, 159 | String $common_name = 'server', 160 | Optional[String[1]] $compression = undef, 161 | String $dev = 'tun0', 162 | String $user = 'nobody', 163 | Optional[String] $group = undef, 164 | Boolean $ipp = false, 165 | Boolean $duplicate_cn = false, 166 | String $local = $facts['networking']['ip'], 167 | Variant[Boolean, String] $logfile = false, 168 | Boolean $manage_logfile_directory = false, 169 | String[1] $logdirectory_user = 'nobody', 170 | String[1] $logdirectory_group = 'nobody', 171 | String $port = '1194', 172 | Optional[String] $portshare = undef, 173 | Enum['tcp', 'tcp4', 'tcp6', 'udp', 'udp4', 'udp6'] $proto = 'tcp', 174 | Enum['1', '2', '3', ''] $status_version = '', 175 | String $status_log = "/var/log/openvpn/${name}-status.log", 176 | Optional[String[1]] $server = undef, 177 | Optional[String[1]] $server_ipv6 = undef, 178 | Optional[String[1]] $server_bridge = undef, 179 | Array $push = [], 180 | Array $route = [], 181 | Array $route_ipv6 = [], 182 | Optional[String[1]] $keepalive = undef, 183 | Variant[Boolean, Integer] $fragment = false, 184 | Enum['rsa', 'ec', 'ed'] $ssl_key_algo = 'rsa', 185 | Integer $ssl_key_size = 2048, 186 | String $ssl_key_curve = 'secp384r1', 187 | Optional[String[1]] $ecdh_curve = undef, 188 | String $topology = 'net30', 189 | Boolean $c2c = false, 190 | Boolean $tcp_nodelay = false, 191 | Boolean $ccd_exclusive = false, 192 | Boolean $pam = false, 193 | String $pam_module_arguments = 'login', 194 | Boolean $management = false, 195 | String $management_ip = 'localhost', 196 | Variant[Stdlib::Port::Unprivileged,Enum['unix']] $management_port = 7505, 197 | Optional[String[1]] $up = undef, 198 | Optional[String[1]] $down = undef, 199 | Optional[String[1]] $client_connect = undef, 200 | Optional[String[1]] $client_disconnect = undef, 201 | Boolean $username_as_common_name = false, 202 | Boolean $client_cert_not_required = false, 203 | Boolean $ldap_enabled = false, 204 | Optional[String[1]] $ldap_server = undef, 205 | Optional[String[1]] $ldap_binddn = undef, 206 | Optional[String[1]] $ldap_bindpass = undef, 207 | Optional[String[1]] $ldap_u_basedn = undef, 208 | Optional[String[1]] $ldap_g_basedn = undef, 209 | Boolean $ldap_gmember = false, 210 | Optional[String[1]] $ldap_u_filter = undef, 211 | Optional[String[1]] $ldap_g_filter = undef, 212 | Optional[String[1]] $ldap_memberatr = undef, 213 | Boolean $ldap_tls_enable = false, 214 | Optional[String[1]] $ldap_tls_ca_cert_file = undef, 215 | Optional[String[1]] $ldap_tls_ca_cert_dir = undef, 216 | Optional[Stdlib::Absolutepath] $ldap_tls_client_cert_file = undef, 217 | Optional[Stdlib::Absolutepath] $ldap_tls_client_key_file = undef, 218 | Integer $ca_expire = 3650, 219 | Integer $key_expire = 3650, 220 | Integer[1] $crl_days = 30, 221 | Enum['md5','sha1','sha256','sha224','sha384','sha512'] $digest = 'sha512', 222 | Optional[String] $key_cn = undef, 223 | Optional[String] $key_name = undef, 224 | Optional[String] $key_ou = undef, 225 | Optional[String] $verb = undef, 226 | String $cipher = 'AES-256-GCM', 227 | String $tls_cipher = 'TLS-DHE-RSA-WITH-AES-256-GCM-SHA384:TLS-DHE-RSA-WITH-AES-256-CBC-SHA256:TLS-DHE-RSA-WITH-AES-128-GCM-SHA256:TLS-DHE-RSA-WITH-AES-128-CBC-SHA256', 228 | Boolean $persist_key = false, 229 | Boolean $persist_tun = false, 230 | Boolean $tls_auth = false, 231 | Boolean $tls_crypt = false, 232 | Boolean $tls_server = false, 233 | Boolean $tls_client = false, 234 | Optional[Integer] $server_poll_timeout = undef, 235 | Boolean $ping_timer_rem = false, 236 | Optional[Integer] $sndbuf = undef, 237 | Optional[Integer] $rcvbuf = undef, 238 | Optional[String] $shared_ca = undef, 239 | Boolean $crl_verify = true, 240 | Boolean $crl_auto_renew = false, 241 | String $crl_renew_schedule_period = 'monthly', 242 | Integer $crl_renew_schedule_repeat = 2, 243 | Boolean $extca_enabled = false, 244 | Optional[String] $extca_ca_cert_file = undef, 245 | Optional[String] $extca_ca_crl_file = undef, 246 | Optional[String] $extca_server_cert_file = undef, 247 | Optional[String] $extca_server_key_file = undef, 248 | Optional[String] $extca_dh_file = undef, 249 | Optional[String] $extca_tls_auth_key_file = undef, 250 | Optional[Boolean] $autostart = undef, 251 | Boolean $remote_cert_tls = true, 252 | Boolean $nobind = false, 253 | Optional[String] $secret = undef, 254 | Hash[String, Hash] $scripts = {}, 255 | Hash $custom_options = {}, 256 | ) { 257 | include openvpn 258 | Class['openvpn::install'] 259 | -> Openvpn::Server[$name] 260 | 261 | if $facts['service_provider'] == 'systemd' and $openvpn::namespecific_rclink { 262 | fail("Using systemd and namespecific rclink's (BSD-style) is not allowed") 263 | } 264 | 265 | if $tls_auth and $tls_crypt { 266 | fail('tls_auth and tls_crypt are mutually exclusive') 267 | } 268 | 269 | if $openvpn::manage_service { 270 | if $facts['service_provider'] == 'systemd' { 271 | $lnotify = Service["${openvpn::server_service_name}@${name}"] 272 | } elsif $openvpn::namespecific_rclink { 273 | $lnotify = Service["openvpn_${name}"] 274 | } else { 275 | $lnotify = Service['openvpn'] 276 | Openvpn::Server[$name] -> Service['openvpn'] 277 | } 278 | } 279 | else { 280 | $lnotify = undef 281 | } 282 | 283 | if $manage_logfile_directory { 284 | $logdir = dirname($logfile) 285 | file { $logdir: 286 | ensure => 'directory', 287 | owner => $logdirectory_user, 288 | group => $logdirectory_group, 289 | } 290 | } 291 | 292 | # Selection block to enable or disable tls-server flag 293 | # Check if we want to run as a client or not 294 | if !$tls_client { 295 | if $tls_server and !$extca_enabled { 296 | $real_tls_server = $tls_server 297 | } elsif ($extca_enabled and $extca_dh_file) or (!$extca_enabled) { 298 | $real_tls_server = $proto ? { 299 | /tcp/ => true, 300 | default => false 301 | } 302 | } else { 303 | $real_tls_server = false 304 | } 305 | } 306 | 307 | $pam_module_path = $openvpn::pam_module_path 308 | $etc_directory = $openvpn::etc_directory 309 | $server_directory = $openvpn::server_directory 310 | 311 | $group_to_set = $group ? { 312 | undef => $openvpn::group, 313 | default => $group 314 | } 315 | 316 | if $shared_ca { 317 | $ca_name = $shared_ca 318 | } elsif !$extca_enabled { 319 | $ca_name = $name 320 | } 321 | 322 | File { 323 | group => $group_to_set, 324 | selinux_ignore_defaults => true, 325 | } 326 | 327 | file { "${server_directory}/${name}": 328 | ensure => directory, 329 | mode => '0750', 330 | notify => $lnotify, 331 | } 332 | file { 333 | ["${server_directory}/${name}/scripts",]: 334 | ensure => directory, 335 | mode => '0750', 336 | recurse => true, 337 | } 338 | if $shared_ca { 339 | ensure_resource(file, "${server_directory}/${ca_name}", { 340 | ensure => directory, 341 | mode => '0750', 342 | }) 343 | } 344 | 345 | if $extca_enabled { 346 | # VPN Server or Client with external CA 347 | if $extca_ca_cert_file == undef { fail('extca_ca_cert_file has to be specified in extca mode') } 348 | if $extca_ca_crl_file == undef and $crl_verify and !$remote { fail('extca_ca_crl_file has to be specified in extca mode if crl_verify is enabled') } 349 | if $extca_server_cert_file == undef { fail('extca_server_cert_file has to be specified in extca mode') } 350 | if $extca_server_key_file == undef { fail('extca_server_key_file has to be specified in extca mode') } 351 | if $extca_dh_file == undef and !$remote and $tls_server { fail('cant enable tls_server: missing extca_dh_file') } 352 | if $extca_tls_auth_key_file == undef and !$remote and $tls_auth { fail('cant enable tls_auth: missing extca_tls_auth_key_file') } 353 | } 354 | 355 | if !$remote { 356 | if !$shared_ca and !$extca_enabled { 357 | if $dn_mode == 'org' or $openvpn::easyrsa_version == '2.0' { 358 | # VPN Server Mode 359 | if $country == undef { 360 | fail('country has to be specified in server mode') 361 | } 362 | if $province == undef { 363 | fail('province has to be specified in server mode') 364 | } 365 | if $city == undef { fail('city has to be specified in server mode') } 366 | if $organization == undef { 367 | fail('organization has to be specified in server mode') 368 | } 369 | if $email == undef { fail('email has to be specified in server mode') } 370 | } 371 | 372 | $ca_common_name = $common_name 373 | openvpn::ca { $name: 374 | dn_mode => $dn_mode, 375 | country => $country, 376 | province => $province, 377 | city => $city, 378 | organization => $organization, 379 | email => $email, 380 | common_name => $common_name, 381 | group => $group, 382 | ssl_key_algo => $ssl_key_algo, 383 | ssl_key_size => $ssl_key_size, 384 | ssl_key_curve => $ssl_key_curve, 385 | ca_expire => $ca_expire, 386 | key_expire => $key_expire, 387 | crl_days => $crl_days, 388 | digest => $digest, 389 | key_cn => $key_cn, 390 | key_name => $key_name, 391 | key_ou => $key_ou, 392 | tls_static_key => $tls_auth or $tls_crypt, 393 | } 394 | 395 | ## Renewal of crl.pem 396 | if ($crl_auto_renew) { 397 | schedule { "renew crl.pem schedule on ${name}": 398 | range => '1 - 4', 399 | period => $crl_renew_schedule_period, 400 | repeat => $crl_renew_schedule_repeat, 401 | } 402 | case $openvpn::easyrsa_version { 403 | '2.0': { 404 | exec { "renew crl.pem on ${name}": 405 | command => ". ./vars && KEY_CN='' KEY_OU='' KEY_NAME='' KEY_ALTNAMES='' openssl ca -gencrl -out ${server_directory}/${name}/crl.pem -config ${server_directory}/${name}/easy-rsa/openssl.cnf", 406 | cwd => "${server_directory}/${name}/easy-rsa", 407 | provider => 'shell', 408 | schedule => "renew crl.pem schedule on ${name}", 409 | } 410 | } 411 | '3.0': { 412 | exec { "renew crl.pem on ${name}": 413 | command => "./easyrsa gen-crl && cp ./keys/crl.pem ${server_directory}/${name}/crl.pem", 414 | cwd => "${server_directory}/${name}/easy-rsa", 415 | provider => 'shell', 416 | schedule => "renew crl.pem schedule on ${name}", 417 | } 418 | ~> exec { "copy renewed crl.pem to ${name} keys directory": 419 | command => "cp ${server_directory}/${name}/easy-rsa/keys/crl.pem ${server_directory}/${name}/crl.pem", 420 | refreshonly => true, 421 | provider => 'shell', 422 | } 423 | } 424 | default: { 425 | fail("unexepected value for EasyRSA version, got '${openvpn::easyrsa_version}', expect 2.0 or 3.0.") 426 | } 427 | } 428 | } 429 | } elsif !$extca_enabled { 430 | if !defined(Openvpn::Ca[$shared_ca]) { 431 | fail("Openvpn::ca[${name}] is not defined for shared_ca") 432 | } 433 | $ca_common_name = getparam(Openvpn::Ca[$shared_ca], 'common_name') 434 | } else { 435 | $ca_common_name = undef 436 | } 437 | 438 | file { 439 | [ 440 | "${server_directory}/${name}/auth", 441 | "${server_directory}/${name}/client-configs", 442 | "${server_directory}/${name}/download-configs", 443 | ]: 444 | ensure => directory, 445 | mode => '0750', 446 | recurse => true, 447 | } 448 | } else { 449 | # VPN Client Mode 450 | $ca_common_name = $name 451 | 452 | file { "${server_directory}/${name}/keys": 453 | ensure => directory, 454 | mode => '0750', 455 | recurse => true, 456 | } 457 | } 458 | 459 | if $facts['os']['family'] == 'Debian' and !$openvpn::autostart_all and $autostart { 460 | concat::fragment { "openvpn.default.autostart.${name}": 461 | content => "AUTOSTART=\"\$AUTOSTART ${name}\"\n", 462 | target => '/etc/default/openvpn', 463 | order => '10', 464 | } 465 | } 466 | 467 | # template use $_easyrsa_version 468 | $_easyrsa_version = $openvpn::easyrsa_version 469 | 470 | # Template might need script directory 471 | $_script_dir = "${server_directory}/${name}/scripts" 472 | 473 | if $facts['os']['family'] == 'Archlinux' { 474 | $set_user_group = false 475 | } else { 476 | $set_user_group = true 477 | } 478 | 479 | file { "${server_directory}/${name}.conf": 480 | owner => root, 481 | group => 0, 482 | mode => '0440', 483 | content => template('openvpn/server.erb'), 484 | notify => $lnotify, 485 | } 486 | 487 | $ensure = $secret ? { 488 | undef => absent, 489 | default => present, 490 | } 491 | file { "${server_directory}/${name}/keys/pre-shared.secret": 492 | ensure => $ensure, 493 | owner => root, 494 | group => root, 495 | mode => '0440', 496 | content => $secret, 497 | notify => $lnotify, 498 | } 499 | 500 | $scripts.each |String $scriptname, Hash $properties| { 501 | file { "${_script_dir}/${scriptname}": 502 | * => $properties, 503 | } 504 | } 505 | 506 | if $ldap_enabled == true { 507 | file { 508 | "${server_directory}/${name}/auth/ldap.conf": 509 | ensure => file, 510 | owner => root, 511 | mode => '0400', 512 | content => template('openvpn/ldap.erb'), 513 | require => Package['openvpn-auth-ldap'], 514 | } 515 | } 516 | 517 | if $facts['service_provider'] == 'systemd' { 518 | if $openvpn::manage_service { 519 | service { "${openvpn::server_service_name}@${name}": 520 | ensure => running, 521 | enable => true, 522 | provider => 'systemd', 523 | require => File["${server_directory}/${name}.conf"], 524 | } 525 | if !$extca_enabled and !$remote { 526 | Openvpn::Ca[$ca_name] -> Service["${openvpn::server_service_name}@${name}"] 527 | } 528 | } 529 | } 530 | 531 | if $openvpn::namespecific_rclink { 532 | file { "/usr/local/etc/rc.d/openvpn_${name}": 533 | ensure => link, 534 | target => "${etc_directory}/rc.d/openvpn", 535 | } 536 | 537 | file { "/etc/rc.conf.d/openvpn_${name}": 538 | owner => root, 539 | group => 0, 540 | mode => '0644', 541 | content => template('openvpn/etc-rc.d-openvpn.erb'), 542 | } 543 | 544 | if $openvpn::manage_service { 545 | service { "openvpn_${name}": 546 | ensure => running, 547 | enable => true, 548 | require => [ 549 | File["${server_directory}/${name}.conf"], 550 | File["/usr/local/etc/rc.d/openvpn_${name}"], 551 | ], 552 | } 553 | if !extca_enabled and !$remote { 554 | Openvpn::Ca[$ca_name] -> Service["openvpn_${name}"] 555 | } 556 | } 557 | } 558 | } 559 | -------------------------------------------------------------------------------- /manifests/service.pp: -------------------------------------------------------------------------------- 1 | # 2 | # @summary This class maintains the openvpn service. 3 | # 4 | class openvpn::service { 5 | if $openvpn::manage_service and !$openvpn::namespecific_rclink { 6 | service { 'openvpn': 7 | ensure => running, 8 | enable => true, 9 | hasrestart => true, 10 | hasstatus => true, 11 | } 12 | } 13 | } 14 | -------------------------------------------------------------------------------- /metadata.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "puppet-openvpn", 3 | "version": "11.0.1-rc0", 4 | "author": "Vox Pupuli", 5 | "summary": "OpenVPN server puppet module", 6 | "license": "Apache-2.0", 7 | "source": "https://github.com/voxpupuli/puppet-openvpn", 8 | "project_page": "https://github.com/voxpupuli/puppet-openvpn", 9 | "issues_url": "https://github.com/voxpupuli/puppet-openvpn/issues", 10 | "description": "Puppet module to manage OpenVPN servers", 11 | "operatingsystem_support": [ 12 | { 13 | "operatingsystem": "Ubuntu", 14 | "operatingsystemrelease": [ 15 | "22.04", 16 | "24.04" 17 | ] 18 | }, 19 | { 20 | "operatingsystem": "Debian", 21 | "operatingsystemrelease": [ 22 | "11", 23 | "12" 24 | ] 25 | }, 26 | { 27 | "operatingsystem": "RedHat", 28 | "operatingsystemrelease": [ 29 | "8", 30 | "9" 31 | ] 32 | }, 33 | { 34 | "operatingsystem": "CentOS", 35 | "operatingsystemrelease": [ 36 | "9" 37 | ] 38 | }, 39 | { 40 | "operatingsystem": "AlmaLinux", 41 | "operatingsystemrelease": [ 42 | "8", 43 | "9" 44 | ] 45 | }, 46 | { 47 | "operatingsystem": "Rocky", 48 | "operatingsystemrelease": [ 49 | "8", 50 | "9" 51 | ] 52 | }, 53 | { 54 | "operatingsystem": "OracleLinux", 55 | "operatingsystemrelease": [ 56 | "8", 57 | "9" 58 | ] 59 | }, 60 | { 61 | "operatingsystem": "Archlinux" 62 | }, 63 | { 64 | "operatingsystem": "FreeBSD", 65 | "operatingsystemrelease": [ 66 | "13", 67 | "14" 68 | ] 69 | }, 70 | { 71 | "operatingsystem": "Solaris" 72 | } 73 | ], 74 | "requirements": [ 75 | { 76 | "name": "puppet", 77 | "version_requirement": ">= 7.0.0 < 9.0.0" 78 | }, 79 | { 80 | "name": "openvox", 81 | "version_requirement": ">= 7.0.0 < 9.0.0" 82 | } 83 | ], 84 | "dependencies": [ 85 | { 86 | "name": "puppetlabs/concat", 87 | "version_requirement": ">= 4.1.0 < 10.0.0" 88 | }, 89 | { 90 | "name": "puppetlabs/stdlib", 91 | "version_requirement": ">= 4.25.0 < 10.0.0" 92 | } 93 | ], 94 | "tags": [ 95 | "vpn", 96 | "openvpn" 97 | ] 98 | } 99 | -------------------------------------------------------------------------------- /spec/acceptance/openvpn_spec.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | 3 | require 'spec_helper_acceptance' 4 | 5 | describe 'openvpn', order: :defined do 6 | describe 'openvpn::server', order: :defined do 7 | describe 'with minimal parameters' do 8 | it_behaves_like 'an idempotent resource', 'master' do 9 | let(:manifest) do 10 | <<-PUPPET 11 | openvpn::server { 'test_openvpn_server': 12 | country => 'CO', 13 | province => 'ST', 14 | city => 'A city', 15 | organization => 'FOO', 16 | email => 'bar@foo.org', 17 | server => '10.0.0.0 255.255.255.0', 18 | } 19 | PUPPET 20 | end 21 | end 22 | 23 | ['/etc/openvpn/server/test_openvpn_server', 24 | '/etc/openvpn/server/test_openvpn_server/keys'].each do |dir| 25 | describe file(dir) do 26 | it { is_expected.to be_directory } 27 | end 28 | end 29 | 30 | describe file('/etc/openvpn/server/test_openvpn_server.conf') do 31 | it { is_expected.to be_file } 32 | end 33 | 34 | describe service('openvpn-server@test_openvpn_server') do 35 | it { is_expected.to be_enabled } 36 | it { is_expected.to be_running } 37 | end 38 | 39 | describe port(1194) do 40 | it { is_expected.to be_listening } 41 | end 42 | 43 | describe file('/etc/openvpn/server/test_openvpn_server/easy-rsa/vars') do 44 | it { is_expected.to be_file } 45 | its(:content) { is_expected.to contain(%r{EASYRSA_REQ_COUNTRY "CO"}) } 46 | its(:content) { is_expected.to contain(%r{EASYRSA_REQ_PROVINCE "ST"}) } 47 | its(:content) { is_expected.to contain(%r{EASYRSA_REQ_CITY "A city"}) } 48 | its(:content) { is_expected.to contain(%r{EASYRSA_REQ_ORG "FOO"}) } 49 | end 50 | end 51 | end 52 | 53 | describe 'openvpn::client', order: :defined do 54 | it_behaves_like 'an idempotent resource', 'master' do 55 | let(:manifest) do 56 | <<-PUPPET 57 | openvpn::server { 'test_openvpn_server': 58 | country => 'CO', 59 | province => 'ST', 60 | city => 'A city', 61 | organization => 'FOO', 62 | email => 'bar@foo.org', 63 | server => '10.0.0.0 255.255.255.0', 64 | } 65 | openvpn::client { ['vpnclienta','vpnclientb'] : 66 | server => 'test_openvpn_server', 67 | require => Openvpn::Server['test_openvpn_server'], 68 | } 69 | PUPPET 70 | end 71 | end 72 | 73 | ['/etc/openvpn/server/test_openvpn_server/download-configs/vpnclienta.ovpn', 74 | '/etc/openvpn/server/test_openvpn_server/download-configs/vpnclientb.ovpn', 75 | '/etc/openvpn/server/test_openvpn_server/keys/private/vpnclienta.key', 76 | '/etc/openvpn/server/test_openvpn_server/keys/private/vpnclientb.key', 77 | '/etc/openvpn/server/test_openvpn_server/keys/issued/vpnclienta.crt', 78 | '/etc/openvpn/server/test_openvpn_server/keys/issued/vpnclientb.crt'].each do |path| 79 | describe file(path) do 80 | it { is_expected.to be_file } 81 | end 82 | end 83 | end 84 | 85 | describe 'openvpn::revoke', order: :defined do 86 | it 'revoke a client certificate' do 87 | pp = <<-PUPPET 88 | openvpn::server { 'test_openvpn_server': 89 | country => 'CO', 90 | province => 'ST', 91 | city => 'A city', 92 | organization => 'FOO', 93 | email => 'bar@foo.org', 94 | server => '10.0.0.0 255.255.255.0', 95 | } 96 | openvpn::client { ['vpnclienta','vpnclientb'] : 97 | server => 'test_openvpn_server', 98 | require => Openvpn::Server['test_openvpn_server'], 99 | } 100 | openvpn::revoke { 'vpnclientb': 101 | server => 'test_openvpn_server', 102 | } 103 | PUPPET 104 | # Apply the manifest to revoke the client certificate 105 | apply_manifest_on(hosts_as('master'), pp, catch_failures: true) 106 | end 107 | 108 | describe file('/etc/openvpn/server/test_openvpn_server/easy-rsa/revoked/vpnclientb') do 109 | it { is_expected.to be_file } 110 | end 111 | end 112 | 113 | describe 'remote client', order: :defined do 114 | it 'connects to vpnserver' do 115 | scp_from(hosts_as('master'), '/etc/openvpn/server/test_openvpn_server/download-configs/vpnclienta.tar.gz', '.') 116 | scp_to(hosts_as('agent'), 'vpnclienta.tar.gz', '/tmp') 117 | on(hosts_as('agent'), 'tar xvfz /tmp/vpnclienta.tar.gz -C /etc/openvpn/client') 118 | on(hosts_as('agent'), 'cp -a /etc/openvpn/client/vpnclienta/* /etc/openvpn/client/') 119 | on(hosts_as('agent'), 'chown openvpn:network -R /etc/openvpn/client/keys') if default[:platform].start_with?('archlinux') 120 | on(hosts_as('agent'), 'systemctl enable openvpn-client@vpnclienta') 121 | on(hosts_as('agent'), 'systemctl restart openvpn-client@vpnclienta') 122 | end 123 | end 124 | end 125 | -------------------------------------------------------------------------------- /spec/classes/openvpn_config_spec.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | 3 | require 'spec_helper' 4 | 5 | describe 'openvpn::config' do 6 | on_supported_os.each do |os, os_facts| 7 | context "on #{os}" do 8 | let(:facts) do 9 | os_facts.merge( 10 | easyrsa: '3.0' 11 | ) 12 | end 13 | 14 | let(:pre_condition) { 'include openvpn' } if os_facts[:os]['family'] == 'Debian' 15 | 16 | it { is_expected.to compile.with_all_deps } 17 | 18 | case os_facts[:os]['family'] 19 | when 'Debian' 20 | it { is_expected.to contain_concat('/etc/default/openvpn') } 21 | 22 | it { is_expected.to contain_concat__fragment('openvpn.default.header') } 23 | 24 | context 'enabled autostart_all' do 25 | let(:pre_condition) { 'class { "openvpn": autostart_all => true }' } 26 | 27 | it { is_expected.to contain_concat__fragment('openvpn.default.header').with_content(%r{^AUTOSTART="all"}) } 28 | end 29 | 30 | context 'disabled autostart_all' do 31 | let(:pre_condition) { 'class { "openvpn": autostart_all => false }' } 32 | 33 | it { is_expected.to contain_concat__fragment('openvpn.default.header').with_content(%r{^AUTOSTART=""}) } 34 | end 35 | end 36 | end 37 | end 38 | end 39 | -------------------------------------------------------------------------------- /spec/classes/openvpn_init_spec.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | 3 | require 'spec_helper' 4 | 5 | describe 'openvpn' do 6 | on_supported_os.each do |os, os_facts| 7 | context "on #{os}" do 8 | let(:facts) do 9 | os_facts.merge( 10 | easyrsa: '3.0' 11 | ) 12 | end 13 | 14 | it { is_expected.to compile.with_all_deps } 15 | 16 | it { is_expected.to create_class('openvpn') } 17 | it { is_expected.to contain_class('openvpn::install') } 18 | it { is_expected.to contain_class('openvpn::config') } 19 | 20 | if os_facts[:service_provider] == 'systemd' 21 | context 'system with systemd' do 22 | it { is_expected.to create_class('openvpn') } 23 | it { is_expected.not_to contain_class('openvpn::service') } 24 | end 25 | else 26 | context 'system without systemd' do 27 | it { is_expected.to create_class('openvpn') } 28 | it { is_expected.to contain_class('openvpn::service') } 29 | end 30 | end 31 | end 32 | end 33 | end 34 | -------------------------------------------------------------------------------- /spec/classes/openvpn_install_spec.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | 3 | require 'spec_helper' 4 | 5 | describe 'openvpn::install' do 6 | on_supported_os.each do |os, os_facts| 7 | context "on #{os}" do 8 | let(:facts) do 9 | os_facts.merge( 10 | easyrsa: '3.0' 11 | ) 12 | end 13 | let(:pre_condition) { 'include openvpn' } 14 | 15 | etc_directory = case os_facts[:os]['family'] 16 | when 'Solaris' 17 | '/opt/local/etc' 18 | when 'FreeBSD' 19 | '/usr/local/etc' 20 | else 21 | '/etc' 22 | end 23 | 24 | it { is_expected.to compile.with_all_deps } 25 | 26 | it { is_expected.to create_class('openvpn::install') } 27 | 28 | it { is_expected.to contain_package('openvpn') } 29 | 30 | it { is_expected.to contain_file("#{etc_directory}/openvpn").with_ensure('directory') } 31 | 32 | it { is_expected.to contain_file("#{etc_directory}/openvpn/keys").with_ensure('directory') } 33 | 34 | it { is_expected.to contain_file('/var/log/openvpn').with_ensure('directory') } 35 | 36 | it { is_expected.to contain_package('easy-rsa') } 37 | 38 | if os_facts[:os]['family'] == 'Debian' 39 | it { is_expected.to contain_package('openvpn-auth-ldap') } 40 | else 41 | it { is_expected.not_to contain_package('openvpn-auth-ldap') } 42 | end 43 | end 44 | end 45 | end 46 | -------------------------------------------------------------------------------- /spec/classes/openvpn_service_spec.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | 3 | require 'spec_helper' 4 | 5 | describe 'openvpn::service' do 6 | on_supported_os.each do |os, os_facts| 7 | context "on #{os}" do 8 | let(:facts) do 9 | os_facts.merge( 10 | easyrsa: '3.0' 11 | ) 12 | end 13 | let(:pre_condition) { 'include openvpn' } 14 | 15 | it { is_expected.to compile.with_all_deps } 16 | 17 | context 'enabled manage_service and disabled namespecific_rclink' do 18 | let(:pre_condition) do 19 | 'class { "openvpn": 20 | manage_service => true, 21 | namespecific_rclink => false 22 | }' 23 | end 24 | 25 | it { is_expected.to create_class('openvpn::service') } 26 | 27 | it { is_expected.to contain_service('openvpn').with_ensure('running').with_enable(true) } 28 | end 29 | 30 | context 'disabled manage_service and disabled namespecific_rclink' do 31 | let(:pre_condition) do 32 | 'class { "openvpn": 33 | manage_service => false, 34 | namespecific_rclink => false 35 | }' 36 | end 37 | 38 | it { is_expected.to create_class('openvpn::service') } 39 | 40 | it { is_expected.not_to contain_service('openvpn') } 41 | end 42 | 43 | context 'disabled manage_service and enabled namespecific_rclink' do 44 | let(:pre_condition) do 45 | 'class { "openvpn": 46 | manage_service => false, 47 | namespecific_rclink => true 48 | }' 49 | end 50 | 51 | it { is_expected.to create_class('openvpn::service') } 52 | 53 | it { is_expected.not_to contain_service('openvpn') } 54 | end 55 | end 56 | end 57 | end 58 | -------------------------------------------------------------------------------- /spec/defines/openvpn_ca_spec.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | 3 | require 'spec_helper' 4 | 5 | describe 'openvpn::ca' do 6 | on_supported_os.each do |os, os_facts| 7 | context "on #{os}" do 8 | let(:facts) do 9 | os_facts.merge( 10 | easyrsa: '3.0' 11 | ) 12 | end 13 | let(:title) { 'test_server' } 14 | 15 | server_directory = case os_facts[:os]['family'] 16 | when 'Archlinux', 'Debian', 'RedHat' 17 | '/etc/openvpn/server' 18 | when 'Solaris' 19 | '/opt/local/etc/openvpn' 20 | when 'FreeBSD' 21 | '/usr/local/etc/openvpn' 22 | else 23 | '/etc/openvpn' 24 | end 25 | 26 | context 'with default parameters' do 27 | let(:params) do 28 | { 29 | 'country' => 'CO', 30 | 'province' => 'ST', 31 | 'city' => 'Some City', 32 | 'organization' => 'example.org', 33 | 'email' => 'admin@example.org' 34 | } 35 | end 36 | 37 | it { is_expected.to contain_class('openvpn') } 38 | 39 | it { is_expected.to contain_file("#{server_directory}/test_server").with_ensure('directory') } 40 | 41 | it { is_expected.to contain_file("#{server_directory}/test_server/easy-rsa").with_ensure('directory') } 42 | 43 | it { is_expected.to contain_file("#{server_directory}/test_server/easy-rsa/revoked").with_ensure('directory') } 44 | 45 | it { is_expected.to contain_file("#{server_directory}/test_server/easy-rsa/easyrsa").with_ensure('link') } if os_facts[:os]['family'] == 'Archlinux' 46 | 47 | it { is_expected.to contain_file("#{server_directory}/test_server/easy-rsa/vars").with_mode('0550') } 48 | 49 | it { 50 | is_expected.to contain_file("#{server_directory}/test_server/keys"). 51 | with(ensure: 'link', target: "#{server_directory}/test_server/easy-rsa/keys") 52 | } 53 | 54 | it { is_expected.to contain_file("#{server_directory}/test_server/easy-rsa/openssl.cnf") } 55 | 56 | it { is_expected.to contain_file("#{server_directory}/test_server/crl.pem").with_mode('0640') } 57 | 58 | it { is_expected.to contain_file("#{server_directory}/test_server/crl.pem").with_group('nobody') } if os_facts[:os]['family'] == %r{'RedHat'|'Solaris'|'FreeBSD'} 59 | 60 | it { is_expected.to contain_file("#{server_directory}/test_server/crl.pem").with_group('nogroup') } if os_facts[:os]['family'] == 'Debian' 61 | 62 | it { is_expected.to contain_file("#{server_directory}/test_server/crl.pem").with_group('network') } if os_facts[:os]['family'] == 'Archlinux' 63 | 64 | it { is_expected.to contain_exec('initca test_server').with_command("./easyrsa --batch --pki-dir=#{server_directory}/test_server/easy-rsa/keys init-pki && ./easyrsa --batch build-ca nopass") } 65 | 66 | it { is_expected.to contain_exec('generate dh param test_server').with_command('./easyrsa --batch gen-dh') } 67 | it { is_expected.to contain_exec('generate server cert test_server').with_command("./easyrsa build-server-full 'server' nopass") } 68 | it { is_expected.to contain_exec('create crl.pem on test_server').with_command('./easyrsa gen-crl') } 69 | it { is_expected.to contain_exec('copy created crl.pem to test_server keys directory').with_command("cp #{server_directory}/test_server/easy-rsa/keys/crl.pem #{server_directory}/test_server/crl.pem") } 70 | 71 | it { 72 | is_expected.to contain_file("#{server_directory}/test_server/easy-rsa/vars"). 73 | with_content(%r{set_var EASYRSA_REQ_COUNTRY "CO"$}). 74 | with_content(%r{set_var EASYRSA_REQ_PROVINCE "ST"$}). 75 | with_content(%r{set_var EASYRSA_REQ_CITY "Some City"$}). 76 | with_content(%r{set_var EASYRSA_REQ_ORG "example.org"$}). 77 | with_content(%r{set_var EASYRSA_REQ_EMAIL "admin@example.org"$}) 78 | } 79 | end 80 | 81 | context 'with all parameters' do 82 | let(:params) do 83 | { 84 | 'dn_mode' => 'cn_only', 85 | 'country' => 'CO', 86 | 'province' => 'ST', 87 | 'city' => 'Some City', 88 | 'organization' => 'example.org', 89 | 'email' => 'testemail@example.org', 90 | 'group' => 'someone', 91 | 'ssl_key_size' => 2048, 92 | 'common_name' => 'mylittlepony', 93 | 'ca_expire' => 365, 94 | 'digest' => 'sha256', 95 | 'key_expire' => 365, 96 | 'key_cn' => 'yolo', 97 | 'key_name' => 'burp', 98 | 'key_ou' => 'NSA' 99 | } 100 | end 101 | 102 | it { 103 | is_expected.to contain_file("#{server_directory}/test_server/easy-rsa/vars"). 104 | with_content(%r{set_var EASYRSA_DN "cn_only"$}). 105 | with_content(%r{set_var EASYRSA_CA_EXPIRE 365$}). 106 | with_content(%r{set_var EASYRSA_CERT_EXPIRE 365$}). 107 | with_content(%r{set_var EASYRSA_REQ_CN "yolo"$}). 108 | with_content(%r{set_var EASYRSA_REQ_OU "NSA"$}). 109 | with_content(%r{set_var EASYRSA_DIGEST sha256$}). 110 | with_content(%r{set_var EASYRSA_KEY_SIZE 2048$}) 111 | } 112 | end 113 | end 114 | end 115 | end 116 | -------------------------------------------------------------------------------- /spec/defines/openvpn_client_spec.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | 3 | require 'spec_helper' 4 | 5 | describe 'openvpn::client' do 6 | on_supported_os.each do |os, os_facts| 7 | context "on #{os}" do 8 | let(:facts) do 9 | os_facts.merge( 10 | easyrsa: '3.0' 11 | ) 12 | end 13 | let(:pre_condition) do 14 | 'openvpn::server { "test_server": 15 | country => "CO", 16 | province => "ST", 17 | city => "Some City", 18 | organization => "example.org", 19 | email => "testemail@example.org" 20 | }' 21 | end 22 | let(:title) { 'test_client' } 23 | 24 | server_directory = case os_facts[:os]['family'] 25 | when 'Archlinux', 'Debian', 'RedHat' 26 | '/etc/openvpn/server' 27 | when 'Solaris' 28 | '/opt/local/etc/openvpn' 29 | when 'FreeBSD' 30 | '/usr/local/etc/openvpn' 31 | else 32 | '/etc/openvpn' 33 | end 34 | context 'with default parameters' do 35 | let(:params) { { server: 'test_server' } } 36 | 37 | it { is_expected.to compile.with_all_deps } 38 | 39 | it { is_expected.to contain_class('openvpn') } 40 | 41 | it { is_expected.to contain_exec('generate certificate for test_client in context of test_server') } 42 | 43 | ['test_client', 'test_client/keys/test_client'].each do |directory| 44 | it { is_expected.to contain_file("#{server_directory}/test_server/download-configs/#{directory}") } 45 | end 46 | it { 47 | is_expected.to contain_file("#{server_directory}/test_server/download-configs/test_client/test_client.conf"). 48 | with_content(%r{^client$}). 49 | with_content(%r{^dev\s+tun$}). 50 | with_content(%r{^proto\s+tcp$}). 51 | with_content(%r{^remote\s+.+\s+1194$}). 52 | with_content(%r{^nobind$}). 53 | with_content(%r{^persist-key$}). 54 | with_content(%r{^persist-tun$}). 55 | with_content(%r{^cipher\s+AES-256-GCM$}). 56 | with_content(%r{^tls-cipher\s+TLS-DHE-RSA-WITH-AES-256-GCM-SHA384:TLS-DHE-RSA-WITH-AES-256-CBC-SHA256:TLS-DHE-RSA-WITH-AES-128-GCM-SHA256:TLS-DHE-RSA-WITH-AES-128-CBC-SHA256$}). 57 | with_content(%r{^mute-replay-warnings$}). 58 | with_content(%r{^remote-cert-tls\s+server$}). 59 | with_content(%r{^verb\s+3$}). 60 | with_content(%r{^mute\s+20$}). 61 | with_content(%r{^ca\s+keys/test_client/ca\.crt$}). 62 | with_content(%r{^cert\s+keys/test_client/test_client.crt$}). 63 | with_content(%r{^key\s+keys/test_client/test_client\.key$}). 64 | without_content(%r{^pull$}). 65 | without_content(%r{^sndbuf}). 66 | without_content(%r{^rcvbuf}). 67 | without_content(%r{^auth-user-pass}). 68 | without_content(%r{^setnev}). 69 | without_content(%r{^setnev-safe}). 70 | without_content(%r{^script-security\s+2$}). 71 | without_content(%r{^up}). 72 | without_content(%r{^down}). 73 | without_content(%r{^x509-verify-name}) 74 | } 75 | 76 | it { 77 | is_expected.to contain_file("#{server_directory}/test_server/download-configs/test_client/keys/test_client/test_client.crt").with( 78 | 'ensure' => 'link', 79 | 'target' => "#{server_directory}/test_server/easy-rsa/keys/issued/test_client.crt" 80 | ) 81 | } 82 | 83 | it { 84 | is_expected.to contain_file("#{server_directory}/test_server/download-configs/test_client/keys/test_client/test_client.key").with( 85 | 'ensure' => 'link', 86 | 'target' => "#{server_directory}/test_server/easy-rsa/keys/private/test_client.key" 87 | ) 88 | } 89 | 90 | it { 91 | is_expected.to contain_file("#{server_directory}/test_server/download-configs/test_client/keys/test_client/ca.crt").with( 92 | 'ensure' => 'link', 93 | 'target' => "#{server_directory}/test_server/easy-rsa/keys/ca.crt" 94 | ) 95 | } 96 | end 97 | 98 | context 'with remote_host' do 99 | let(:params) do 100 | { 101 | 'server' => 'test_server', 102 | 'remote_host' => 'foo.example.com' 103 | } 104 | end 105 | 106 | it { 107 | is_expected.to contain_file("#{server_directory}/test_server/download-configs/test_client/test_client.conf"). 108 | with_content(%r{^client$}). 109 | with_content(%r{^dev\s+tun$}). 110 | with_content(%r{^proto\s+tcp$}). 111 | with_content(%r{^remote\s+foo.example.com\s+1194$}) 112 | } 113 | 114 | it { 115 | is_expected.not_to contain_file("#{server_directory}/test_server/download-configs/test_client/test_client.conf"). 116 | with_content(%r{^tls-client$}). 117 | with_content(%r{^verify-x509-name}). 118 | with_content(%r{^sndbuf}). 119 | with_content(%r{^rcvbuf}). 120 | with_content(%r{^pull}) 121 | } 122 | end 123 | 124 | context 'with tls_crypt true' do 125 | let(:params) { { 'server' => 'test_server', 'tls_crypt' => true } } 126 | 127 | it { 128 | is_expected.to contain_file("#{server_directory}/test_server/download-configs/test_client/test_client.conf"). 129 | with_content(%r{^tls-crypt\s+keys/test_client/ta\.key$}) 130 | } 131 | end 132 | 133 | context 'with tls_auth true' do 134 | let(:params) { { 'server' => 'test_server', 'tls_auth' => true } } 135 | 136 | it { 137 | is_expected.to contain_file("#{server_directory}/test_server/download-configs/test_client/test_client.conf"). 138 | with_content(%r{^tls-client$}). 139 | with_content(%r{^tls-auth\s+keys/test_client/ta\.key\s+1$}) 140 | } 141 | end 142 | 143 | context 'with tls_auth and tls_crypt true' do 144 | let(:params) { { 'server' => 'test_server', 'tls_auth' => true, 'tls_crypt' => true } } 145 | 146 | it { is_expected.to compile.and_raise_error(%r{tls_auth and tls_crypt are mutually exclusive}) } 147 | end 148 | 149 | context 'with authuserpass true' do 150 | let(:params) { { 'server' => 'test_server', 'authuserpass' => true } } 151 | 152 | it { 153 | is_expected.to contain_file("#{server_directory}/test_server/download-configs/test_client/test_client.conf"). 154 | with_content(%r{^auth-user-pass$}) 155 | } 156 | end 157 | 158 | context 'with pam true' do 159 | let(:params) { { 'server' => 'test_server', 'pam' => true } } 160 | 161 | it { 162 | is_expected.to contain_file("#{server_directory}/test_server/download-configs/test_client/test_client.conf"). 163 | with_content(%r{^auth-user-pass$}) 164 | } 165 | end 166 | 167 | context 'custom options' do 168 | let(:params) do 169 | { 170 | 'server' => 'test_server', 171 | 'custom_options' => { 'this' => 'that' } 172 | } 173 | end 174 | 175 | it { 176 | is_expected.to contain_file("#{server_directory}/test_server/download-configs/test_client/test_client.conf"). 177 | with_content(%r{^this that$}) 178 | } 179 | end 180 | 181 | context 'with all parameters' do 182 | let(:params) do 183 | { 184 | 'server' => 'test_server', 185 | 'compression' => 'compress lz4', 186 | 'dev' => 'tap', 187 | 'mute' => 10, 188 | 'mute_replay_warnings' => false, 189 | 'nobind' => false, 190 | 'persist_key' => false, 191 | 'persist_tun' => false, 192 | 'cipher' => 'AES-256-GCM', 193 | 'tls_cipher' => 'TLS-DHE-RSA-WITH-AES-256-CBC-SHA', 194 | 'port' => '123', 195 | 'proto' => 'udp', 196 | 'remote_host' => %w[somewhere galaxy], 197 | 'resolv_retry' => '2m', 198 | 'auth_retry' => 'interact', 199 | 'verb' => '1', 200 | 'setenv' => { 'CLIENT_CERT' => '0' }, 201 | 'setenv_safe' => { 'FORWARD_COMPATIBLE' => '1' }, 202 | 'tls_auth' => true, 203 | 'x509_name' => 'test_server', 204 | 'sndbuf' => 393_216, 205 | 'rcvbuf' => 393_215, 206 | 'readme' => 'readme text', 207 | 'pull' => true, 208 | 'remote_cert_tls' => false 209 | } 210 | end 211 | 212 | it { 213 | is_expected.to contain_file("#{server_directory}/test_server/download-configs/test_client/test_client.conf"). 214 | with_content(%r{^client$}). 215 | with_content(%r{^ca\s+keys/test_client/ca\.crt$}). 216 | with_content(%r{^cert\s+keys/test_client/test_client.crt$}). 217 | with_content(%r{^key\s+keys/test_client/test_client\.key$}). 218 | with_content(%r{^dev\s+tap$}). 219 | with_content(%r{^proto\s+udp$}). 220 | with_content(%r{^remote\s+somewhere\s+123$}). 221 | with_content(%r{^remote\s+galaxy\s+123$}). 222 | with_content(%r{^compress lz4$}). 223 | with_content(%r{^resolv-retry\s+2m$}). 224 | with_content(%r{^verb\s+1$}). 225 | with_content(%r{^mute\s+10$}). 226 | with_content(%r{^auth-retry\s+interact$}). 227 | with_content(%r{^setenv\s+CLIENT_CERT\s+0$}). 228 | with_content(%r{^setenv_safe\s+FORWARD_COMPATIBLE\s+1$}). 229 | with_content(%r{^cipher\s+AES-256-GCM$}). 230 | with_content(%r{^tls-cipher\s+TLS-DHE-RSA-WITH-AES-256-CBC-SHA$}). 231 | with_content(%r{^tls-client$}). 232 | with_content(%r{^verify-x509-name\s+"test_server"\s+name$}). 233 | with_content(%r{^sndbuf\s+393216$}). 234 | with_content(%r{^rcvbuf\s+393215$}). 235 | with_content(%r{^pull$}) 236 | } 237 | 238 | it { is_expected.not_to contain_file("#{server_directory}/test_server/download-configs/test_client/test_client.conf").with_content(%r{^remote-cert-tls\s+server$}) } 239 | 240 | it { is_expected.to contain_file("#{server_directory}/test_server/download-configs/test_client/README").with_content(%r{^readme text$}) } 241 | end 242 | 243 | context 'with extca' do 244 | let(:pre_condition) do 245 | 'openvpn::server { "text_server_extca": 246 | tls_auth => true, 247 | extca_enabled => true, 248 | extca_ca_cert_file => "/etc/ipa/ca.crt", 249 | extca_ca_crl_file => "/etc/ipa/ca_crl.pem", 250 | extca_server_cert_file => "/etc/pki/tls/certs/localhost.crt", 251 | extca_server_key_file => "/etc/pki/tls/private/localhost.key", 252 | extca_dh_file => "/etc/ipa/dh.pem", 253 | extca_tls_auth_key_file => "/etc/openvpn/keys/ta.key", 254 | }' 255 | end 256 | let(:params) { { 'server' => 'text_server_extca' } } 257 | 258 | it { is_expected.to compile.and_raise_error(%r{extca_enabled}) } 259 | end 260 | 261 | context 'with shared_ca' do 262 | let(:pre_condition) do 263 | 'openvpn::server { "test_server": 264 | country => "CO", 265 | province => "ST", 266 | city => "Some City", 267 | organization => "example.org", 268 | email => "testemail@example.org" 269 | } 270 | openvpn::server { "my_shared_ca": 271 | country => "CO", 272 | province => "ST", 273 | city => "Some City", 274 | organization => "example.org", 275 | email => "testemail@example.org" 276 | }' 277 | end 278 | let(:params) do 279 | { 280 | 'server' => 'test_server', 281 | 'shared_ca' => 'my_shared_ca' 282 | } 283 | end 284 | 285 | it { is_expected.to contain_openvpn__ca('my_shared_ca') } 286 | it { is_expected.to contain_exec('generate certificate for test_client in context of my_shared_ca') } 287 | 288 | it { 289 | is_expected.to contain_file("#{server_directory}/test_server/download-configs/test_client/test_client.conf"). 290 | with_content(%r{^client$}). 291 | with_content(%r{^ca\s+keys/test_client/ca\.crt$}). 292 | with_content(%r{^cert\s+keys/test_client/test_client\.crt$}). 293 | with_content(%r{^key\s+keys/test_client/test_client\.key$}) 294 | } 295 | 296 | it { 297 | is_expected.to contain_file("#{server_directory}/test_server/download-configs/test_client/keys/test_client/test_client.crt").with( 298 | 'ensure' => 'link', 299 | 'target' => "#{server_directory}/my_shared_ca/easy-rsa/keys/issued/test_client.crt" 300 | ) 301 | } 302 | 303 | it { 304 | is_expected.to contain_file("#{server_directory}/test_server/download-configs/test_client/keys/test_client/test_client.key").with( 305 | 'ensure' => 'link', 306 | 'target' => "#{server_directory}/my_shared_ca/easy-rsa/keys/private/test_client.key" 307 | ) 308 | } 309 | 310 | it { 311 | is_expected.to contain_file("#{server_directory}/test_server/download-configs/test_client/keys/test_client/ca.crt").with( 312 | 'ensure' => 'link', 313 | 'target' => "#{server_directory}/my_shared_ca/easy-rsa/keys/ca.crt" 314 | ) 315 | } 316 | end 317 | 318 | context 'with not existed shared_ca' do 319 | let(:params) do 320 | { 321 | 'server' => 'test_server', 322 | 'shared_ca' => 'my_shared_ca' 323 | } 324 | end 325 | 326 | it { is_expected.to compile.and_raise_error(%r{Could not find resource}) } 327 | end 328 | end 329 | end 330 | end 331 | -------------------------------------------------------------------------------- /spec/defines/openvpn_client_specific_config_spec.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | 3 | require 'spec_helper' 4 | 5 | describe 'openvpn::client_specific_config' do 6 | on_supported_os.each do |os, os_facts| 7 | context "on #{os}" do 8 | let(:facts) do 9 | os_facts.merge( 10 | easyrsa: '3.0' 11 | ) 12 | end 13 | let(:pre_condition) do 14 | 'openvpn::server { "test_server": 15 | country => "CO", 16 | province => "ST", 17 | city => "Some City", 18 | organization => "example.org", 19 | email => "testemail@example.org" 20 | } 21 | openvpn::client { "test_client": 22 | server => "test_server" 23 | }' 24 | end 25 | 26 | let(:title) { 'test_client' } 27 | 28 | server_directory = case os_facts[:os]['family'] 29 | when 'Archlinux', 'Debian', 'RedHat' 30 | '/etc/openvpn/server' 31 | when 'Solaris' 32 | '/opt/local/etc/openvpn' 33 | when 'FreeBSD' 34 | '/usr/local/etc/openvpn' 35 | else 36 | '/etc/openvpn' 37 | end 38 | 39 | context 'with the minimum parameters' do 40 | let(:params) { { server: 'test_server' } } 41 | 42 | it { is_expected.to compile.with_all_deps } 43 | 44 | it { 45 | is_expected.to contain_file("#{server_directory}/test_server/client-configs/test_client") 46 | } 47 | end 48 | 49 | context 'with all parameters' do 50 | let(:params) do 51 | { 52 | server: 'test_server', 53 | iroute: ['10.0.1.0 255.255.255.0'], 54 | iroute_ipv6: ['2001:db8:1234::/64'], 55 | ifconfig: '10.10.10.2 255.255.255.0', 56 | ifconfig_ipv6: '2001:db8:0:123::2/64 2001:db8:0:123::1', 57 | route: ['10.200.100.0 255.255.255.0 10.10.10.1'], 58 | route_ipv6: ['2001:db8:1::/64'], 59 | dhcp_options: ['DNS 8.8.8.8'], 60 | custom_options: { 'this' => 'that' }, 61 | redirect_gateway: true 62 | } 63 | end 64 | 65 | it { is_expected.to compile.with_all_deps } 66 | 67 | it { 68 | is_expected.to contain_file("#{server_directory}/test_server/client-configs/test_client"). 69 | with_content(%r{iroute 10.0.1.0 255.255.255.0}). 70 | with_content(%r{iroute-ipv6 2001:db8:1234::/64}). 71 | with_content(%r{ifconfig-push 10.10.10.2 255.255.255.0}). 72 | with_content(%r{ifconfig-ipv6-push 2001:db8:0:123::2/64 2001:db8:0:123::1}). 73 | with_content(%r{route 10.200.100.0 255.255.255.0 10.10.10.1}). 74 | with_content(%r{push "route-ipv6 2001:db8:1::/64}). 75 | with_content(%r{dhcp-option DNS 8.8.8.8}). 76 | with_content(%r{this that}). 77 | with_content(%r{redirect-gateway}) 78 | } 79 | end 80 | end 81 | end 82 | end 83 | -------------------------------------------------------------------------------- /spec/defines/openvpn_revoke_spec.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | 3 | require 'spec_helper' 4 | 5 | describe 'openvpn::revoke' do 6 | on_supported_os.each do |os, os_facts| 7 | context "on #{os}" do 8 | let(:facts) do 9 | os_facts.merge( 10 | easyrsa: '3.0' 11 | ) 12 | end 13 | 14 | server_directory = case os_facts[:os]['family'] 15 | when 'Archlinux', 'Debian', 'RedHat' 16 | '/etc/openvpn/server' 17 | when 'Solaris' 18 | '/opt/local/etc/openvpn' 19 | when 'FreeBSD' 20 | '/usr/local/etc/openvpn' 21 | else 22 | '/etc/openvpn' 23 | end 24 | context 'with default parameters' do 25 | let(:pre_condition) do 26 | [ 27 | 'openvpn::server { "test_server": 28 | country => "CO", 29 | province => "ST", 30 | city => "Some City", 31 | organization => "example.org", 32 | email => "testemail@example.org" 33 | }', 34 | 'openvpn::client { "test_client": 35 | server => "test_server" 36 | }' 37 | ].join 38 | end 39 | let(:title) { 'test_client' } 40 | let(:params) { { 'server' => 'test_server' } } 41 | 42 | it { is_expected.to compile.with_all_deps } 43 | 44 | it { 45 | is_expected.to contain_file("#{server_directory}/test_server/easy-rsa/revoked/test_client"). 46 | with_ensure('file') 47 | } 48 | 49 | it { 50 | is_expected.to contain_exec('revoke certificate for test_client in context of test_server'). 51 | with_command("./easyrsa --batch revoke test_client; echo \"exit $?\" | grep -qE '(error 23|exit (0|2))'") 52 | } 53 | 54 | it { 55 | is_expected.to contain_exec('renew crl.pem on test_server because of revocation of test_client'). 56 | with_command('./easyrsa --batch gen-crl') 57 | } 58 | 59 | it { 60 | is_expected.to contain_exec('copy renewed crl.pem to test_server keys directory because of revocation of test_client'). 61 | with_command("cp #{server_directory}/test_server/easy-rsa/keys/crl.pem #{server_directory}/test_server/crl.pem") 62 | } 63 | end 64 | end 65 | end 66 | end 67 | -------------------------------------------------------------------------------- /spec/defines/openvpn_server_spec.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | 3 | require 'spec_helper' 4 | 5 | describe 'openvpn::server' do 6 | on_supported_os.each do |os, os_facts| 7 | context "on #{os}" do 8 | let(:facts) do 9 | os_facts.merge( 10 | easyrsa: '3.0' 11 | ) 12 | end 13 | 14 | let(:title) { 'test_server' } 15 | 16 | server_directory = case os_facts[:os]['family'] 17 | when 'Archlinux', 'Debian', 'RedHat' 18 | '/etc/openvpn/server' 19 | when 'Solaris' 20 | '/opt/local/etc/openvpn' 21 | when 'FreeBSD' 22 | '/usr/local/etc/openvpn' 23 | else 24 | '/etc/openvpn' 25 | end 26 | pam_module_path = case os_facts[:os]['family'] 27 | when 'RedHat' 28 | case os_facts[:os]['name'] 29 | when 'Rocky' 30 | '/usr/lib64/openvpn/plugins/openvpn-auth-pam.so' 31 | else 32 | '/usr/lib64/openvpn/plugin/lib/openvpn-auth-pam.so' 33 | end 34 | when 'Debian' 35 | '/usr/lib/openvpn/openvpn-plugin-auth-pam.so' 36 | when 'FreeBSD' 37 | '/usr/local/lib/openvpn/openvpn-auth-pam.so' 38 | when 'Archlinux' 39 | '/usr/lib/openvpn/plugins/openvpn-plugin-auth-pam.so' 40 | else 41 | '~' 42 | end 43 | context 'with default parameters' do 44 | let(:params) { {} } 45 | 46 | it { is_expected.to compile.and_raise_error(%r{Evaluation Error}) } 47 | end 48 | 49 | context 'with country' do 50 | let(:params) do 51 | { 52 | 'country' => 'CO' 53 | } 54 | end 55 | 56 | it { is_expected.to compile.and_raise_error(%r{Evaluation Error}) } 57 | 58 | context 'with province' do 59 | let(:params) do 60 | { 61 | 'country' => 'CO', 62 | 'province' => 'ST' 63 | } 64 | end 65 | 66 | it { is_expected.to compile.and_raise_error(%r{Evaluation Error}) } 67 | 68 | context 'with city' do 69 | let(:params) do 70 | { 71 | 'country' => 'CO', 72 | 'province' => 'ST', 73 | 'city' => 'Some City' 74 | } 75 | end 76 | 77 | it { is_expected.to compile.and_raise_error(%r{Evaluation Error}) } 78 | 79 | context 'with organization' do 80 | let(:params) do 81 | { 82 | 'country' => 'CO', 83 | 'province' => 'ST', 84 | 'city' => 'Some City', 85 | 'organization' => 'example.org' 86 | } 87 | end 88 | 89 | it { is_expected.to compile.and_raise_error(%r{Evaluation Error}) } 90 | 91 | context 'with email' do 92 | let(:params) do 93 | { 94 | 'country' => 'CO', 95 | 'province' => 'ST', 96 | 'city' => 'Some City', 97 | 'organization' => 'example.org', 98 | 'email' => 'user@example.com' 99 | } 100 | end 101 | 102 | it { is_expected.to compile.with_all_deps } 103 | end 104 | end 105 | end 106 | end 107 | end 108 | 109 | context 'with extca_enabled' do 110 | let(:params) do 111 | { 112 | 'extca_enabled' => true 113 | } 114 | end 115 | 116 | it { is_expected.to compile.and_raise_error(%r{Evaluation Error}) } 117 | 118 | context 'with extca parameters' do 119 | let(:params) do 120 | { 121 | 'extca_enabled' => true, 122 | 'extca_ca_cert_file' => '/etc/ipa/ca.crt', 123 | 'extca_ca_crl_file' => '/etc/ipa/ca_crl.pem', 124 | 'extca_server_cert_file' => '/etc/pki/tls/certs/localhost.crt', 125 | 'extca_server_key_file' => '/etc/pki/tls/private/localhost.key', 126 | 'extca_dh_file' => '/etc/ipa/dh.pem' 127 | } 128 | end 129 | 130 | it { is_expected.to compile.with_all_deps } 131 | 132 | it { 133 | is_expected.to contain_file("#{server_directory}/test_server.conf"). 134 | with_content(%r{^ca\s+/etc/ipa/ca\.crt$}). 135 | with_content(%r{^crl-verify\s+/etc/ipa/ca_crl\.pem$}). 136 | with_content(%r{^cert\s+/etc/pki/tls/certs/localhost\.crt$}). 137 | with_content(%r{^key\s+/etc/pki/tls/private/localhost\.key$}). 138 | with_content(%r{^dh\s+/etc/ipa/dh\.pem$}) 139 | } 140 | end 141 | 142 | context 'with tls_auth=true' do 143 | let(:params) do 144 | { 145 | 'tls_auth' => true, 146 | 'extca_enabled' => true, 147 | 'extca_ca_cert_file' => '/etc/ipa/ca.crt', 148 | 'extca_ca_crl_file' => '/etc/ipa/ca_crl.pem', 149 | 'extca_server_cert_file' => '/etc/pki/tls/certs/localhost.crt', 150 | 'extca_server_key_file' => '/etc/pki/tls/private/localhost.key', 151 | 'extca_dh_file' => '/etc/ipa/dh.pem' 152 | } 153 | end 154 | 155 | it { is_expected.to compile.and_raise_error(%r{Evaluation Error}) } 156 | 157 | context 'with extca_tls_auth_key_file' do 158 | let(:params) do 159 | { 160 | 'tls_auth' => true, 161 | 'extca_tls_auth_key_file' => '/etc/openvpn/ta.key', 162 | 'extca_enabled' => true, 163 | 'extca_ca_cert_file' => '/etc/ipa/ca.crt', 164 | 'extca_ca_crl_file' => '/etc/ipa/ca_crl.pem', 165 | 'extca_server_cert_file' => '/etc/pki/tls/certs/localhost.crt', 166 | 'extca_server_key_file' => '/etc/pki/tls/private/localhost.key', 167 | 'extca_dh_file' => '/etc/ipa/dh.pem' 168 | } 169 | end 170 | 171 | it { is_expected.to compile.with_all_deps } 172 | 173 | it { 174 | is_expected.to contain_file("#{server_directory}/test_server.conf"). 175 | with_content(%r{^ca\s+/etc/ipa/ca\.crt$}). 176 | with_content(%r{^crl-verify\s+/etc/ipa/ca_crl\.pem$}). 177 | with_content(%r{^cert\s+/etc/pki/tls/certs/localhost\.crt$}). 178 | with_content(%r{^key\s+/etc/pki/tls/private/localhost\.key$}). 179 | with_content(%r{^dh\s+/etc/ipa/dh\.pem$}). 180 | with_content(%r{^tls-auth\s+/etc/openvpn/ta\.key$}). 181 | with_content(%r{^key-direction\s+0$}) 182 | } 183 | end 184 | end 185 | end 186 | 187 | context 'with sndbuf and rcvbuf' do 188 | let(:params) do 189 | { 190 | 'country' => 'CO', 191 | 'province' => 'ST', 192 | 'city' => 'Some City', 193 | 'organization' => 'example.org', 194 | 'email' => 'testemail@example.org', 195 | 'sndbuf' => 393_216, 196 | 'rcvbuf' => 393_215 197 | } 198 | end 199 | 200 | it { is_expected.to contain_file("#{server_directory}/test_server.conf").with_content(%r{^sndbuf\s+393216$}) } 201 | it { is_expected.to contain_file("#{server_directory}/test_server.conf").with_content(%r{^rcvbuf\s+393215$}) } 202 | end 203 | 204 | %w[udp tcp udp4 tcp4 udp6 tcp6].each do |proto| 205 | context "with proto=#{proto}" do 206 | let(:params) do 207 | { 208 | 'country' => 'CO', 209 | 'province' => 'ST', 210 | 'city' => 'Some City', 211 | 'organization' => 'example.org', 212 | 'email' => 'testemail@example.org', 213 | 'proto' => proto 214 | } 215 | end 216 | 217 | it { is_expected.to compile.with_all_deps } 218 | 219 | it { 220 | if proto.include?('tcp') 221 | is_expected.to contain_file("#{server_directory}/test_server.conf"). 222 | with_content(%r{^proto\s+#{proto}-server$}) 223 | else 224 | is_expected.to contain_file("#{server_directory}/test_server.conf"). 225 | with_content(%r{^proto\s+#{proto}$}) 226 | end 227 | } 228 | end 229 | end 230 | 231 | context 'with invalid proto' do 232 | let(:params) do 233 | { 234 | 'country' => 'CO', 235 | 'province' => 'ST', 236 | 'city' => 'Some City', 237 | 'organization' => 'example.org', 238 | 'email' => 'testemail@example.org', 239 | 'proto' => 'invalid' 240 | } 241 | end 242 | 243 | it { is_expected.to compile.and_raise_error(%r{Evaluation Error}) } 244 | end 245 | 246 | context 'with remote' do 247 | let(:title) { 'test_client' } 248 | let(:params) do 249 | { 250 | 'server_poll_timeout' => 1, 251 | 'ping_timer_rem' => true, 252 | 'tls_auth' => true, 253 | 'tls_client' => true, 254 | 'remote' => ['vpn.example.com 1194'] 255 | } 256 | end 257 | 258 | it { is_expected.to compile.with_all_deps } 259 | 260 | it { 261 | is_expected.to contain_file("#{server_directory}/test_client.conf"). 262 | with_content(%r{^remote\s+vpn\.example\.com\s+1194$}). 263 | with_content(%r{^client$}). 264 | with_content(%r{^server-poll-timeout\s+1$}). 265 | with_content(%r{^remote-cert-tls server}). 266 | with_content(%r{^ping-timer-rem$}). 267 | with_content(%r{^tls-client$}). 268 | with_content(%r{^key-direction\s+1$}). 269 | with_content(%r{^port\s+\d+$}). 270 | without_content(%r{^mode\s+server$}). 271 | without_content(%r{^nobind$}). 272 | without_content(%r{^client-config-dir}). 273 | without_content(%r{^dh}). 274 | without_content(%r{^remote-random-hostname$}). 275 | without_content(%r{^remote-random$}) 276 | } 277 | 278 | context 'with nobind' do 279 | let(:params) do 280 | { 281 | 'server_poll_timeout' => 1, 282 | 'ping_timer_rem' => true, 283 | 'tls_auth' => true, 284 | 'tls_client' => true, 285 | 'nobind' => true, 286 | 'remote' => ['vpn.example.com 1194'] 287 | } 288 | end 289 | 290 | it { is_expected.to compile.with_all_deps } 291 | 292 | it { 293 | is_expected.to contain_file("#{server_directory}/test_client.conf"). 294 | with_content(%r{^nobind$}). 295 | without_content(%r{^port\s+\d+$}) 296 | } 297 | end 298 | 299 | it { is_expected.not_to contain_openvpn__ca('test_client') } 300 | 301 | it { is_expected.to contain_file("#{server_directory}/test_client/keys").with(mode: '0750', ensure: 'directory') } 302 | 303 | it { is_expected.to contain_file("#{server_directory}/test_client/keys").with_group('nobody') } if os_facts[:os]['family'] == %r{'RedHat'|'Solaris'|'FreeBSD'} 304 | 305 | it { is_expected.to contain_file("#{server_directory}/test_client/keys").with_group('nogroup') } if os_facts[:os]['family'] == 'Debian' 306 | 307 | it { is_expected.to contain_file("#{server_directory}/test_client/keys").with_group('network') } if os_facts[:os]['family'] == 'Archlinux' 308 | 309 | context 'with multiple remotes' do 310 | let(:params) do 311 | { 312 | 'server_poll_timeout' => 1, 313 | 'ping_timer_rem' => true, 314 | 'tls_auth' => true, 315 | 'tls_client' => true, 316 | 'remote' => ['vpn.example.com 1194', 'vpn2.example.com 1194'] 317 | } 318 | end 319 | 320 | it { is_expected.to compile.with_all_deps } 321 | 322 | it { 323 | is_expected.to contain_file("#{server_directory}/test_client.conf"). 324 | with_content(%r{^remote\s+vpn\.example\.com\s+1194$}). 325 | with_content(%r{^remote\s+vpn2\.example\.com\s+1194$}). 326 | with_content(%r{^client$}). 327 | with_content(%r{^server-poll-timeout\s+1$}). 328 | with_content(%r{^remote-cert-tls server}). 329 | with_content(%r{^ping-timer-rem$}). 330 | with_content(%r{^tls-client$}). 331 | with_content(%r{^key-direction\s+1$}). 332 | with_content(%r{^port\s+\d+$}). 333 | without_content(%r{^mode\s+server$}). 334 | without_content(%r{^nobind$}). 335 | without_content(%r{^client-config-dir}). 336 | without_content(%r{^dh}). 337 | without_content(%r{^remote-random-hostname$}). 338 | without_content(%r{^remote-random$}) 339 | } 340 | 341 | it { is_expected.not_to contain_openvpn__ca('test_client') } 342 | it { is_expected.to contain_file("#{server_directory}/test_client/keys").with(mode: '0750', ensure: 'directory') } 343 | 344 | it { is_expected.to contain_file("#{server_directory}/test_client/keys").with_group('nobody') } if os_facts[:os]['family'] == %r{'RedHat'|'Solaris'|'FreeBSD'} 345 | 346 | it { is_expected.to contain_file("#{server_directory}/test_client/keys").with_group('nogroup') } if os_facts[:os]['family'] == 'Debian' 347 | 348 | it { is_expected.to contain_file("#{server_directory}/test_client/keys").with_group('network') } if os_facts[:os]['family'] == 'Archlinux' 349 | 350 | context 'with remote_random' do 351 | let(:params) do 352 | { 353 | 'server_poll_timeout' => 1, 354 | 'ping_timer_rem' => true, 355 | 'tls_auth' => true, 356 | 'tls_client' => true, 357 | 'remote_random' => true, 358 | 'remote_random_hostname' => true, 359 | 'remote' => ['vpn.example.com 1194', 'vpn2.example.com 1194'] 360 | } 361 | end 362 | 363 | it { is_expected.to compile.with_all_deps } 364 | 365 | it { 366 | is_expected.to contain_file("#{server_directory}/test_client.conf"). 367 | with_content(%r{^remote\s+vpn\.example\.com\s+1194$}). 368 | with_content(%r{^remote\s+vpn2\.example\.com\s+1194$}). 369 | with_content(%r{^client$}). 370 | with_content(%r{^server-poll-timeout\s+1$}). 371 | with_content(%r{^remote-cert-tls server}). 372 | with_content(%r{^ping-timer-rem$}). 373 | with_content(%r{^tls-client$}). 374 | with_content(%r{^key-direction\s+1$}). 375 | with_content(%r{^port\s+\d+$}). 376 | with_content(%r{^remote-random$}). 377 | with_content(%r{^remote-random-hostname$}). 378 | without_content(%r{^mode\s+server$}). 379 | without_content(%r{^nobind$}). 380 | without_content(%r{^client-config-dir}). 381 | without_content(%r{^dh}) 382 | } 383 | 384 | it { is_expected.not_to contain_openvpn__ca('test_client') } 385 | it { is_expected.to contain_file("#{server_directory}/test_client/keys").with(mode: '0750', ensure: 'directory') } 386 | 387 | it { is_expected.to contain_file("#{server_directory}/test_client/keys").with_group('nobody') } if os_facts[:os]['family'] == %r{'RedHat'|'Solaris'|'FreeBSD'} 388 | 389 | it { is_expected.to contain_file("#{server_directory}/test_client/keys").with_group('nogroup') } if os_facts[:os]['family'] == 'Debian' 390 | 391 | it { is_expected.to contain_file("#{server_directory}/test_client/keys").with_group('network') } if os_facts[:os]['family'] == 'Archlinux' 392 | end 393 | end 394 | end 395 | 396 | context 'with all parameters' do 397 | let(:params) do 398 | { 399 | 'country' => 'CO', 400 | 'province' => 'ST', 401 | 'city' => 'Some City', 402 | 'organization' => 'example.org', 403 | 'email' => 'testemail@example.org', 404 | 'compression' => 'compress lz4', 405 | 'port' => '123', 406 | 'proto' => 'udp', 407 | 'group' => 'someone', 408 | 'user' => 'someone', 409 | 'logfile' => '/var/log/openvpn/server1/test_server.log', 410 | 'manage_logfile_directory' => true, 411 | 'logdirectory_user' => 'someone', 412 | 'logdirectory_group' => 'someone', 413 | 'status_log' => '/tmp/test_server_status.log', 414 | 'dev' => 'tun1', 415 | 'up' => '/tmp/up', 416 | 'down' => '/tmp/down', 417 | 'client_connect' => '/tmp/connect', 418 | 'client_disconnect' => '/tmp/disconnect', 419 | 'local' => '2.3.4.5', 420 | 'ipp' => true, 421 | 'server' => '2.3.4.0 255.255.0.0', 422 | 'server_ipv6' => 'fe80:1337:1337:1337::/64', 423 | 'push' => ['dhcp-option DNS 172.31.0.30', 'route 172.31.0.0 255.255.0.0'], 424 | 'route' => ['192.168.30.0 255.255.255.0', '192.168.35.0 255.255.0.0'], 425 | 'route_ipv6' => ['2001:db8:1234::/64', '2001:db8:abcd::/64'], 426 | 'keepalive' => '10 120', 427 | 'topology' => 'subnet', 428 | 'ssl_key_size' => 2048, 429 | 'management' => true, 430 | 'management_ip' => '1.3.3.7', 431 | 'management_port' => 1337, 432 | 'common_name' => 'mylittlepony', 433 | 'ca_expire' => 365, 434 | 'crl_auto_renew' => true, 435 | 'key_expire' => 365, 436 | 'crl_days' => 20, 437 | 'digest' => 'sha256', 438 | 'key_cn' => 'yolo', 439 | 'key_name' => 'burp', 440 | 'key_ou' => 'NSA', 441 | 'verb' => 'mute', 442 | 'cipher' => 'DES-CBC', 443 | 'tls_cipher' => 'TLS-DHE-RSA-WITH-AES-256-CBC-SHA', 444 | 'persist_key' => true, 445 | 'persist_tun' => true, 446 | 'duplicate_cn' => true, 447 | 'tls_auth' => true, 448 | 'tls_server' => true, 449 | 'fragment' => 1412, 450 | 'custom_options' => { 'this' => 'that' }, 451 | 'portshare' => '127.0.0.1 8443', 452 | 'secret' => 'secretsecret1234', 453 | 'remote_cert_tls' => true 454 | } 455 | end 456 | 457 | it { 458 | is_expected.to contain_file("#{server_directory}/test_server.conf"). 459 | with_content(%r{^mode\s+server$}). 460 | with_content(%r{^client-config-dir\s+#{server_directory}/test_server/client-configs$}). 461 | with_content(%r{^ca\s+#{server_directory}/test_server/keys/ca.crt$}). 462 | with_content(%r{^proto\s+udp$}). 463 | with_content(%r{^port\s+123$}). 464 | with_content(%r{^compress lz4$}). 465 | with_content(%r{^log-append\s+/var/log/openvpn/server1/test_server\.log$}). 466 | with_content(%r{^status\s+/tmp/test_server_status\.log$}). 467 | with_content(%r{^dev\s+tun1$}). 468 | with_content(%r{^local\s+2\.3\.4\.5$}). 469 | with_content(%r{^server\s+2\.3\.4\.0\s+255\.255\.0\.0$}). 470 | with_content(%r{^server-ipv6\s+fe80:1337:1337:1337::/64$}). 471 | with_content(%r{^push\s+"dhcp-option\s+DNS\s+172\.31\.0\.30"$}). 472 | with_content(%r{^push\s+"route\s+172\.31\.0\.0\s+255\.255\.0\.0"$}). 473 | with_content(%r{^route\s+192.168.30.0\s+255.255.255.0$}). 474 | with_content(%r{^route\s+192.168.35.0\s+255.255.0.0$}). 475 | with_content(%r{^route-ipv6\s+2001:db8:1234::/64$}). 476 | with_content(%r{^route-ipv6\s+2001:db8:abcd::/64$}). 477 | with_content(%r{^keepalive\s+10\s+120$}). 478 | with_content(%r{^topology\s+subnet$}). 479 | with_content(%r{^management\s+1.3.3.7 1337$}). 480 | with_content(%r{^verb mute$}). 481 | with_content(%r{^cipher DES-CBC$}). 482 | with_content(%r{^tls-cipher\s+TLS-DHE-RSA-WITH-AES-256-CBC-SHA$}). 483 | with_content(%r{^persist-key$}). 484 | with_content(%r{^persist-tun$}). 485 | with_content(%r{^up "/tmp/up"$}). 486 | with_content(%r{^down "/tmp/down"$}). 487 | with_content(%r{^client-connect "/tmp/connect"$}). 488 | with_content(%r{^client-disconnect "/tmp/disconnect"$}). 489 | with_content(%r{^script-security 2$}). 490 | with_content(%r{^duplicate-cn$}). 491 | with_content(%r{^tls-server$}). 492 | with_content(%r{^tls-auth\s+#{server_directory}/test_server/keys/ta.key$}). 493 | with_content(%r{^key-direction 0$}). 494 | with_content(%r{^this that$}). 495 | with_content(%r{^fragment 1412$}). 496 | with_content(%r{^port-share 127.0.0.1 8443$}). 497 | with_content(%r{^secret #{server_directory}/test_server/keys/pre-shared.secret$}). 498 | without_content(%r{^proto\s+tls-server$}). 499 | without_content(%r{^server-poll-timeout}). 500 | without_content(%r{^ping-timer-rem}). 501 | without_content(%r{^sndbuf}). 502 | without_content(%r{^rcvbuf}). 503 | without_content(%r{^remote-cert-tls server$}) 504 | } 505 | 506 | unless os_facts[:os]['family'] == 'Archlinux' 507 | it { 508 | is_expected.to contain_file("#{server_directory}/test_server.conf"). 509 | with_content(%r{^group\s+someone$}). 510 | with_content(%r{^user\s+someone$}) 511 | } 512 | end 513 | 514 | it { is_expected.to contain_file('/var/log/openvpn/server1').with(ensure: 'directory', owner: 'someone', group: 'someone') } 515 | 516 | it { 517 | is_expected.to contain_file("#{server_directory}/test_server/keys/pre-shared.secret"). 518 | with_content(%r{^secretsecret1234$}). 519 | with_ensure('present') 520 | } 521 | 522 | it { is_expected.to contain_schedule('renew crl.pem schedule on test_server') } 523 | it { is_expected.to contain_exec('renew crl.pem on test_server') } 524 | 525 | # OpenVPN easy-rsa CA 526 | it { 527 | is_expected.to contain_openvpn__ca('test_server'). 528 | with(country: 'CO', 529 | province: 'ST', 530 | city: 'Some City', 531 | organization: 'example.org', 532 | email: 'testemail@example.org', 533 | group: 'someone', 534 | ssl_key_size: 2048, 535 | common_name: 'mylittlepony', 536 | ca_expire: 365, 537 | key_expire: 365, 538 | crl_days: 20, 539 | digest: 'sha256', 540 | key_cn: 'yolo', 541 | key_name: 'burp', 542 | key_ou: 'NSA', 543 | tls_static_key: true) 544 | } 545 | end 546 | 547 | context 'with pam' do 548 | let(:params) do 549 | { 550 | 'country' => 'CO', 551 | 'province' => 'ST', 552 | 'city' => 'Some City', 553 | 'organization' => 'example.org', 554 | 'email' => 'testmail@example.org', 555 | 'pam' => true 556 | } 557 | end 558 | 559 | it { is_expected.to compile.with_all_deps } 560 | 561 | it { is_expected.to contain_file("#{server_directory}/test_server.conf").with_content(%r{^plugin #{pam_module_path} "?login"?$}) } unless os_facts[:os]['family'] == 'Archlinux' 562 | 563 | context 'with pam_module_arguments' do 564 | let(:params) do 565 | { 566 | 'country' => 'CO', 567 | 'province' => 'ST', 568 | 'city' => 'Some City', 569 | 'organization' => 'example.org', 570 | 'email' => 'testmail@example.org', 571 | 'pam' => true, 572 | 'pam_module_arguments' => 'openvpn login USERNAME password PASSWORD' 573 | } 574 | end 575 | 576 | it { is_expected.to compile.with_all_deps } 577 | 578 | it { is_expected.to contain_file("#{server_directory}/test_server.conf").with_content(%r{^plugin #{pam_module_path} "openvpn login USERNAME password PASSWORD"$}) } unless os_facts[:os]['family'] == 'Archlinux' 579 | end 580 | end 581 | 582 | if os_facts[:os]['family'] == 'Debian' 583 | context 'with ldap authentication' do 584 | let(:params) do 585 | { 586 | 'country' => 'CO', 587 | 'province' => 'ST', 588 | 'city' => 'Some City', 589 | 'organization' => 'example.org', 590 | 'email' => 'testemail@example.org', 591 | 'ldap_enabled' => true, 592 | 'ldap_binddn' => 'dn=foo,ou=foo,ou=com', 593 | 'ldap_bindpass' => 'ldappass123', 594 | 'ldap_tls_enable' => true, 595 | 'ldap_tls_ca_cert_file' => '/etc/ldap/ca.pem', 596 | 'ldap_tls_ca_cert_dir' => '/etc/ldap/certs' 597 | } 598 | end 599 | 600 | it { is_expected.to compile.with_all_deps } 601 | 602 | it { 603 | is_expected.to contain_file("#{server_directory}/test_server/auth/ldap.conf"). 604 | with_content(%r{^\s+TLSEnable\s+yes$}). 605 | with_content(%r{^\s+TLSCACertFile\s+/etc/ldap/ca.pem$}). 606 | with_content(%r{^\s+TLSCACertDir\s+/etc/ldap/certs$}). 607 | without_content(%r{^\s+TLSCertFile.*$}). 608 | without_content(%r{^\s+TLSKeyFile.*$}) 609 | } 610 | 611 | context 'with ldap_tls_cert_file and ldap_tls_key_file' do 612 | let(:params) do 613 | { 614 | 'country' => 'CO', 615 | 'province' => 'ST', 616 | 'city' => 'Some City', 617 | 'organization' => 'example.org', 618 | 'email' => 'testemail@example.org', 619 | 'ldap_enabled' => true, 620 | 'ldap_binddn' => 'dn=foo,ou=foo,ou=com', 621 | 'ldap_bindpass' => 'ldappass123', 622 | 'ldap_tls_enable' => true, 623 | 'ldap_tls_ca_cert_file' => '/etc/ldap/ca.pem', 624 | 'ldap_tls_ca_cert_dir' => '/etc/ldap/certs', 625 | 'ldap_tls_client_cert_file' => '/etc/ldap/client-cert.pem', 626 | 'ldap_tls_client_key_file' => '/etc/ldap/client-key.pem' 627 | } 628 | end 629 | 630 | it { 631 | is_expected.to contain_file("#{server_directory}/test_server/auth/ldap.conf"). 632 | with_content(%r{^\s+TLSEnable\s+yes$}). 633 | with_content(%r{^\s+TLSCACertFile\s+/etc/ldap/ca.pem$}). 634 | with_content(%r{^\s+TLSCACertDir\s+/etc/ldap/certs$}). 635 | with_content(%r{^\s+TLSCertFile\s+/etc/ldap/client-cert.pem$}). 636 | with_content(%r{^\s+TLSKeyFile\s+/etc/ldap/client-key.pem$}) 637 | } 638 | end 639 | end 640 | end 641 | end 642 | end 643 | end 644 | -------------------------------------------------------------------------------- /spec/setup_acceptance_node.pp: -------------------------------------------------------------------------------- 1 | if $facts['os']['family'] == 'RedHat' { 2 | package { 'epel-release': 3 | ensure => present, 4 | } 5 | } 6 | 7 | $netcat_package_name = $facts['os']['family'] ? { 8 | 'Debian' => 'netcat-openbsd', 9 | 'RedHat' => 'nc', 10 | 'Archlinux' => 'gnu-netcat', 11 | default => 'netcat', 12 | } 13 | 14 | node /vpnserver/ { 15 | package { $netcat_package_name: 16 | ensure => present, 17 | } 18 | } 19 | 20 | node /vpnclient/ { 21 | package { ['tar','openvpn']: 22 | ensure => present, 23 | } 24 | } 25 | 26 | node default { 27 | package { $netcat_package_name: 28 | ensure => present, 29 | } 30 | } 31 | -------------------------------------------------------------------------------- /spec/spec_helper.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | 3 | # Managed by modulesync - DO NOT EDIT 4 | # https://voxpupuli.org/docs/updating-files-managed-with-modulesync/ 5 | 6 | # puppetlabs_spec_helper will set up coverage if the env variable is set. 7 | # We want to do this if lib exists and it hasn't been explicitly set. 8 | ENV['COVERAGE'] ||= 'yes' if Dir.exist?(File.expand_path('../lib', __dir__)) 9 | 10 | require 'voxpupuli/test/spec_helper' 11 | 12 | RSpec.configure do |c| 13 | c.facterdb_string_keys = false 14 | end 15 | 16 | add_mocked_facts! 17 | 18 | if File.exist?(File.join(__dir__, 'default_module_facts.yml')) 19 | facts = YAML.safe_load(File.read(File.join(__dir__, 'default_module_facts.yml'))) 20 | facts&.each do |name, value| 21 | add_custom_fact name.to_sym, value 22 | end 23 | end 24 | Dir['./spec/support/spec/**/*.rb'].sort.each { |f| require f } 25 | -------------------------------------------------------------------------------- /spec/spec_helper_acceptance.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | 3 | # Managed by modulesync - DO NOT EDIT 4 | # https://voxpupuli.org/docs/updating-files-managed-with-modulesync/ 5 | 6 | require 'voxpupuli/acceptance/spec_helper_acceptance' 7 | 8 | configure_beaker(modules: :metadata) 9 | 10 | Dir['./spec/support/acceptance/**/*.rb'].sort.each { |f| require f } 11 | -------------------------------------------------------------------------------- /templates/client.erb: -------------------------------------------------------------------------------- 1 | client 2 | dev <%= @dev %> 3 | proto <%= @proto %> 4 | <% @remote_host = [@remote_host] unless @remote_host.kind_of?(Array) -%> 5 | <% @remote_host.each do |item| -%> 6 | remote <%= item %> <%= @port %> 7 | <% end -%> 8 | <% if @compression -%> 9 | <%= @compression %> 10 | <% end -%> 11 | resolv-retry <%= @resolv_retry %> 12 | auth-retry <%= @auth_retry %> 13 | <% if @pull -%> 14 | pull 15 | <% end -%> 16 | <% if @nobind -%> 17 | nobind 18 | <% end -%> 19 | <% if @persist_key -%> 20 | persist-key 21 | <% end -%> 22 | <% if @persist_tun -%> 23 | persist-tun 24 | <% end -%> 25 | <% if @cipher != '' -%> 26 | cipher <%= @cipher %> 27 | <% end -%> 28 | <% if @tls_cipher != '' -%> 29 | tls-cipher <%= @tls_cipher %> 30 | <% end -%> 31 | <% if @mute_replay_warnings -%> 32 | mute-replay-warnings 33 | <% end -%> 34 | <% if @remote_cert_tls -%> 35 | remote-cert-tls server 36 | <% end -%> 37 | <% if @sndbuf -%> 38 | sndbuf <%= @sndbuf %> 39 | <% end -%> 40 | <% if @rcvbuf -%> 41 | rcvbuf <%= @rcvbuf %> 42 | <% end -%> 43 | verb <%= @verb %> 44 | mute <%= @mute %> 45 | <% if @pam || @authuserpass -%> 46 | auth-user-pass 47 | <% end -%> 48 | <% @setenv.each do |key, value| -%> 49 | setenv <%= key %> <%= value %> 50 | <% end -%> 51 | <% @setenv_safe.each do |key, value| -%> 52 | setenv_safe <%= key %> <%= value %> 53 | <% end -%> 54 | <% if @up or @down -%> 55 | script-security 2 56 | <% end -%> 57 | <% if @up -%> 58 | up "<%= @up %>" 59 | <% end -%> 60 | <% if @down -%> 61 | down "<%= @down %>" 62 | <% end -%> 63 | <% if @x509_name -%> 64 | 65 | # x509 name verification 66 | verify-x509-name "<%= @x509_name %>" name 67 | <% end -%> 68 | 69 | # Additional custom options 70 | <% @custom_options.each_pair do |key, value| -%> 71 | <%= key %> <%= value %> 72 | <% end -%> 73 | 74 | -------------------------------------------------------------------------------- /templates/client_external_auth.erb: -------------------------------------------------------------------------------- 1 | ca keys/<%= @name %>/ca.crt 2 | cert keys/<%= @name %>/<%= @name %>.crt 3 | key keys/<%= @name %>/<%= @name %>.key 4 | <% if @tls_auth -%> 5 | 6 | # tls authentification 7 | tls-client 8 | tls-auth keys/<%= @name %>/ta.key 1 9 | <% end -%> 10 | <% if @tls_crypt -%> 11 | tls-crypt keys/<%= @name %>/ta.key 12 | <% end -%> 13 | -------------------------------------------------------------------------------- /templates/client_specific_config.erb: -------------------------------------------------------------------------------- 1 | <% @iroute.each do |iroute| -%> 2 | iroute <%= iroute %> 3 | <% end -%> 4 | <% @iroute_ipv6.each do |iroute_ipv6| -%> 5 | iroute-ipv6 <%= iroute_ipv6 %> 6 | <% end -%> 7 | <% if @ifconfig -%> 8 | ifconfig-push <%= @ifconfig %> 9 | <% end -%> 10 | <% if @ifconfig_ipv6 -%> 11 | ifconfig-ipv6-push <%= @ifconfig_ipv6 %> 12 | <% end -%> 13 | <% @dhcp_options.each do |option| -%> 14 | push "dhcp-option <%= option %>" 15 | <% end -%> 16 | <% if @redirect_gateway -%> 17 | push "redirect-gateway def1" 18 | <% end -%> 19 | <% @route.each do |route| -%> 20 | push "route <%= route %>" 21 | <% end -%> 22 | <% @route_ipv6.each do |route| -%> 23 | push "route-ipv6 <%= route %>" 24 | <% end -%> 25 | <% @custom_options.each_pair do |key, value| -%> 26 | <%= key %> <%= value %> 27 | <% end -%> 28 | 29 | -------------------------------------------------------------------------------- /templates/etc-default-openvpn.erb: -------------------------------------------------------------------------------- 1 | # This is the configuration file for /etc/init.d/openvpn 2 | 3 | # 4 | # Start only these VPNs automatically via init script. 5 | # Allowed values are "all", "none" or space separated list of 6 | # names of the VPNs. If empty, "all" is assumed. 7 | # 8 | #AUTOSTART="all" 9 | #AUTOSTART="none" 10 | #AUTOSTART="home office" 11 | # 12 | # Refresh interval (in seconds) of default status files 13 | # located in /var/run/openvpn.$NAME.status 14 | # Defaults to 10, 0 disables status file generation 15 | # 16 | #STATUSREFRESH=10 17 | #STATUSREFRESH=0 18 | # Optional arguments to openvpn's command line 19 | OPTARGS="" 20 | <% if scope.lookupvar('openvpn::autostart_all') -%> 21 | AUTOSTART="all" 22 | <% else -%> 23 | AUTOSTART="" 24 | <% end -%> 25 | -------------------------------------------------------------------------------- /templates/etc-rc.d-openvpn.erb: -------------------------------------------------------------------------------- 1 | openvpn_<%= @name -%>_enable="YES" 2 | openvpn_<%= @name -%>_configfile="<%= @server_directory -%>/<%= @name -%>.conf" 3 | openvpn_<%= @name -%>_dir="<%= @server_directory -%>/<%= @name -%>" 4 | -------------------------------------------------------------------------------- /templates/ldap.erb: -------------------------------------------------------------------------------- 1 | 2 | URL <%= @ldap_server %> 3 | <% if @ldap_binddn and @ldap_bindpass -%> 4 | BindDN <%= @ldap_binddn %> 5 | Password <%= @ldap_bindpass %> 6 | <% end -%> 7 | Timeout 15 8 | FollowReferrals no 9 | 10 | <% if @ldap_tls_enable -%> 11 | TLSEnable yes 12 | TLSCACertFile <%= @ldap_tls_ca_cert_file %> 13 | TLSCACertDir <%= @ldap_tls_ca_cert_dir %> 14 | <% if @ldap_tls_client_cert_file or @ldap_tls_client_key_file -%> 15 | TLSCertFile <%= @ldap_tls_client_cert_file %> 16 | TLSKeyFile <%= @ldap_tls_client_key_file %> 17 | <% end -%> 18 | <% else %> 19 | TLSEnable no 20 | <% end -%> 21 | 22 | 23 | 24 | BaseDN <%= @ldap_u_basedn %> 25 | SearchFilter "<%= @ldap_u_filter %>" 26 | RequireGroup <%= @ldap_gmember %> 27 | 28 | <% if @ldap_gmember == true -%> 29 | 30 | BaseDN <%= @ldap_g_basedn %> 31 | SearchFilter "<%= @ldap_g_filter %>" 32 | MemberAttribute <%= @ldap_memberatr %> 33 | 34 | <% end -%> 35 | 36 | -------------------------------------------------------------------------------- /templates/server.erb: -------------------------------------------------------------------------------- 1 | <% unless @remote -%> 2 | mode server 3 | client-config-dir <%= @server_directory %>/<%= @name %>/client-configs 4 | <% else -%> 5 | client 6 | <% if @remote_cert_tls -%> 7 | remote-cert-tls server 8 | <% end -%> 9 | <% @remote.to_a.each do |rem| -%> 10 | remote <%= rem %> 11 | <% end -%> 12 | <% if @remote_random_hostname %> 13 | remote-random-hostname 14 | <% end -%> 15 | <% if @remote_random %> 16 | remote-random 17 | <% end -%> 18 | <% if @server_poll_timeout -%> 19 | server-poll-timeout <%= @server_poll_timeout %> 20 | <% end -%> 21 | <% end -%> 22 | <% if @extca_enabled -%> 23 | ca <%= @extca_ca_cert_file %> 24 | cert <%= @extca_server_cert_file %> 25 | key <%= @extca_server_key_file %> 26 | <% unless @remote or !@extca_dh_file -%> 27 | dh <%= @extca_dh_file %> 28 | <% end -%> 29 | <% unless @remote or !@crl_verify or !@extca_ca_crl_file -%> 30 | crl-verify <%= @extca_ca_crl_file %> 31 | <% end -%> 32 | <% else -%> 33 | 34 | ca <%= @server_directory %>/<%= @ca_name %>/keys/ca.crt 35 | cert <%= @server_directory %>/<%= @ca_name %>/keys/issued/<%= @ca_common_name %>.crt 36 | key <%= @server_directory %>/<%= @ca_name %>/keys/private/<%= @ca_common_name %>.key 37 | <% unless @remote -%> 38 | <%- if @ssl_key_algo == 'rsa' -%> 39 | dh <%= @server_directory %>/<%= @ca_name %>/keys/dh.pem 40 | <%- else -%> 41 | dh none 42 | <%- end -%> 43 | <%- if @ecdh_curve -%> 44 | ecdh-curve <%= @ecdh_curve %> 45 | <%- end -%> 46 | <% end -%> 47 | <% unless @remote or !@crl_verify -%> 48 | crl-verify <%= @server_directory %>/<%= @ca_name %>/crl.pem 49 | <% end -%> 50 | <% end -%> 51 | <% if @proto.include?('tcp') -%> 52 | <% unless @remote -%> 53 | proto <%= @proto %>-server 54 | <% else -%> 55 | proto <%= @proto %> 56 | <% end -%> 57 | <% else -%> 58 | proto <%= @proto %> 59 | <% end -%> 60 | <% if @nobind -%> 61 | nobind 62 | <% else -%> 63 | port <%= @port %> 64 | <% if @portshare -%> 65 | port-share <%= @portshare %> 66 | <% end -%> 67 | <% end -%> 68 | <% if @real_tls_server -%> 69 | tls-server 70 | <% end -%> 71 | <% if @tls_client -%> 72 | tls-client 73 | <% end -%> 74 | <% if @compression -%> 75 | <%= @compression %> 76 | <% end -%> 77 | <% if @set_user_group %> 78 | group <%= @group_to_set %> 79 | user <%= @user %> 80 | <% end -%> 81 | <% if @logfile -%> 82 | log-append <%= @logfile %> 83 | <% end -%> 84 | <% if @status_log != '' -%> 85 | status <%= @status_log %> 86 | <% end -%> 87 | <% if @status_version != '' -%> 88 | status-version <%= @status_version %> 89 | <% end -%> 90 | dev <%= @dev %> 91 | <% if @local != '' -%> 92 | local <%= @local %> 93 | <% end -%> 94 | <% if @ipp -%> 95 | ifconfig-pool-persist <%= @name %>/vpn-ipp.txt 96 | <% end -%> 97 | <% if @server -%> 98 | server <%= @server %> 99 | <% end -%> 100 | <% if @server_ipv6 -%> 101 | server-ipv6 <%= @server_ipv6 %> 102 | <% end -%> 103 | <% if @server_bridge -%> 104 | server-bridge <%= @server_bridge %> 105 | <% end -%> 106 | <% @push.each do |item| -%> 107 | push "<%= item %>" 108 | <% end -%> 109 | <% @route.each do |item| -%> 110 | route <%= item %> 111 | <% end -%> 112 | <% @route_ipv6.each do |item| -%> 113 | route-ipv6 <%= item %> 114 | <% end -%> 115 | <% if @sndbuf -%> 116 | sndbuf <%= @sndbuf %> 117 | <% end -%> 118 | <% if @rcvbuf -%> 119 | rcvbuf <%= @rcvbuf %> 120 | <% end -%> 121 | <% if @keepalive -%> 122 | keepalive <%= @keepalive %> 123 | <% end -%> 124 | <% if @topology != '' -%> 125 | topology <%= @topology %> 126 | <% end -%> 127 | <% if @verb -%> 128 | verb <%= @verb %> 129 | <% end -%> 130 | <% if @cipher != '' -%> 131 | cipher <%= @cipher %> 132 | <% end -%> 133 | <% if @tls_cipher != '' -%> 134 | tls-cipher <%= @tls_cipher %> 135 | <% end -%> 136 | <% if @c2c -%> 137 | client-to-client 138 | <% end -%> 139 | <% if @persist_key -%> 140 | persist-key 141 | <% end -%> 142 | <% if @persist_tun -%> 143 | persist-tun 144 | <% end -%> 145 | <% if @tcp_nodelay -%> 146 | tcp-nodelay 147 | <% end -%> 148 | <% if @ccd_exclusive -%> 149 | ccd-exclusive 150 | <% end -%> 151 | <% if @pam -%> 152 | plugin <%= @pam_module_path %> "<%= @pam_module_arguments %>" 153 | <% end -%> 154 | <% if @management -%> 155 | management <%= @management_ip %> <%= @management_port %> 156 | <% end -%> 157 | <% if @up or @down or @client_connect or @client_disconnect -%> 158 | script-security 2 159 | <% end -%> 160 | <% if @up -%> 161 | up "<% unless @up =~ /^\// %><%= @_script_dir %>/<% end %><%= @up %>" 162 | <% end -%> 163 | <% if @down -%> 164 | down "<% unless @down =~ /^\// %><%= @_script_dir %>/<% end %><%= @down %>" 165 | <% end -%> 166 | <% if @client_connect -%> 167 | client-connect "<% unless @client_connect =~ /^\// %><%= @_script_dir %>/<% end %><%= @client_connect %>" 168 | <% end -%> 169 | <% if @client_disconnect -%> 170 | client-disconnect "<% unless @client_disconnect =~ /^\// %><%= @_script_dir %>/<% end %><%= @client_disconnect %>" 171 | <% end -%> 172 | <% if @username_as_common_name -%> 173 | username-as-common-name 174 | <% end -%> 175 | <% if @ldap_enabled == true -%> 176 | plugin <%= scope.lookupvar('openvpn::ldap_auth_plugin_location') %> "<%= @server_directory %>/<%= @name %>/auth/ldap.conf" 177 | <% end -%> 178 | <% if @client_cert_not_required -%> 179 | client-cert-not-required 180 | <% end -%> 181 | <% if @duplicate_cn -%> 182 | duplicate-cn 183 | <% end -%> 184 | <% if @ping_timer_rem -%> 185 | ping-timer-rem 186 | <% end -%> 187 | <% if @tls_auth -%> 188 | <% if @extca_enabled and @extca_tls_auth_key_file -%> 189 | # tls authentification 190 | tls-auth <%= @extca_tls_auth_key_file %> 191 | <% elsif !@extca_enabled -%> 192 | # tls authentification 193 | tls-auth <%= @server_directory %>/<%= @name %>/keys/ta.key 194 | <% end -%> 195 | <% unless @remote -%> 196 | key-direction 0 197 | <% else -%> 198 | key-direction 1 199 | <% end -%> 200 | <% end -%> 201 | <% if @tls_crypt -%> 202 | tls-crypt <%= @server_directory %>/<%= @name %>/keys/ta.key 203 | <% end -%> 204 | <% if @fragment != false -%> 205 | fragment <%= @fragment %> 206 | <% end -%> 207 | <% if @secret -%> 208 | secret <%= @server_directory %>/<%= @name %>/keys/pre-shared.secret 209 | <% end -%> 210 | 211 | # Additional custom options 212 | <% @custom_options.each_pair do |key, value| -%> 213 | <%= key %> <%= value %> 214 | <% end -%> 215 | -------------------------------------------------------------------------------- /templates/vars-30.epp: -------------------------------------------------------------------------------- 1 | # Easy-RSA 3 parameter settings 2 | 3 | # NOTE: If you installed Easy-RSA from your package manager, do not edit 4 | # this file in place -- instead, you should copy the entire easy-rsa directory 5 | # to another location so future upgrades do not wipe out your changes. 6 | 7 | # HOW TO USE THIS FILE 8 | # 9 | # vars.example contains built-in examples to Easy-RSA settings. You MUST name 10 | # this file "vars" if you want it to be used as a configuration file. If you 11 | # do not, it WILL NOT be automatically read when you call easyrsa commands. 12 | # 13 | # It is not necessary to use this config file unless you wish to change 14 | # operational defaults. These defaults should be fine for many uses without 15 | # the need to copy and edit the "vars" file. 16 | # 17 | # All of the editable settings are shown commented and start with the command 18 | # "set_var" -- this means any set_var command that is uncommented has been 19 | # modified by the user. If you are happy with a default, there is no need to 20 | # define the value to its default. 21 | 22 | # NOTES FOR WINDOWS USERS 23 | # 24 | # Paths for Windows *MUST* use forward slashes, or optionally double-escaped 25 | # backslashes (single forward slashes are recommended.) This means your path 26 | # to the openssl binary might look like this: 27 | # "C:/Program Files/OpenSSL-Win32/bin/openssl.exe" 28 | 29 | # A little housekeeping: DO NOT EDIT THIS SECTION 30 | # 31 | # Easy-RSA 3.x does not source into the environment directly. 32 | # Complain if a user tries to do this: 33 | if [ -z "$EASYRSA_CALLER" ]; then 34 | echo "You appear to be sourcing an Easy-RSA *vars* file. This is" >&2 35 | echo "no longer necessary and is disallowed. See the section called" >&2 36 | echo "*How to use this file* near the top comments for more details." >&2 37 | return 1 38 | fi 39 | 40 | # DO YOUR EDITS BELOW THIS POINT 41 | 42 | # This variable is used as the base location of configuration files needed by 43 | # easyrsa. More specific variables for specific files (eg: EASYRSA_SSL_CONF) 44 | # may override this default. 45 | # 46 | # The default value of this variable is the location of the easyrsa script 47 | # itself, which is also where the configuration files are located in the 48 | # easy-rsa tree. 49 | # 50 | set_var EASYRSA "<%= $server_directory -%>/<%= $openvpn_server %>/easy-rsa" 51 | 52 | set_var EASYRSA_PKI "$EASYRSA/keys" 53 | 54 | # If your OpenSSL command is not in the system PATH, you will need to define 55 | # the path here. Normally this means a full path to the executable, otherwise 56 | # you could have left it undefined here and the shown default would be used. 57 | # 58 | # Windows users, remember to use paths with forward-slashes (or escaped 59 | # back-slashes.) Windows users should declare the full path to the openssl 60 | # binary here if it is not in their system PATH. 61 | # 62 | set_var EASYRSA_OPENSSL "openssl" 63 | # 64 | # This sample is in Windows syntax -- edit it for your path if not using PATH: 65 | #set_var EASYRSA_OPENSSL "C:/Program Files/OpenSSL-Win32/bin/openssl.exe" 66 | 67 | # Define X509 DN mode. 68 | # 69 | # This is used to adjust which elements are included in the Subject field 70 | # as the DN ("Distinguished Name"). Note that in 'cn_only' mode the 71 | # Organizational fields, listed further below, are not used. 72 | # 73 | # Choices are: 74 | # cn_only - Use just a commonName value. 75 | # org - Use the "traditional" format: 76 | # Country/Province/City/Org/Org.Unit/email/commonName 77 | # 78 | set_var EASYRSA_DN "<%= $dn_mode %>" 79 | 80 | # Organizational fields (used with "org" mode and ignored in "cn_only" mode). 81 | # These are the default values for fields which will be placed in the 82 | # certificate. Do not leave any of these fields blank, although interactively 83 | # you may omit any specific field by typing the "." symbol (not valid for 84 | # email). 85 | # 86 | # NOTE: The following characters are not supported 87 | # in these "Organizational fields" by Easy-RSA: 88 | # back-tick (`) 89 | # 90 | <% if $country { -%> 91 | set_var EASYRSA_REQ_COUNTRY "<%= $country %>" 92 | <% } -%> 93 | <% if $province { -%> 94 | set_var EASYRSA_REQ_PROVINCE "<%= $province %>" 95 | <% } -%> 96 | <% if $city { -%> 97 | set_var EASYRSA_REQ_CITY "<%= $city %>" 98 | <% } -%> 99 | <% if $organization { -%> 100 | set_var EASYRSA_REQ_ORG "<%= $organization %>" 101 | <% } -%> 102 | <% if $email { -%> 103 | set_var EASYRSA_REQ_EMAIL "<%= $email %>" 104 | <% } -%> 105 | <% if $key_cn { -%> 106 | set_var EASYRSA_REQ_CN "<%= $key_cn %>" 107 | <% } -%> 108 | <% if $key_ou { -%> 109 | set_var EASYRSA_REQ_OU "<%= $key_ou %>" 110 | <% } -%> 111 | 112 | # Preserve the Distinguished Name field order 113 | # of the certificate signing request 114 | # *Only* effective in --dn-mode=org 115 | # 116 | #set_var EASYRSA_PRESERVE_DN 1 117 | 118 | # Set no password mode - This will create the entire PKI without passwords. 119 | # This can be better managed by choosing which entity private keys should be 120 | # encrypted with the following command line options: 121 | # Global option '--no-pass' or command option 'nopass'. 122 | # 123 | #set_var EASYRSA_NO_PASS 1 124 | 125 | # Choose a size in bits for your keypairs. The recommended value is 2048. 126 | # Using 2048-bit keys is considered more than sufficient for many years into 127 | # the future. Larger keysizes will slow down TLS negotiation and make key/DH 128 | # param generation take much longer. Values up to 4096 should be accepted by 129 | # most software. Only used when the crypto alg is rsa, see below. 130 | # 131 | set_var EASYRSA_KEY_SIZE <%= $ssl_key_size %> 132 | 133 | # The default crypto mode is rsa; ec can enable elliptic curve support. 134 | # Note that not all software supports ECC, so use care when enabling it. 135 | # Choices for crypto alg are: (each in lower-case) 136 | # * rsa 137 | # * ec 138 | # * ed 139 | # 140 | <% if $ssl_key_algo { -%> 141 | set_var EASYRSA_ALGO <%= $ssl_key_algo %> 142 | <% } -%> 143 | 144 | # Define the named curve, used in ec & ed modes: 145 | # 146 | <% if $ssl_key_curve { -%> 147 | set_var EASYRSA_CURVE <%= $ssl_key_curve %> 148 | <% } -%> 149 | 150 | # In how many days should the root CA key expire? 151 | # 152 | set_var EASYRSA_CA_EXPIRE <%= $ca_expire %> 153 | 154 | # In how many days should certificates expire? 155 | # 156 | set_var EASYRSA_CERT_EXPIRE <%= $key_expire %> 157 | 158 | # How many days until the Certificate Revokation List will expire. 159 | # 160 | # IMPORTANT: When the CRL expires, an OpenVPN Server which uses a 161 | # CRL will reject ALL new connections, until the CRL is replaced. 162 | # 163 | set_var EASYRSA_CRL_DAYS <%= $crl_days %> 164 | 165 | # Random serial numbers by default. 166 | # Set to 'no' for the old incremental serial numbers. 167 | # 168 | #set_var EASYRSA_RAND_SN "yes" 169 | 170 | # Cut-off window for checking expiring certificates. 171 | # 172 | #set_var EASYRSA_PRE_EXPIRY_WINDOW 90 173 | 174 | # Generate automatic subjectAltName for certificates 175 | # 176 | #set_var EASYRSA_AUTO_SAN 1 177 | 178 | # Add critical attribute to X509 fields: basicConstraints (BC), 179 | # keyUsage (KU), extendedKeyUsage (EKU) or SAN 180 | # 181 | #set_var EASYRSA_BC_CRIT 1 182 | #set_var EASYRSA_KU_CRIT 1 183 | #set_var EASYRSA_EKU_CRIT 1 184 | #set_var EASYRSA_SAN_CRIT 1 185 | 186 | # Disable automatic inline files 187 | # 188 | #set_var EASYRSA_DISABLE_INLINE 1 189 | 190 | # Support deprecated "Netscape" extensions? (choices "yes" or "no"). 191 | # The default is "no", to discourage use of deprecated extensions. 192 | # If you require this feature to use with --ns-cert-type, set this to "yes". 193 | # This support should be replaced with the more modern --remote-cert-tls 194 | # feature. If you do not use --ns-cert-type in your configs, it is safe, 195 | # and recommended, to leave this defined to "no". 196 | # When set to "yes", server-signed certs get the nsCertType=server attribute 197 | # and also get any NS_COMMENT defined below in the nsComment field. 198 | # 199 | #set_var EASYRSA_NS_SUPPORT "no" 200 | 201 | # When NS_SUPPORT is set to "yes", this field is added as the nsComment field. 202 | # Set this blank to omit it. With NS_SUPPORT set to "no" this field is ignored. 203 | # 204 | #set_var EASYRSA_NS_COMMENT "Easy-RSA Generated Certificate" 205 | 206 | # !! 207 | # NOTE: ADVANCED OPTIONS BELOW THIS POINT 208 | # PLAY WITH THEM AT YOUR OWN RISK 209 | # !! 210 | 211 | # Broken shell command aliases: If you have a largely broken shell that is 212 | # missing any of these POSIX-required commands used by Easy-RSA, you will need 213 | # to define an alias to the proper path for the command. The symptom will be 214 | # some form of a "command not found" error from your shell. This means your 215 | # shell is BROKEN, but you can hack around it here if you really need. These 216 | # shown values are not defaults: it is up to you to know what you are doing if 217 | # you touch these. 218 | # 219 | #alias awk="/alt/bin/awk" 220 | #alias cat="/alt/bin/cat" 221 | 222 | # X509 extensions directory: 223 | # If you want to customize the X509 extensions used, set the directory to look 224 | # for extensions here. Each cert type you sign must have a matching filename, 225 | # and an optional file named "COMMON" is included first when present. Note that 226 | # when undefined here, default behaviour is to look in $EASYRSA_PKI first, then 227 | # fallback to $EASYRSA for the "x509-types" dir. You may override this 228 | # detection with an explicit dir here. 229 | # 230 | #set_var EASYRSA_EXT_DIR "$EASYRSA/x509-types" 231 | 232 | # Non-functional 233 | # If you want to generate KDC certificates, you need to set the realm here. 234 | # 235 | #set_var EASYRSA_KDC_REALM "CHANGEME.EXAMPLE.COM" 236 | 237 | # OpenSSL config file: 238 | # If you need to use a specific openssl config file, you can reference it here. 239 | # Normally this file is auto-detected from a file named openssl-easyrsa.cnf 240 | # from the EASYRSA_PKI or EASYRSA dir, in that order. NOTE that this file is 241 | # Easy-RSA specific and you cannot just use a standard config file, so this is 242 | # an advanced feature. 243 | # 244 | #set_var EASYRSA_SSL_CONF "$EASYRSA_PKI/openssl-easyrsa.cnf" 245 | 246 | # Cryptographic digest to use. 247 | # Do not change this default unless you understand the security implications. 248 | # Valid choices include: md5, sha1, sha256, sha224, sha384, sha512 249 | # 250 | set_var EASYRSA_DIGEST <%= $digest %> 251 | 252 | # Batch mode. Leave this disabled unless you intend to call Easy-RSA explicitly 253 | # in batch mode without any user input, confirmation on dangerous operations, 254 | # or most output. Setting this to any non-blank string enables batch mode. 255 | # 256 | set_var EASYRSA_BATCH "1" 257 | --------------------------------------------------------------------------------