initial commit

This commit is contained in:
ludal 2020-08-17 11:48:37 +02:00
parent 06cb1b5acc
commit 01e4b0efa1
12 changed files with 488 additions and 1 deletions

View File

@ -1 +1,93 @@
# ansible-role-openvpn
openvpn
========
The present role :
- installs OpenVPN and dependancies
- configures it as a server
- creates client certificates and configuration file
It has been tested on :
- Debian 9
- Debian 10
Role variables
--------------
| Variable | Type | Choices | Default | Comment |
|------------------------------------|---------|--------------|-------------------------------------------------------------------------------|----------------------------------------------------------------------------|
| openvpn_user | string | | nobody | Set the OpenVPN service user. |
| openvpn_group | string | | nogroup | Set the OpenVPN service group. |
| openvpn_public_ip | string | | | Set the OpenVPN IP on which it will be reachable. |
| openvpn_port | int | | 1194 | Which TCP/UDP port should OpenVPN listen on ? |
| openvpn_proto | string | | tcp | TCP or UDP server? |
| openvpn_dev | string | | tun | Set the OpenVPN type off internal network device (tun or tap). |
| openvpn_ip_range | string | | 10.8.0.0 | Set the OpenVPN internal IP range. |
| openvpn_ip_netmask | string | | 255.255.255.0 | Set the OpenVPN internal netmask. |
| openvpn_compress | string | | lz4-v2 | Set the kind of compression type. |
| openvpn_maxclients | int | | 10 | Set number of maximum clients allowed. |
| openvpn_keepalive_ping | int | | 10 | Set "keepalive" ping interval in seconds. |
| openvpn_keepalive_timeout | int | | 120 | Set "keepalive" timeout in seconds. |
| openvpn_cipher | string | | AES-256-GCM | Set "cipher" option for server and client. |
| openvpn_auth | string | | SHA384 | Set "auth" option for authentication algoritm. |
| openvpn_tls_cipher | string | | TLS-ECDHE-RSA-WITH-AES-256-GCM-SHA384:TLS-ECDHE-ECDSA-WITH-AES-256-GCM-SHA384 | Set "tls-cipher' option. |
| openvpn_client_to_client | boolean | true , false | false | Allow clients to "see" eachother. By default client only see the server. |
| openvpn_push_route | list | | [] | List of route to push in order to allow client access. |
| openvpn_verbosity | int | | 3 | Set the log verbosity. |
| openvpn_mute    | int | | 20 | Set the number of consecutive messages in the same category in the log. |
| openvpn_tls_auth | boolean | true , false | false | Enable or disable tls authentication. |
| openvpn_log_status | string | | /var/log/openvpn-status.log | Path of the status log file. File is truncated and rewritten evert minute. |
| openvpn_log_append | string | | /var/log/openvpn.log | Path of log file. |
| openvpn_easyrsa_req_country | string | | | Easy-RSA variable "EASYRSA_REQ_COUNTRY" |
| openvpn_easyrsa_req_province | string | | | Esay-RSA variable "EASYRSA_REQ_PROVINCE" |
| openvpn_easyrsa_req_city | string | | | Esay-RSA variable "EASYRSA_REQ_CITY" |
| openvpn_easyrsa_req_org | string | | | Esay-RSA variable "EASYRSA_REQ_ORG" |
| openvpn_easyrsa_req_email | string | | | Esay-RSA variable "EASYRSA_REQ_EMAIL" |
| openvpn_easyrsa_req_ou | string | | | Esay-RSA variable "EASYRSA_REQ_OU" |
Dependencies
------------
Does not depend on any other roles.
Example Playbook
----------------
- hosts: vpn
ignore_errors: "{{ ansible_check_mode }}" # ignore errors only in check mode !
roles:
- { role: brainsys.openvpn, tags: ['openvpn'] }
Example variables
-----------------
openvpn_public_ip: a.b.c.d
openvpn_client_to_client: false
openvpn_proto: 'tcp'
openvpn_ip_range: '10.8.0.0'
openvpn_push_route:
- ip: a.b.c.d
netmask: 255.255.255.0
openvpn_client:
- name: client1
ip: 10.8.0.11
- name: client2
ip: 10.8.0.12
TODO
----
- sets up networking / firewall
- handle delegate_to instead of lookfile when creating client configuration
License
-------
GPLv3
Author Information
------------------
Written by Ludovic Cartier <ludovic.cartier@brainsys.io>

