Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Make client settings match server settings and improve docs (#189) #190

Open
wants to merge 2 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,9 @@ This file is used to list changes made in each version of the openvpn cookbook.

## Unreleased

- Make client config match server config (fixes [#189](https://github.com/sous-chefs/openvpn/issues/189))
- Document usage of `openvpn_user` with examples for `additional_vars`

## 7.0.20 - *2024-05-06*

## 7.0.19 - *2024-05-06*
Expand Down
51 changes: 49 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -58,7 +58,7 @@ These attributes are set by the cookbook by default.
- `node['openvpn']['configure_default_server']` - Boolean. Set this to false if you want to create all of your "conf" files with the LWRP.
- `node['openvpn']['git_package']` - Boolean. Whether to use the `openvpn-git` package (Arch Linux only, default false).
- `node['openvpn']['client_prefix']` - String. Name of the config that is created for clients. When imported into most vpn clients, this is the name that will be displayed for the connection. Default is 'vpn-prod'.
- `node['openvpn']['cookbook_user_conf']` - String. The cookbook used by the `openvpn::users` recipe for the `client.conf.erb` template. You can override this to your own, such as your wrapper cookbook. Default is `'openvpn'`.
- `node['openvpn']['cookbook_user_conf']` - String. The cookbook used by the `openvpn::users` recipe for the `client.conf.erb` template. You can override this to your own, such as your wrapper cookbook. Default is `'openvpn'`. See [Customizing user configuration](#customizing-user-configuration) under the [openvpn_user resource](#openvpn_user) section
- `node['openvpn']['key_dir']` - Location to store keys, certificates and related files. Default `/etc/openvpn/keys`.
- `node['openvpn']['signing_ca_cert']` - CA certificate for signing, default `/etc/openvpn/keys/ca.crt`
- `node['openvpn']['signing_ca_key']` - CA key for signing, default `/etc/openvpn/keys/ca.key`
Expand Down Expand Up @@ -198,7 +198,54 @@ This cookbook also provides an 'up' script that runs when OpenVPN is started. Th

### openvpn_user

Implements a resource for creation of users and bundles.
Implements a resource for creation of users and bundles. User configuration will attempt to match the server configuration as best as possible,
by matching node attributes like `node['openvpn']['config']['compress']` and `node['openvpn']['config']['cipher']`. Reasonable default configuration
for the user bundle is specified otherwise.

By default, an OpenVPN user _bundle_ is created, which is a gzipped TAR file (`.tgz` archive) containing the user configuration and the public/private
keys. This is controlled by the `create_bundle` attribute of the `openvpn_user` resource; pass `create_bundle false` if you prefer to have inline `.ovpn`
files created, containing the public and private keys all inside one OpenVPN config file.

#### Customizing user configuration

If the provided OpenVPN configuration does not meet your needs, either because you need different configuration directives, or you want to add directives which
are not present, you can use the node attribute `node['openvpn']['cookbook_user_conf']` to look for the template files in a different cookbook, E.G. in your
wrapper cookbook.

If you only need _additional_ directives, you can use the `additional_vars` attribute of the `openvpn_user` resource to pass additional template variables to your
custom template. This way, you can render the user configuration from this cookbook using a partial, and append (or prepend) your own config inside your template.

#### Example

Adding a 2FA via a hardware token

`cookbooks/vpn_wrapper/recipes/user.rb`:

```ruby
override["openvpn"]["cookbook_user_conf"] => "vpn_wrapper"
openvpn_user "VPN User Bundle" do
client_name "my_user"
additional_vars(
static_challenge: %{"Touch your hardware token now:" 0}
)
end
```

`cookbooks/vpn_wrapper/templates/client.conf.erb`:

```ruby
<%= render "client.conf.erb", cookbook: "openvpn" %>
auth-user-pass
static-challenge <%= @static_challenge %>
```

`cookbooks/vpn_wrapper/templates/client-inline.conf.erb`:

```ruby
<%= render "client-inline.conf.erb", cookbook: "openvpn" %>
auth-user-pass
static-challenge <%= @static_challenge %>
```

### openvpn_config

Expand Down
10 changes: 8 additions & 2 deletions resources/user.rb
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,11 @@
destination_path = ::File.expand_path(new_resource.destination || key_dir)
bundle_filename = "#{new_resource.client_name}.tar.gz"
bundle_full_path = ::File.expand_path(::File.join(destination_path, bundle_filename))
compression = if node['openvpn']['config']['compress']
node['openvpn']['config']['compress']
elsif node['openvpn']['config']['comp-lzo']
'lzo'
end

execute "generate-openvpn-#{new_resource.client_name}" do
command "umask 077 && ./pkitool #{new_resource.client_name}"
Expand Down Expand Up @@ -51,15 +56,15 @@

template "#{destination_path}/#{client_file_basename}.conf" do
source 'client.conf.erb'
cookbook node['openvpn']['cookbook_user_conf']
cookbook lazy { node['openvpn']['cookbook_user_conf'] }
variables(client_cn: new_resource.client_name)
notifies :delete, "file[#{cleanup_name}]", :immediately
only_if { new_resource.create_bundle }
end

template "#{destination_path}/#{client_file_basename}.ovpn" do
source new_resource.create_bundle ? 'client.conf.erb' : 'client-inline.conf.erb'
cookbook node['openvpn']['cookbook_user_conf']
cookbook lazy { node['openvpn']['cookbook_user_conf'] }
if new_resource.create_bundle
variables(client_cn: new_resource.client_name)
else
Expand All @@ -71,6 +76,7 @@
ca: IO.read(ca_cert_path),
cert: IO.read(cert_path),
key: IO.read(key_path),
compression: compression,
}.merge(new_resource.additional_vars) { |key, oldval, newval| oldval } # rubocop:disable Lint/UnusedBlockArgument
end
)
Expand Down
11 changes: 11 additions & 0 deletions templates/client-inline.conf.erb
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,17 @@ resolv-retry infinite
nobind
persist-key
persist-tun
<% if @compression -%>
compress <%= @compression %>
<% end %>
<%
%w(cipher tls-cipher auth keysize link-mtu).each do |conf|
if node['openvpn']['config'][conf]
%><%= "#{conf} #{node['openvpn']['config'][conf]}" %>
<%
end
end
-%>
verb 3
<ca>
<%= @ca -%>
Expand Down
15 changes: 13 additions & 2 deletions templates/client.conf.erb
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,18 @@ persist-tun
ca ca.crt
cert <%= @client_cn %>.crt
key <%= @client_cn %>.key
<% if @compression -%>
<%= @compression %>
<% end %>
<%
%w(cipher tls-cipher auth keysize link-mtu).each do |conf|
if node['openvpn']['config'][conf]
%><%= "#{conf} #{node['openvpn']['config'][conf]}" %>
<%
end
end
-%>
verb 3
<% if node['openvpn']['server_verification'] %>
<% if node['openvpn']['server_verification'] -%>
<%= node['openvpn']['server_verification'] %>
<% end %>
<% end -%>
Loading