Skip to content

Commit

Permalink
[feature] Added support for OpenVPN tls-auth option #174
Browse files Browse the repository at this point in the history
The OpenVPN backend will automatically create a file for the
key present in "tls_auth" field and update the value of the
"tls-auth" parameter.

Closes #174
  • Loading branch information
pandafy committed Mar 8, 2022
1 parent 47b4435 commit 8658840
Show file tree
Hide file tree
Showing 5 changed files with 131 additions and 0 deletions.
2 changes: 2 additions & 0 deletions docs/source/backends/openvpn.rst
Original file line number Diff line number Diff line change
Expand Up @@ -169,6 +169,8 @@ Required properties:
+--------------------------+---------+--------------+-------------------------------------------------------------+
| ``verb`` | integer | ``1`` | from ``0`` (disabled) to ``11`` (very verbose) |
+--------------------------+---------+--------------+-------------------------------------------------------------+
| ``tls_auth`` | string | | string containing TLS Auth key |
+--------------------------+---------+--------------+-------------------------------------------------------------+

Client specific settings
~~~~~~~~~~~~~~~~~~~~~~~~
Expand Down
32 changes: 32 additions & 0 deletions netjsonconfig/backends/openvpn/converters.py
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
from copy import deepcopy

from ...schema import X509_FILE_MODE
from ..base.converter import BaseConverter
from .schema import schema

Expand Down Expand Up @@ -46,8 +47,39 @@ def __intermediate_vpn(self, config, remove=[False, 0, '']):
# do not display status-version if status directive not present
if 'status' not in config and 'status_version' in config:
del config['status_version']
config = self.__add_tls_auth_key(config)
return self.sorted_dict(config)

def __add_tls_auth_key(self, config):
tls_auth = config.get('tls_auth', None)
if not tls_auth:
return config
tls_auth = tls_auth.strip()
if len(tls_auth.split(' ')) == 1:
# The TLS Auth key is present in the field.
cert_path = config.get('cert', '')
tls_auth_path = '/'.join(cert_path.split('/')[:-1] + ['tls_auth.key'])
if config.get('mode') == 'server':
tls_auth_direction = 0
else:
tls_auth_direction = 1
config['tls_auth'] = f'{tls_auth_path} {tls_auth_direction}'
# Add TLS Auth key file
file_data = {
'path': tls_auth_path,
'mode': X509_FILE_MODE,
'contents': tls_auth,
}
try:
self.netjson['files'].append(file_data)
except KeyError:
self.netjson['files'] = [file_data]
else:
# The field already contains path to auth key
# and TLS Auth direction. No operation is required.
pass
return config

def to_netjson_loop(self, block, result, index):
vpn = self.__netjson_vpn(block)
result.setdefault('openvpn', [])
Expand Down
11 changes: 11 additions & 0 deletions netjsonconfig/backends/openvpn/openvpn.py
Original file line number Diff line number Diff line change
Expand Up @@ -76,6 +76,17 @@ def auto_client(
# remote_cert_tls
remote_cert_tls = {None: '', '': '', 'client': 'server'}
client['remote_cert_tls'] = remote_cert_tls[server.get('remote_cert_tls')]
tls_auth = server.get('tls_auth')
if tls_auth:
if len(tls_auth.split(' ')) == 1:
# The TLS Auth key is present in the field.
# Copy the TLS Auth key. Convertor will handle
# parsing it into file.
client['tls_auth'] = tls_auth
else:
# The field contains path to auth key and direction.
# auto_client does not support such format.
pass
copy_keys = [
'name',
'dev_type',
Expand Down
10 changes: 10 additions & 0 deletions netjsonconfig/backends/openvpn/schema.py
Original file line number Diff line number Diff line change
Expand Up @@ -445,6 +445,16 @@
"description": "Set output verbosity for logging and debugging",
"propertyOrder": 52,
},
"tls_auth": {
"title": "TLS Auth",
"description": (
"Adds an additional layer of HMAC authentication on top of "
"the TLS control channel to mitigate DoS attacks and "
"attacks on the TLS stack"
),
"type": "string",
"propertyOrder": 53,
},
},
},
"client": {
Expand Down
76 changes: 76 additions & 0 deletions tests/openvpn/test_backend.py
Original file line number Diff line number Diff line change
Expand Up @@ -738,3 +738,79 @@ def test_override(self):
o = OpenVpn(self._simple_conf, templates=[template])
# ensure dummy values in template have been overridden
self.assertDictEqual(o.config, self._simple_conf)

_openvpn_server_tls_auth_config = {
"openvpn": [
{
"name": "test",
"ca": "/etc/openvpn/ca.pem",
"cert": "/etc/openvpn/cert.pem",
"dev": "tap0",
"dev_type": "tap",
"dh": "/etc/openvpn/dh.pem",
"key": "/etc/openvpn/key.pem",
"mode": "server",
"proto": "udp",
"status": "",
"status_version": 1,
"tls_server": True,
"tls_auth": "tls-auth-key",
}
],
}

_openvpn_server_tls_auth_render = """# openvpn config: test
ca /etc/openvpn/ca.pem
cert /etc/openvpn/cert.pem
dev tap0
dev-type tap
dh /etc/openvpn/dh.pem
key /etc/openvpn/key.pem
mode server
proto udp
tls-auth /etc/openvpn/tls_auth.key 0
tls-server
# ---------- files ---------- #
# path: /etc/openvpn/tls_auth.key
# mode: 0600
tls-auth-key
"""

_openvpn_client_tls_auth_render = """# openvpn config: test
ca /etc/openvpn/ca.pem
cert /etc/openvpn/cert.pem
dev tap0
dev-type tap
key /etc/openvpn/key.pem
mode p2p
nobind
proto udp
remote vpn1.test.com 1195
resolv-retry infinite
tls-auth /etc/openvpn/tls_auth.key 1
tls-client
# ---------- files ---------- #
# path: /etc/openvpn/tls_auth.key
# mode: 0600
tls-auth-key
"""

def test_tls_auth_key_present(self):
server = OpenVpn(self._openvpn_server_tls_auth_config)
self.assertEqual(server.render(), self._openvpn_server_tls_auth_render)
client_config = OpenVpn.auto_client(
'vpn1.test.com',
self._openvpn_server_tls_auth_config['openvpn'][0],
)
client = OpenVpn(client_config)
self.assertEqual(client.render(), self._openvpn_client_tls_auth_render)

0 comments on commit 8658840

Please sign in to comment.