31
defaults/main.yml Normal file
View File

@ -0,0 +1,31 @@
---
openvpn_asserts: True
openvpn_user: 'nobody'
openvpn_group: 'nogroup'
openvpn_ip_range: '10.8.0.0'
openvpn_ip_netmask: '255.255.255.0'
openvpn_port: 1194
openvpn_proto: 'tcp'
openvpn_dev: 'tun'
openvpn_compress: 'lz4-v2'
openvpn_client_to_client: False
openvpn_maxclients: 10
openvpn_keepalive_ping: 10
openvpn_keepalive_timeout: 120
openvpn_tls_auth: False
openvpn_cipher: 'AES-256-GCM'
openvpn_auth: 'SHA384'
openvpn_tls_cipher: 'TLS-ECDHE-RSA-WITH-AES-256-GCM-SHA384:TLS-ECDHE-ECDSA-WITH-AES-256-GCM-SHA384'
openvpn_log_verbosity: 3
openvpn_mute: 20
openvpn_log_status: '/var/log/openvpn-status.log'
openvpn_log_append: '/var/log/openvpn.log'

13
handlers/main.yml Normal file
View File

@ -0,0 +1,13 @@
---
- name: 'openvpn | start service'
systemd:
name: openvpn@{{ ansible_hostname }}.service
state: started
enabled: yes
tags: ['openvpn']
- name: 'openvpn | restart service'
systemd:
name: openvpn@{{ ansible_hostname }}.service
enabled: yes
tags: ['openvpn']

48
tasks/asserts.yml Normal file
View File

@ -0,0 +1,48 @@
---
- name: 'openvpn | validate | ensure Easy-RSA request Country is defined'
assert:
that: openvpn_easyrsa_req_country is defined
msg: '<openvpn_easyrsa_req_country> is mandatory and must be defined.'
when:
- openvpn_server
- openvpn_client
- name: 'openvpn | validate | ensure Easy-RSA request Province is defined'
assert:
that: openvpn_easyrsa_req_province is defined
msg: '<openvpn_easyrsa_req_province> is mandatory and must be defined'
when:
- openvpn_server
- openvpn_client
- name: 'openvpn | validate | ensure Easy-RSA request City is defined'
assert:
that: openvpn_easyrsa_req_city is defined
msg: '<openvpn_easyrsa_req_city> is mandatory and must be defined'
when:
- openvpn_server
- openvpn_client
- name: 'openvpn | validate | ensure Easy-RSA request Organization is defined'
assert:
that: openvpn_easyrsa_req_org is defined
msg: '<openvpn_easyrsa_req_org> is mandatory and must be defined'
when:
- openvpn_server
- openvpn_client
- name: 'openvpn | validate | ensure Easy-RSA request Email is defined'
assert:
that: openvpn_easyrsa_req_email is defined
msg: '<openvpn_easyrsa_req_email> is mandatory and must be defined'
when:
- openvpn_server
- openvpn_client
- name: 'openvpn | validate | ensure Easy-RSA request OU is defined'
assert:
that: openvpn_easyrsa_req_ou is defined
msg: '<openvpn_easyrsa_req_ou> is mandatory and must be defined'
when:
- openvpn_server
- openvpn_client

56
tasks/client.yml Normal file
View File

