diff options
| -rw-r--r-- | data/templates/zabbix-agent/zabbix-agent.conf.j2 | 13 | ||||
| -rw-r--r-- | interface-definitions/include/auth-mode-pre-shared-secret.xml.i | 14 | ||||
| -rw-r--r-- | interface-definitions/include/auth-psk-id.xml.i | 11 | ||||
| -rw-r--r-- | interface-definitions/include/auth-psk-secret.xml.i | 15 | ||||
| -rw-r--r-- | interface-definitions/include/stunnel/psk.xml.i | 23 | ||||
| -rw-r--r-- | interface-definitions/service_monitoring_zabbix-agent.xml.in | 17 | ||||
| -rw-r--r-- | interface-definitions/vpn_ipsec.xml.in | 13 | ||||
| -rw-r--r-- | op-mode-definitions/generate-psk.xml.in | 28 | ||||
| -rwxr-xr-x | smoketest/scripts/cli/test_service_monitoring_zabbix-agent.py | 21 | ||||
| -rwxr-xr-x | src/conf_mode/service_monitoring_zabbix-agent.py | 23 | ||||
| -rw-r--r-- | src/op_mode/generate_psk.py | 45 | 
11 files changed, 189 insertions, 34 deletions
| diff --git a/data/templates/zabbix-agent/zabbix-agent.conf.j2 b/data/templates/zabbix-agent/zabbix-agent.conf.j2 index e6dcef872..b8df2d177 100644 --- a/data/templates/zabbix-agent/zabbix-agent.conf.j2 +++ b/data/templates/zabbix-agent/zabbix-agent.conf.j2 @@ -75,3 +75,16 @@ Include={{ directory }}/*.conf  Timeout={{ timeout }}  {% endif %} +{% if authentication is vyos_defined and authentication.mode is vyos_defined %} +{%     if authentication.mode == "pre-shared-secret" %} +TLSConnect=psk +TLSAccept=psk +{%     endif %} +{%     if authentication.psk.secret is vyos_defined %} +TLSPSKFile={{ service_psk_file }} +{%     endif %} +{%     if authentication.psk.id is vyos_defined %} +TLSPSKIdentity={{ authentication.psk.id }} +{%     endif %} +{% endif %} + diff --git a/interface-definitions/include/auth-mode-pre-shared-secret.xml.i b/interface-definitions/include/auth-mode-pre-shared-secret.xml.i new file mode 100644 index 000000000..cf1003917 --- /dev/null +++ b/interface-definitions/include/auth-mode-pre-shared-secret.xml.i @@ -0,0 +1,14 @@ +<!-- include start from auth-mode-pre-shared-secret.xml.i --> +<leafNode name="mode"> +  <properties> +    <help>Authentication mode</help> +    <completionHelp> +      <list>pre-shared-secret</list> +    </completionHelp> +    <valueHelp> +      <format>pre-shared-secret</format> +      <description>Use a pre-shared secret key</description> +    </valueHelp> +  </properties> +</leafNode> +<!-- include end --> diff --git a/interface-definitions/include/auth-psk-id.xml.i b/interface-definitions/include/auth-psk-id.xml.i new file mode 100644 index 000000000..ab2451045 --- /dev/null +++ b/interface-definitions/include/auth-psk-id.xml.i @@ -0,0 +1,11 @@ +<!-- include start from auth-psk-id.xml.i --> +<leafNode name="id"> +  <properties> +    <help>ID for authentication</help> +    <valueHelp> +      <format>txt</format> +      <description>ID used for authentication</description> +    </valueHelp> +  </properties> +</leafNode> +<!-- include end --> diff --git a/interface-definitions/include/auth-psk-secret.xml.i b/interface-definitions/include/auth-psk-secret.xml.i new file mode 100644 index 000000000..24257dcab --- /dev/null +++ b/interface-definitions/include/auth-psk-secret.xml.i @@ -0,0 +1,15 @@ +<!-- include start from auth-psk-secret.xml.i --> +<leafNode name="secret"> +  <properties> +    <help>pre-shared secret key</help> +    <valueHelp> +      <format>txt</format> +      <description>16byte pre-shared-secret key (32 character hexadecimal key)</description> +    </valueHelp> +    <constraint> +      <validator name="psk-secret"/> +    </constraint> +    <constraintErrorMessage>Pre-Shared-Keys must be at leas 16 bytes long, which implies at least 32 characterss</constraintErrorMessage> +  </properties> +</leafNode> +<!-- include end --> diff --git a/interface-definitions/include/stunnel/psk.xml.i b/interface-definitions/include/stunnel/psk.xml.i index db11a93d3..a8226c866 100644 --- a/interface-definitions/include/stunnel/psk.xml.i +++ b/interface-definitions/include/stunnel/psk.xml.i @@ -4,27 +4,8 @@      <help>Pre-shared key name</help>    </properties>    <children> -    <leafNode name="id"> -      <properties> -        <help>ID for authentication</help> -        <valueHelp> -          <format>txt</format> -          <description>ID used for authentication</description> -        </valueHelp> -      </properties> -    </leafNode> -    <leafNode name="secret"> -      <properties> -        <help>pre-shared secret key</help> -        <valueHelp> -          <format>txt</format> -          <description>pre-shared secret key are required to be at least 16 bytes long, which implies at least 32 characters for hexadecimal key</description> -        </valueHelp> -        <constraint> -          <validator name="psk-secret"/> -        </constraint> -      </properties> -    </leafNode> +    #include <include/auth-psk-id.xml.i> +    #include <include/auth-psk-secret.xml.i>    </children>  </tagNode>  <!-- include end --> diff --git a/interface-definitions/service_monitoring_zabbix-agent.xml.in b/interface-definitions/service_monitoring_zabbix-agent.xml.in index e44b31312..122e61e8b 100644 --- a/interface-definitions/service_monitoring_zabbix-agent.xml.in +++ b/interface-definitions/service_monitoring_zabbix-agent.xml.in @@ -10,6 +10,23 @@                <priority>1280</priority>              </properties>              <children> +              <node name="authentication"> +                <properties> +                  <help>Authentication</help> +                </properties> +                <children> +                  #include <include/auth-mode-pre-shared-secret.xml.i> +                  <node name="psk"> +                    <properties> +                      <help>Pre-shared key</help> +                    </properties> +                    <children> +                      #include <include/auth-psk-id.xml.i> +                      #include <include/auth-psk-secret.xml.i> +                    </children> +                  </node> +                </children> +              </node>                <leafNode name="directory">                  <properties>                    <help>Folder containing individual Zabbix-agent configuration files</help> diff --git a/interface-definitions/vpn_ipsec.xml.in b/interface-definitions/vpn_ipsec.xml.in index 5540021e2..0cf526fad 100644 --- a/interface-definitions/vpn_ipsec.xml.in +++ b/interface-definitions/vpn_ipsec.xml.in @@ -722,18 +722,7 @@                    <help>Authentication</help>                  </properties>                  <children> -                  <leafNode name="mode"> -                    <properties> -                      <help>Authentication mode</help> -                      <completionHelp> -                        <list>pre-shared-secret</list> -                      </completionHelp> -                      <valueHelp> -                        <format>pre-shared-secret</format> -                        <description>Use a pre-shared secret key</description> -                      </valueHelp> -                    </properties> -                  </leafNode> +                  #include <include/auth-mode-pre-shared-secret.xml.i>                    #include <include/ipsec/authentication-pre-shared-secret.xml.i>                  </children>                </node> diff --git a/op-mode-definitions/generate-psk.xml.in b/op-mode-definitions/generate-psk.xml.in new file mode 100644 index 000000000..69963f5be --- /dev/null +++ b/op-mode-definitions/generate-psk.xml.in @@ -0,0 +1,28 @@ +<?xml version="1.0"?> +<interfaceDefinition> +  <node name="generate"> +    <children> +      <node name="psk"> +        <properties> +          <help>Generate PSK key</help> +        </properties> +        <children> +          <node name="random"> +            <properties> +              <help>Generate random hex PSK key</help> +            </properties> +            <command>${vyos_op_scripts_dir}/generate_psk.py</command> +            <children> +              <tagNode name="size"> +                <properties> +                  <help>Key size in bytes</help> +                </properties> +                <command>${vyos_op_scripts_dir}/generate_psk.py --hex_size "$5"</command> +              </tagNode> +            </children> +          </node> +        </children> +      </node> +    </children> +  </node> +</interfaceDefinition> diff --git a/smoketest/scripts/cli/test_service_monitoring_zabbix-agent.py b/smoketest/scripts/cli/test_service_monitoring_zabbix-agent.py index a60dae0a0..522f9df0f 100755 --- a/smoketest/scripts/cli/test_service_monitoring_zabbix-agent.py +++ b/smoketest/scripts/cli/test_service_monitoring_zabbix-agent.py @@ -23,6 +23,7 @@ from vyos.utils.file import read_file  PROCESS_NAME = 'zabbix_agent2'  ZABBIX_AGENT_CONF = '/run/zabbix/zabbix-agent2.conf' +ZABBIX_PSK_FILE = f'/run/zabbix/zabbix-agent2.psk'  base_path = ['service', 'monitoring', 'zabbix-agent'] @@ -82,6 +83,26 @@ class TestZabbixAgent(VyOSUnitTestSHIM.TestCase):          self.assertIn(f'Timeout={timeout}', config)          self.assertIn(f'Hostname={hostname}', config) +    def test_02_zabbix_agent_psk_auth(self): +        secret = '8703ce4cb3f51279acba895e1421d69d8a7e2a18546d013d564ad87ac3957f29' +        self.cli_set(base_path + ['server', '127.0.0.1']) +        self.cli_set(base_path + ['authentication', 'mode', 'pre-shared-secret']) +        self.cli_set(base_path + ['authentication', 'psk', 'id', 'smoke_test']) +        self.cli_set(base_path + ['authentication', 'psk', 'secret', secret]) +        self.cli_commit() + +        config = read_file(ZABBIX_AGENT_CONF) +        self.assertIn('TLSConnect=psk', config) +        self.assertIn('TLSAccept=psk', config) +        self.assertIn('TLSPSKIdentity=smoke_test', config) +        self.assertIn(f'TLSPSKFile={ZABBIX_PSK_FILE}', config) +        self.assertEqual(secret, read_file(ZABBIX_PSK_FILE)) + +        secret = '8703ce4cb3f51279acba895e1421d69d8a7e2a18546d013d564ad87ac3957f88' +        self.cli_set(base_path + ['authentication', 'psk', 'secret', secret]) +        self.cli_commit() +        self.assertEqual(secret, read_file(ZABBIX_PSK_FILE)) +  if __name__ == '__main__':      unittest.main(verbosity=2) diff --git a/src/conf_mode/service_monitoring_zabbix-agent.py b/src/conf_mode/service_monitoring_zabbix-agent.py index 98d8a32ca..f17146a8d 100755 --- a/src/conf_mode/service_monitoring_zabbix-agent.py +++ b/src/conf_mode/service_monitoring_zabbix-agent.py @@ -18,6 +18,8 @@ import os  from vyos.config import Config  from vyos.template import render +from vyos.utils.dict import dict_search +from vyos.utils.file import write_file  from vyos.utils.process import call  from vyos import ConfigError  from vyos import airbag @@ -26,6 +28,7 @@ airbag.enable()  service_name = 'zabbix-agent2'  service_conf = f'/run/zabbix/{service_name}.conf' +service_psk_file = f'/run/zabbix/{service_name}.psk'  systemd_override = r'/run/systemd/system/zabbix-agent2.service.d/10-override.conf' @@ -49,6 +52,8 @@ def get_config(config=None):      if 'directory' in config and config['directory'].endswith('/'):          config['directory'] = config['directory'][:-1] +    config['service_psk_file'] = service_psk_file +      return config @@ -60,18 +65,34 @@ def verify(config):      if 'server' not in config:          raise ConfigError('Server is required!') +    if 'authentication' in config and dict_search("authentication.mode", +                                                  config) == 'pre_shared_secret': +        if 'id' not in config['authentication']['psk']: +            raise ConfigError( +                'PSK identity is required for pre-shared-secret authentication mode') + +        if 'secret' not in config['authentication']['psk']: +            raise ConfigError( +                'PSK secret is required for pre-shared-secret authentication mode') +  def generate(config):      # bail out early - looks like removal from running config      if config is None:          # Remove old config and return -        config_files = [service_conf, systemd_override] +        config_files = [service_conf, systemd_override, service_psk_file]          for file in config_files:              if os.path.isfile(file):                  os.unlink(file)          return None +    if not dict_search("authentication.psk.secret", config): +        if os.path.isfile(service_psk_file): +            os.unlink(service_psk_file) +    else: +        write_file(service_psk_file, config["authentication"]["psk"]["secret"]) +      # Write configuration file      render(service_conf, 'zabbix-agent/zabbix-agent.conf.j2', config)      render(systemd_override, 'zabbix-agent/10-override.conf.j2', config) diff --git a/src/op_mode/generate_psk.py b/src/op_mode/generate_psk.py new file mode 100644 index 000000000..d51293712 --- /dev/null +++ b/src/op_mode/generate_psk.py @@ -0,0 +1,45 @@ +#!/usr/bin/env python3 +# +# Copyright (C) 2024 VyOS maintainers and contributors +# +# This program is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License version 2 or later as +# published by the Free Software Foundation. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program.  If not, see <http://www.gnu.org/licenses/>. +import argparse + +from vyos.utils.process import cmd + + +def validate_hex_size(value): +    """Validate that the hex_size is between 32 and 512.""" +    try: +        value = int(value) +    except ValueError: +        raise argparse.ArgumentTypeError("hex_size must be integer.") + +    if value < 32 or value > 512: +        raise argparse.ArgumentTypeError("hex_size must be between 32 and 512.") +    return value + + +if __name__ == '__main__': +    parser = argparse.ArgumentParser() +    parser.add_argument( +        "--hex_size", +        type=validate_hex_size, +        help='PKS value size in hex format. Default is 32 bytes.', +        default=32, + +        required=False, +    ) +    args = parser.parse_args() + +    print(cmd(f'openssl rand -hex {args.hex_size}'))
\ No newline at end of file | 
