From b2bf1592189fb9298f2a68272418a132a73f37bf Mon Sep 17 00:00:00 2001 From: Christian Poessinger Date: Sat, 3 Jul 2021 15:52:26 +0200 Subject: ipsec: T1210: T1251: IKEv2 road-warrior support set vpn ipsec esp-group ESP-RW compression 'disable' set vpn ipsec esp-group ESP-RW lifetime '3600' set vpn ipsec esp-group ESP-RW pfs 'disable' set vpn ipsec esp-group ESP-RW proposal 10 encryption 'aes256' set vpn ipsec esp-group ESP-RW proposal 10 hash 'sha256' set vpn ipsec esp-group ESP-RW proposal 20 encryption 'aes256' set vpn ipsec esp-group ESP-RW proposal 20 hash 'sha1' set vpn ipsec ike-group IKE-RW key-exchange 'ikev2' set vpn ipsec ike-group IKE-RW lifetime '10800' set vpn ipsec ike-group IKE-RW mobike 'enable' set vpn ipsec ike-group IKE-RW proposal 10 dh-group '2' set vpn ipsec ike-group IKE-RW proposal 10 encryption 'aes256' set vpn ipsec ike-group IKE-RW proposal 10 hash 'sha1' set vpn ipsec ike-group IKE-RW proposal 20 dh-group '2' set vpn ipsec ike-group IKE-RW proposal 20 encryption 'aes128' set vpn ipsec ike-group IKE-RW proposal 20 hash 'sha1' set vpn ipsec ipsec-interfaces interface 'dum0' set vpn ipsec remote-access rw authentication id 'vyos' set vpn ipsec remote-access rw authentication local-users username vyos password vyos set vpn ipsec remote-access rw authentication x509 ca-certificate 'peer_172-18-254-202' set vpn ipsec remote-access rw authentication x509 certificate 'peer_172-18-254-202' set vpn ipsec remote-access rw description 'asdf' set vpn ipsec remote-access rw esp-group 'ESP-RW' set vpn ipsec remote-access rw ike-group 'IKE-RW' --- data/templates/ipsec/swanctl.conf.tmpl | 18 +++++++++ data/templates/ipsec/swanctl/remote_access.tmpl | 37 +++++++++++++++++ interface-definitions/vpn_ipsec.xml.in | 53 +++++++++++++++++++++++++ src/conf_mode/vpn_ipsec.py | 42 ++++++++++---------- 4 files changed, 129 insertions(+), 21 deletions(-) create mode 100644 data/templates/ipsec/swanctl/remote_access.tmpl diff --git a/data/templates/ipsec/swanctl.conf.tmpl b/data/templates/ipsec/swanctl.conf.tmpl index cafe52e78..15c035688 100644 --- a/data/templates/ipsec/swanctl.conf.tmpl +++ b/data/templates/ipsec/swanctl.conf.tmpl @@ -1,6 +1,7 @@ ### Autogenerated by vpn_ipsec.py ### {% import 'ipsec/swanctl/profile.tmpl' as profile_tmpl %} {% import 'ipsec/swanctl/peer.tmpl' as peer_tmpl %} +{% import 'ipsec/swanctl/remote_access.tmpl' as remote_access_tmpl %} connections { {% if profile is defined %} @@ -13,6 +14,11 @@ connections { {{ peer_tmpl.conn(peer, peer_conf, ike_group, esp_group) }} {% endfor %} {% endif %} +{% if remote_access is defined and remote_access is not none %} +{% for rw, rw_conf in remote_access.items() if rw_conf.disable is not defined %} +{{ remote_access_tmpl.conn(rw, rw_conf, ike_group, esp_group) }} +{% endfor %} +{% endif %} } secrets { @@ -60,5 +66,17 @@ secrets { {% endif %} {% endfor %} {% endif %} +{% if remote_access is defined %} +{% for ra, ra_conf in remote_access.items() if remote_access is defined %} +{% if ra_conf.authentication is defined and ra_conf.authentication.local_users is defined and ra_conf.authentication.local_users.username is defined %} +{% for user, user_conf in ra_conf.authentication.local_users.username.items() if user_conf.disable is not defined %} + eap-{{ ra }}-{{ user }} { + secret = "{{ user_conf.password }}" + id-{{ ra }}-{{ user }} = "{{ user }}" + } +{% endfor %} +{% endif %} +{% endfor %} +{% endif %} } diff --git a/data/templates/ipsec/swanctl/remote_access.tmpl b/data/templates/ipsec/swanctl/remote_access.tmpl new file mode 100644 index 000000000..89f6e343e --- /dev/null +++ b/data/templates/ipsec/swanctl/remote_access.tmpl @@ -0,0 +1,37 @@ +{% macro conn(name, rw_conf, ike_group, esp_group) %} +{# peer needs to reference the global IKE configuration for certain values #} +{% set ike = ike_group[rw_conf.ike_group] %} +{% set esp = esp_group[rw_conf.esp_group] %} + ra-{{ name }} { + remote_addrs = %any + local_addrs = %any + proposals = {{ ike_group[rw_conf.ike_group] | get_esp_ike_cipher | join(',') }} + version = {{ ike.key_exchange[4:] if ike is defined and ike.key_exchange is defined else "0" }} + send_certreq = no + rekey_time = {{ ike.lifetime }}s + keyingtries = 0 + local { + auth = pubkey +{% if rw_conf.authentication is defined and rw_conf.authentication.id is defined and rw_conf.authentication.use_x509_id is not defined %} + id = "{{ rw_conf.authentication.id }}" +{% endif %} +{% if rw_conf.authentication is defined and rw_conf.authentication.x509 is defined and rw_conf.authentication.x509.certificate is defined %} + certs = {{ rw_conf.authentication.x509.certificate }}.pem +{% endif %} + } + remote { + auth = eap-mschapv2 + id = %any + eap_id = %any + } + children { + ikev2-vpn { + esp_proposals = {{ esp | get_esp_ike_cipher | join(',') }} + rekey_time = {{ esp.lifetime }}s + rand_time = 540s + local_ts = 0.0.0.0/0 + dpd_action = clear + } + } + } +{% endmacro %} diff --git a/interface-definitions/vpn_ipsec.xml.in b/interface-definitions/vpn_ipsec.xml.in index ff60bb82f..ef3b05e29 100644 --- a/interface-definitions/vpn_ipsec.xml.in +++ b/interface-definitions/vpn_ipsec.xml.in @@ -705,6 +705,59 @@ #include + + + Remote access IKEv2 VPN + + + + + Authentication for remote access + + + #include + #include + + + Local user authentication for PPPoE server + + + + + User name for authentication + + + #include + + + Password for authentication + + + + + + + + + #include + #include + #include + #include + + + Timeout to close connection if no data is transmitted + + u32:10-86400 + Timeout in seconds (default 28800) + + + + + + 28800 + + + Site-to-site VPN diff --git a/src/conf_mode/vpn_ipsec.py b/src/conf_mode/vpn_ipsec.py index d1b29ee9a..50223320d 100755 --- a/src/conf_mode/vpn_ipsec.py +++ b/src/conf_mode/vpn_ipsec.py @@ -34,7 +34,6 @@ from vyos.template import render from vyos.validate import is_ipv6_link_local from vyos.util import call from vyos.util import dict_search -from vyos.util import process_named_running from vyos.util import run from vyos.xml import defaults from vyos import ConfigError @@ -81,6 +80,7 @@ def get_config(config=None): # added in a more fine grained way later on del default_values['esp_group'] del default_values['ike_group'] + del default_values['remote_access'] ipsec = dict_merge(default_values, ipsec) if 'esp_group' in ipsec: @@ -88,12 +88,16 @@ def get_config(config=None): for group in ipsec['esp_group']: ipsec['esp_group'][group] = dict_merge(default_values, ipsec['esp_group'][group]) - if 'ike_group' in ipsec: default_values = defaults(base + ['ike-group']) for group in ipsec['ike_group']: ipsec['ike_group'][group] = dict_merge(default_values, ipsec['ike_group'][group]) + if 'remote_access' in ipsec: + default_values = defaults(base + ['remote-access']) + for rw in ipsec['remote_access']: + ipsec['remote_access'][rw] = dict_merge(default_values, + ipsec['remote_access'][rw]) ipsec['dhcp_no_address'] = {} ipsec['interface_change'] = leaf_node_changed(conf, base + ['ipsec-interfaces', @@ -109,8 +113,6 @@ def get_config(config=None): get_first_key=True, no_tag_node_value_mangle=True) - import pprint - pprint.pprint(ipsec) return ipsec def get_rsa_local_key(ipsec): @@ -326,6 +328,11 @@ def generate(ipsec): if not os.path.exists(KEY_PATH): os.mkdir(KEY_PATH, mode=0o700) + if 'remote_access' in ipsec: + for rw, rw_conf in ipsec['remote_access'].items(): + if 'authentication' in rw_conf and 'x509' in rw_conf['authentication']: + generate_pki_files(ipsec['pki'], rw_conf['authentication']['x509']) + if 'site_to_site' in data and 'peer' in data['site_to_site']: for peer, peer_conf in ipsec['site_to_site']['peer'].items(): if peer in ipsec['dhcp_no_address']: @@ -385,24 +392,17 @@ def resync_nhrp(ipsec): def apply(ipsec): if not ipsec: - call('sudo /usr/sbin/ipsec stop') + call('sudo ipsec stop') else: - should_start = 'profile' in ipsec or dict_search('site_to_site.peer', ipsec) - - if not process_named_running('charon') and should_start: - args = f'--auto-update {ipsec["auto_update"]}' if 'auto_update' in ipsec else '' - call(f'sudo /usr/sbin/ipsec start {args}') - elif not should_start: - call('sudo /usr/sbin/ipsec stop') - elif ipsec['interface_change']: - call('sudo /usr/sbin/ipsec restart') - else: - call('sudo /usr/sbin/ipsec rereadall') - call('sudo /usr/sbin/ipsec reload') - - if should_start: - sleep(2) # Give charon enough time to start - call('sudo /usr/sbin/swanctl -q') + args = '' + if 'auto_update' in ipsec: + args = '--auto-update ' + ipsec['auto_update'] + call(f'sudo ipsec restart {args}') + call('sudo ipsec rereadall') + call('sudo ipsec reload') + + sleep(5) # Give charon enough time to start + call('sudo swanctl -q') resync_l2tp(ipsec) resync_nhrp(ipsec) -- cgit v1.2.3