@ -0,0 +1,56 @@
---
- name: 'openvpn | create client directory'
file:
path: /etc/openvpn/client/{{ item.name }}/
state: directory
mode: '0755'
loop: "{{ openvpn_client }}"
tags: ['openvpn', 'openvpn_client']
- name: 'openvpn | create client request'
command: ./easyrsa --batch --req-cn={{ item.name }} gen-req {{ item.name }} nopass
args:
chdir: /etc/openvpn/{{ ansible_hostname }}/easy-rsa
environment:
EASYRSA_BATCH: 1
loop: "{{ openvpn_client }}"
tags: ['openvpn', 'openvpn_client']
- name: 'openvpn | create client certificates'
command: ./easyrsa sign-req client {{ item.name }}
args:
chdir: /etc/openvpn/{{ ansible_hostname }}/easy-rsa
environment:
EASYRSA_BATCH: 1
loop: "{{ openvpn_client }}"
tags: ['openvpn', 'openvpn_client']
- name: 'openvpn | copy client certificate'
copy:
src: "/etc/openvpn/{{ ansible_hostname }}/easy-rsa/pki/issued/{{ item.name }}.crt"
dest: "/etc/openvpn/client/{{ item.name }}/{{ item.name }}.crt"
remote_src: yes
loop: "{{ openvpn_client }}"
tags: ['openvpn', 'openvpn_client']
- name: 'openvpn | copy client private key'
copy:
src: "/etc/openvpn/{{ ansible_hostname }}/easy-rsa/pki/private/{{ item.name }}.key"
dest: "/etc/openvpn//client/{{ item.name }}/{{ item.name }}.key"
remote_src: yes
loop: "{{ openvpn_client }}"
tags: ['openvpn', 'openvpn_client']
- name: 'openvpn | create client configuration file'
template:
src: "../data/openvpn/client.ovpn.j2"
dest: "/etc/openvpn/client/{{ item.name }}/{{ item.name }}.ovpn"
when: openvpn_client is defined
loop: "{{ openvpn_client }}"
vars:
loop_cert: "{{ lookup('file', '/etc/openvpn/client/' + item.name + '/' + item.name + '.crt') }}"
loop_key : "{{ lookup('file', '/etc/openvpn/client/' + item.name + '/' + item.name + '.key') }}"
loop_ca : "{{ lookup('file', '/etc/openvpn/' + ansible_hostname + '/keys/ca.crt') }}"
loop_ta : "{{ lookup('file', '/etc/openvpn/' + ansible_hostname + '/keys/ta.key') }}"
tags: ['openvpn', 'openvpn_client']

39
tasks/install.yml Normal file
View File

@ -0,0 +1,39 @@
---
- name: 'openvpn | update APT Cache'
apt:
update_cache: yes
cache_valid_time: 3600
tags: ['openvpn', 'openvpn_install']
- name: 'openvpn | install packages'
apt:
name:
- openvpn
- openssl
- easy-rsa
state: present
tags: ['openvpn', 'openvpn_install']
- name: 'openvpn | create directories'
file:
path: /etc/openvpn/{{ ansible_hostname }}/keys
state: directory
mode: '0755'
tags: ['openvpn', 'openvpn_install']
- name: 'openvpn | copy easy-rsa'
copy:
src: /usr/share/easy-rsa
dest: /etc/openvpn/{{ ansible_hostname }}
owner: root
group: root
tags: ['openvpn', 'openvpn_install']
- name: 'openvpn | chmod +x easyrsa'
file:
path: /etc/openvpn/{{ ansible_hostname }}/easy-rsa/easyrsa
owner: root
group: root
mode: 0755
tags: ['openvpn', 'openvpn_install']

19
tasks/main.yml Normal file
View File

@ -0,0 +1,19 @@
---
- name: 'Check if ansible version >= 2.7.'
assert:
that: "ansible_version.full is version_compare(2.7, '>=')"
msg: "Une version Ansible 2.7 ou supérieur est nécessaire pour utiliser cette version du rôle."
tags: always
- include_tasks: asserts.yml
when: openvpn_asserts
tags: always
- include_tasks: install.yml
tags: ['openvpn','openvpn_install']
- include_tasks: server.yml
tags: ['openvpn', 'openvpn_server']
- include_tasks: client.yml
tags: ['openvpn', 'openvpn_client']

