Add ocserv role
Create a self-signed CA, set up group configs, add script to allow new connections through the firewall. In the base debian role, drop the default nftables forward chain with drop policy because it clashes with this. If you enable forwarding on a debian host, make sure to configure the firewall.
This commit is contained in:
parent
a1c7be8184
commit
cf6b682cf8
|
@ -23,14 +23,6 @@ table inet filter {
|
||||||
nd-neighbor-advert, nd-neighbor-solicit, nd-router-advert, nd-router-solicit
|
nd-neighbor-advert, nd-neighbor-solicit, nd-router-advert, nd-router-solicit
|
||||||
} accept comment "accept IPv6 neighbor discovery"
|
} accept comment "accept IPv6 neighbor discovery"
|
||||||
}
|
}
|
||||||
|
|
||||||
chain forward {
|
|
||||||
type filter hook forward priority filter; policy drop
|
|
||||||
}
|
|
||||||
|
|
||||||
chain output {
|
|
||||||
type filter hook output priority filter; policy accept
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
include "/etc/nftables.d/*.nft"
|
include "/etc/nftables.d/*.nft"
|
||||||
|
|
11
roles/ocserv/README.md
Normal file
11
roles/ocserv/README.md
Normal file
|
@ -0,0 +1,11 @@
|
||||||
|
Install and configure ocserv with a script to configure nftables on (dis)connection.
|
||||||
|
|
||||||
|
Create a self‐signed CA authority for issuing user certificates. User and group are read from the CN and OU certificate subject fields, respectively. To configure VPN groups, define the variable `vpn` as follows:
|
||||||
|
|
||||||
|
"vpn": {
|
||||||
|
"network": "<VPN network>"
|
||||||
|
"routes": {
|
||||||
|
"<group>": [ "<route>", … ]
|
||||||
|
…
|
||||||
|
}
|
||||||
|
}
|
25
roles/ocserv/files/ocserv-script
Normal file
25
roles/ocserv/files/ocserv-script
Normal file
|
@ -0,0 +1,25 @@
|
||||||
|
#!/bin/sh
|
||||||
|
|
||||||
|
set -x
|
||||||
|
|
||||||
|
[ -n "$DEVICE" ] || exit 1
|
||||||
|
[ -n "$USERNAME" ] || exit 2
|
||||||
|
[ -n "$IP_REMOTE" ] || exit 3
|
||||||
|
|
||||||
|
chain="inet ocserv client-${USERNAME}"
|
||||||
|
remote_ip="${IP_REMOTE%/*}"
|
||||||
|
|
||||||
|
case "${REASON}" in
|
||||||
|
connect)
|
||||||
|
nft "add chain ${chain} { type filter hook forward priority filter; policy accept; }"
|
||||||
|
nft "flush chain ${chain}" # in case it already existed and not empty
|
||||||
|
if [ -n "$OCSERV_ROUTES" ] ; then
|
||||||
|
# convert netmask to prefix len, e.g. /255.0.0.0 to /8 and replace spaces with commas
|
||||||
|
routes="$(netmask $OCSERV_ROUTES | paste -s -d ',' | tr -d '[:space:]')"
|
||||||
|
nft "add rule ${chain} iif ${DEVICE} ip saddr ${remote_ip} ip daddr { ${routes} } mark set 0x100"
|
||||||
|
fi
|
||||||
|
;;
|
||||||
|
disconnect)
|
||||||
|
nft "delete chain ${chain}"
|
||||||
|
;;
|
||||||
|
esac
|
14
roles/ocserv/files/ocserv.nft
Normal file
14
roles/ocserv/files/ocserv.nft
Normal file
|
@ -0,0 +1,14 @@
|
||||||
|
table inet ocserv {
|
||||||
|
chain forward {
|
||||||
|
type filter hook forward priority filter + 10; policy drop;
|
||||||
|
ct state { established, related } accept
|
||||||
|
meta mark 0x100 accept
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
table ip ocserv {
|
||||||
|
chain postrouting {
|
||||||
|
type nat hook postrouting priority srcnat; policy drop;
|
||||||
|
meta mark 0x100 masquerade
|
||||||
|
}
|
||||||
|
}
|
15
roles/ocserv/handlers/main.yml
Normal file
15
roles/ocserv/handlers/main.yml
Normal file
|
@ -0,0 +1,15 @@
|
||||||
|
- name: reload nftables
|
||||||
|
service:
|
||||||
|
name: nftables
|
||||||
|
state: reloaded
|
||||||
|
when: "'handler' not in ansible_skip_tags"
|
||||||
|
|
||||||
|
- name: reload systemd
|
||||||
|
command: systemctl daemon-reload
|
||||||
|
when: "'handler' not in ansible_skip_tags"
|
||||||
|
|
||||||
|
- name: restart ocserv
|
||||||
|
service:
|
||||||
|
name: ocserv
|
||||||
|
state: restarted
|
||||||
|
when: "'handler' not in ansible_skip_tags"
|
78
roles/ocserv/tasks/main.yml
Normal file
78
roles/ocserv/tasks/main.yml
Normal file
|
@ -0,0 +1,78 @@
|
||||||
|
- name: Install packages
|
||||||
|
package:
|
||||||
|
name:
|
||||||
|
- netmask # for ocserv-script
|
||||||
|
- ocserv
|
||||||
|
install_recommends: false # don’t install dnsmasq for whatever reason
|
||||||
|
|
||||||
|
- name: Configure firewall
|
||||||
|
copy:
|
||||||
|
dest: /etc/nftables.d/
|
||||||
|
src: ocserv.nft
|
||||||
|
notify: reload nftables
|
||||||
|
|
||||||
|
- name: Generate CA key
|
||||||
|
command:
|
||||||
|
cmd: openssl genpkey -algorithm ec -pkeyopt ec_paramgen_curve:P-256 -out ca.key
|
||||||
|
chdir: /etc/ocserv
|
||||||
|
creates: ca.key
|
||||||
|
notify: restart ocserv
|
||||||
|
|
||||||
|
- name: Create CA certificate
|
||||||
|
command:
|
||||||
|
cmd: >
|
||||||
|
openssl req -key ca.key -out ca.crt -new -x509 -days 3650
|
||||||
|
-subj "/O=FRI/CN=vrata"
|
||||||
|
-addext keyUsage=critical,keyCertSign,cRLSign
|
||||||
|
chdir: /etc/ocserv
|
||||||
|
creates: ca.crt
|
||||||
|
notify: restart ocserv
|
||||||
|
|
||||||
|
# this script allows routing from the client to their networks on connection
|
||||||
|
- name: Install ocserv firewall script
|
||||||
|
copy:
|
||||||
|
dest: /usr/local/bin/
|
||||||
|
src: ocserv-script
|
||||||
|
mode: 755
|
||||||
|
|
||||||
|
- name: Configure ocserv
|
||||||
|
template:
|
||||||
|
dest: /etc/ocserv/ocserv.conf
|
||||||
|
src: ocserv.conf.j2
|
||||||
|
notify: restart ocserv
|
||||||
|
|
||||||
|
- name: Create config-per-group directory
|
||||||
|
file:
|
||||||
|
path: /etc/ocserv/config-per-group/
|
||||||
|
state: directory
|
||||||
|
|
||||||
|
- name: Configure ocserv routes for each group
|
||||||
|
template:
|
||||||
|
dest: '/etc/ocserv/config-per-group/{{ item.key }}'
|
||||||
|
src: ocserv-group.j2
|
||||||
|
loop: '{{ vpn.routes | dict2items }}'
|
||||||
|
notify: restart ocserv
|
||||||
|
|
||||||
|
- name: Create ocserv service override directory
|
||||||
|
file:
|
||||||
|
path: /etc/systemd/system/ocserv.service.d
|
||||||
|
state: directory
|
||||||
|
owner: root
|
||||||
|
group: root
|
||||||
|
mode: 0755
|
||||||
|
|
||||||
|
- name: Set ocserv to start after network is online
|
||||||
|
copy:
|
||||||
|
dest: /etc/systemd/system/ocserv.service.d/override.conf
|
||||||
|
content: |
|
||||||
|
[Unit]
|
||||||
|
After=network-online.target
|
||||||
|
Wants=network-online.target
|
||||||
|
notify: reload systemd
|
||||||
|
|
||||||
|
- name: Enable IP forwarding
|
||||||
|
sysctl:
|
||||||
|
name: net.ipv4.ip_forward
|
||||||
|
value: 1
|
||||||
|
sysctl_file: /etc/sysctl.d/99-local.conf
|
||||||
|
sysctl_set: true
|
3
roles/ocserv/templates/ocserv-group.j2
Normal file
3
roles/ocserv/templates/ocserv-group.j2
Normal file
|
@ -0,0 +1,3 @@
|
||||||
|
{% for route in item.value %}
|
||||||
|
route = {{ route }}
|
||||||
|
{% endfor %}
|
26
roles/ocserv/templates/ocserv.conf.j2
Normal file
26
roles/ocserv/templates/ocserv.conf.j2
Normal file
|
@ -0,0 +1,26 @@
|
||||||
|
listen-host = {{ dns_name }}
|
||||||
|
tcp-port = 443
|
||||||
|
server-cert = /etc/letsencrypt/live/{{ dns_name }}/fullchain.pem
|
||||||
|
server-key = /etc/letsencrypt/live/{{ dns_name }}/privkey.pem
|
||||||
|
|
||||||
|
run-as-user = ocserv
|
||||||
|
run-as-group = ocserv
|
||||||
|
socket-file = /run/ocserv-socket
|
||||||
|
chroot-dir = /var/lib/ocserv
|
||||||
|
connect-script = /usr/local/bin/ocserv-script
|
||||||
|
disconnect-script = /usr/local/bin/ocserv-script
|
||||||
|
|
||||||
|
device = vpns
|
||||||
|
cisco-client-compat = true
|
||||||
|
dtls-legacy = true
|
||||||
|
compression = true
|
||||||
|
isolate-workers = true
|
||||||
|
|
||||||
|
auth = certificate
|
||||||
|
ca-cert = /etc/ocserv/ca.crt
|
||||||
|
cert-user-oid = 2.5.4.3
|
||||||
|
cert-group-oid = 2.5.4.11
|
||||||
|
config-per-group = /etc/ocserv/config-per-group/
|
||||||
|
default-domain = {{ domain }}
|
||||||
|
ipv4-network = {{ vpn.network }}
|
||||||
|
route = {{ vpn.network }}
|
Loading…
Reference in a new issue