69
tasks/server.yml Normal file
View File

@ -0,0 +1,69 @@
---
- name: 'openvpn | copy vars'
template:
src: "../data/openvpn/vars.j2"
dest: "/etc/openvpn/{{ ansible_hostname }}/easy-rsa/vars"
tags: ['openvpn', 'openvpn_server']
- name: 'openvpn | cleanup everything'
command: "./easyrsa init-pki"
args:
chdir: /etc/openvpn/{{ ansible_hostname }}/easy-rsa
tags: ['openvpn', 'openvpn_server']
- name: 'openvpn | create random file'
command: "dd if=/dev/urandom of=pki/.rnd bs=256 count=1"
args:
chdir: /etc/openvpn/{{ ansible_hostname }}/easy-rsa
tags: ['openvpn', 'openvpn_server']
- name: 'openvpn | generate certificates'
command: "{{ item }}"
args:
chdir: /etc/openvpn/{{ ansible_hostname }}/easy-rsa
environment:
EASYRSA_BATCH: 1
with_items:
- ./easyrsa build-ca nopass
- ./easyrsa gen-dh
- ./easyrsa build-server-full {{ ansible_hostname }} nopass
tags: ['openvpn', 'openvpn_server']
- name: 'openvpn | copy certificates'
copy:
src: "{{ item }}"
dest: "/etc/openvpn/{{ ansible_hostname }}/keys"
remote_src: yes
with_items:
- /etc/openvpn/{{ ansible_hostname }}/easy-rsa/pki/dh.pem
- /etc/openvpn/{{ ansible_hostname }}/easy-rsa/pki/private/{{ ansible_hostname }}.key
- /etc/openvpn/{{ ansible_hostname }}/easy-rsa/pki/issued/{{ ansible_hostname }}.crt
- /etc/openvpn/{{ ansible_hostname }}/easy-rsa/pki/ca.crt
tags: ['openvpn', 'openvpn_server']
- name: 'openvpn | generate ta.key'
command: "openvpn --genkey --secret /etc/openvpn/{{ ansible_hostname }}/keys/ta.key"
tags: ['openvpn', 'openvpn_server']
- name: 'openvpn | chmod ta.key'
file:
path: "/etc/openvpn/{{ ansible_hostname }}/keys/ta.key"
owner: root
group: root
mode: 0644
tags: ['openvpn', 'openvpn_server']
- name: 'openvpn | configure ifconfig-pool-persist'
template:
src: "../data/openvpn/ipp.txt.j2"
dest: "/etc/openvpn/{{ ansible_hostname }}/ipp.txt"
when: openvpn_client is defined
tags: ['openvpn', 'openvpn_server']
- name: 'openvpn | copy server configuration'
template:
src: "../data/openvpn/server.conf.j2"
dest: "/etc/openvpn/{{ ansible_hostname }}.conf"
tags: ['openvpn', 'openvpn_server']
notify: openvpn-restart

43
templates/client.ovpn.j2 Normal file
View File

@ -0,0 +1,43 @@
# alterway - openvpn client configuration
client
dev {{ openvpn_dev }}
proto {{ openvpn_proto) }}
remote {{ openvpn_public_ip }} {{ openvpn_port }}
resolv-retry infinite
nobind
persist-key
persist-tun
ca [inline]
cert [inline]
key [inline]
{% if openvpn_tls_auth is defined and openvpn_tls_auth == "true" %}
tls-auth [inline] 1
{% endif %}
cipher {{ openvpn_cipher }}
auth {{ openvpn_auth }}
tls-cipher {{ openvpn_tls_cipher }}
compress {{ openvpn_compress }}
<ca>
{{ loop_ca }}
</ca>
<cert>
{{ loop_cert }}
</cert>
<key>
{{ loop_key }}
</key>
{% if openvpn_tls_auth is defined and openvpn_tls_auth == "true" %}
<tls-auth>
{{ loop_ta }}
</tls-auth>
{% endif %}

8
templates/ipp.txt.j2 Normal file
View File

@ -0,0 +1,8 @@
# ansible managed - DO NOT EDIT MANUALLY !!!
# official documentation - https://openvpn.net/community-resources/reference-manual-for-openvpn-2-4/
#
# <user>,<ip_address>
{% for user in openvpn_client %}
{{ user.name }},{{ user.ip }}
{% endfor %}

54
templates/server.conf.j2 Normal file
View File

@ -0,0 +1,54 @@
# ansible managed - DO NOT EDIT MANUALLY !!!
# official documentation - https://openvpn.net/community-resources/reference-manual-for-openvpn-2-4/
user {{ openvpn_user }}
group {{ openvpn_group }}
server {{ openvpn_ip_range }} {{ openvpn_ip_netmask }}
port {{ openvpn_port }}
proto {{ openvpn_proto }}
dev {{ openvpn_dev }}
keepalive {{ openvpn_keepalive_ping }} {{ openvpn_keepalive_timeout }}
ca /etc/openvpn/{{ ansible_hostname }}/keys/ca.crt
cert /etc/openvpn/{{ ansible_hostname }}/keys/{{ ansible_hostname }}.crt
key /etc/openvpn/{{ ansible_hostname }}/keys/{{ ansible_hostname }}.key
dh /etc/openvpn/{{ ansible_hostname }}/keys/dh.pem
{% if openvpn_tls_auth is defined and openvpn_tls_auth == "true" %}
tls-auth /etc/openvpn/{{ ansible_hostname }}/keys/ta.key 0
{% endif %}
cipher {{ openvpn_cipher }}
auth {{ openvpn_auth }}
tls-cipher {{ openvpn_tls_cipher }}
compress {{ openvpn_compress }}
push "compress {{ openvpn_compress }}"
max-clients {{ openvpn_maxclients }}
ifconfig-pool-persist /etc/openvpn/{{ ansible_hostname }}/ipp.txt
{% if openvpn_push_route is defined %}
{% for route in openvpn_push_route %}
push "route {{ route.ip }} {{ route.netmask }}"
{% endfor %}
{% endif %}
persist-key
persist-tun
verb {{ openvpn_log_verbosity }}
status {{ openvpn_log_status }}
log-append {{ openvpn_log_append }}
mute {{ openvpn_mute }}
{% if openvpn_proto is defined and openvpn_proto == "udp" %}
explicit-exit-notify 5
{% endif %}
{% if openvpn_client_to_client is defined and openvpn_client_to_client is sameas true %}
client-to-client
{% endif %}

15
templates/vars.j2 Normal file
View File

@ -0,0 +1,15 @@
# ansible managed - DO NOT EDIT MANUALLY !!!
if [ -z "$EASYRSA_CALLER" ]; then
echo "You appear to be sourcing an Easy-RSA 'vars' file." >&2
echo "This is no longer necessary and is disallowed. See the section called" >&2
echo "'How to use this file' near the top comments for more details." >&2
return 1
fi
set_var EASYRSA_REQ_COUNTRY "{{ openvpn_easyrsa_req_country }}"
set_var EASYRSA_REQ_PROVINCE "{{ openvpn_easyrsa_req_province }}"
set_var EASYRSA_REQ_CITY "{{ openvpn_easyrsa_req_city }}"
set_var EASYRSA_REQ_ORG "{{ openvpn_easyrsa_req_org }}"
set_var EASYRSA_REQ_EMAIL "{{ openvpn_easyrsa_req_email }}"
set_var EASYRSA_REQ_OU "{{ openvpn_easyrsa_req_ou }}"