summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorChristian Breunig <christian@breunig.cc>2024-02-11 21:49:57 +0100
committerMergify <37929162+mergify[bot]@users.noreply.github.com>2024-02-13 20:40:00 +0000
commitef64c051d0c90a1ddafe80b4509ffdf1e1035b50 (patch)
tree578cd8a3099f737e20eabcbe1b9cc6edc558bfbf
parent71397fb4070758e5ce29be08a3572bf3ee62cb06 (diff)
downloadvyos-1x-ef64c051d0c90a1ddafe80b4509ffdf1e1035b50.tar.gz
vyos-1x-ef64c051d0c90a1ddafe80b4509ffdf1e1035b50.zip
rpki: T6034: move SSH authentication keys to PKI subsystem
(cherry picked from commit ac2d7dfac6073d0f232191ec494f78a8d12889e4)
-rw-r--r--interface-definitions/protocols_rpki.xml.in17
-rwxr-xr-xsmoketest/scripts/cli/test_protocols_rpki.py80
-rwxr-xr-xsrc/conf_mode/protocols_rpki.py43
3 files changed, 87 insertions, 53 deletions
diff --git a/interface-definitions/protocols_rpki.xml.in b/interface-definitions/protocols_rpki.xml.in
index 6c71f69f3..54d69eadb 100644
--- a/interface-definitions/protocols_rpki.xml.in
+++ b/interface-definitions/protocols_rpki.xml.in
@@ -47,22 +47,7 @@
<help>RPKI SSH connection settings</help>
</properties>
<children>
- <leafNode name="private-key-file">
- <properties>
- <help>RPKI SSH private key file</help>
- <constraint>
- <validator name="file-path"/>
- </constraint>
- </properties>
- </leafNode>
- <leafNode name="public-key-file">
- <properties>
- <help>RPKI SSH public key file path</help>
- <constraint>
- <validator name="file-path"/>
- </constraint>
- </properties>
- </leafNode>
+ #include <include/pki/openssh-key.xml.i>
#include <include/generic-username.xml.i>
</children>
</node>
diff --git a/smoketest/scripts/cli/test_protocols_rpki.py b/smoketest/scripts/cli/test_protocols_rpki.py
index c52c0dd76..041fe4c76 100755
--- a/smoketest/scripts/cli/test_protocols_rpki.py
+++ b/smoketest/scripts/cli/test_protocols_rpki.py
@@ -14,20 +14,57 @@
# 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 os
import unittest
from base_vyostest_shim import VyOSUnitTestSHIM
from vyos.configsession import ConfigSessionError
-from vyos.utils.process import cmd
from vyos.utils.process import process_named_running
base_path = ['protocols', 'rpki']
PROCESS_NAME = 'bgpd'
-rpki_ssh_key = '/config/auth/id_rsa_rpki'
-rpki_ssh_pub = f'{rpki_ssh_key}.pub'
+rpki_key_name = 'rpki-smoketest'
+rpki_key_type = 'ssh-rsa'
+
+rpki_ssh_key = """
+b3BlbnNzaC1rZXktdjEAAAAABG5vbmUAAAAEbm9uZQAAAAAAAAABAAABFwAAAAdz
+c2gtcnNhAAAAAwEAAQAAAQEAweDyflDFR4qyEwETbJkZ2ZZc+sJNiDTvYpwGsWIk
+ju49lJSxHe1xKf8FhwfyMu40Snt1yDlRmmmz4CsbLgbuZGMPvXG11e34+C0pSVUv
+pF6aqRTeLl1pDRK7Rnjgm3su+I8SRLQR4qbLG6VXWOFuVpwiqbExLaU0hFYTPNP+
+dArNpsWEEKsohk6pTXdhg3VzWp3vCMjl2JTshDa3lD7p2xISSAReEY0fnfEAmQzH
+4Z6DIwwGdFuMWoQIg+oFBM9ARrO2/FIjRsz6AecR/WeU72JEw4aJic1/cAJQA6Pi
+QBHwkuo3Wll1tbpxeRZoB2NQG22ETyJLvhfTaooNLT9HpQAAA8joU5dM6FOXTAAA
+AAdzc2gtcnNhAAABAQDB4PJ+UMVHirITARNsmRnZllz6wk2INO9inAaxYiSO7j2U
+lLEd7XEp/wWHB/Iy7jRKe3XIOVGaabPgKxsuBu5kYw+9cbXV7fj4LSlJVS+kXpqp
+FN4uXWkNErtGeOCbey74jxJEtBHipssbpVdY4W5WnCKpsTEtpTSEVhM80/50Cs2m
+xYQQqyiGTqlNd2GDdXNane8IyOXYlOyENreUPunbEhJIBF4RjR+d8QCZDMfhnoMj
+DAZ0W4xahAiD6gUEz0BGs7b8UiNGzPoB5xH9Z5TvYkTDhomJzX9wAlADo+JAEfCS
+6jdaWXW1unF5FmgHY1AbbYRPIku+F9Nqig0tP0elAAAAAwEAAQAAAQACkDlUjzfU
+htJs6uY5WNrdJB5NmHUS+HQzzxFNlhkapK6+wKqI1UNaRUtq6iF7J+gcFf7MK2nX
+S098BsXguWm8fQzPuemoDvHsQhiaJhyvpSqRUrvPTB/f8t/0AhQiKiJIWgfpTaIw
+53inAGwjujNNxNm2eafHTThhCYxOkRT7rsT6bnSio6yeqPy5QHg7IKFztp5FXDUy
+iOS3aX3SvzQcDUkMXALdvzX50t1XIk+X48Rgkq72dL4VpV2oMNDu3hM6FqBUplf9
+Mv3s51FNSma/cibCQoVufrIfoqYjkNTjIpYFUcq4zZ0/KvgXgzSsy9VN/4Ttbalr
+Ouu7X/SHJbvhAAAAgGPFsXgONYQvXxCnK1dIueozgaZg1I/n522E2ZCOXBW4dYJV
+yNpppwRreDzuFzTDEe061MpNHfScjVBJCCulivFYWscL6oaGsryDbFxO3QmB4I98
+UBqrds2yan9/JGc6EYe299yvaHy7Y64+NC0+fN8H2RAZ61T4w10JrCaJRyvzAAAA
+gQDvBfuV1U7o9k/fbU+U7W2UYnWblpOZAMfi1XQP6IJJeyWs90PdTdXh+l0eIQrC
+awIiRJytNfxMmbD4huwTf77fWiyCcPznmALQ7ex/yJ+W5Z0V4dPGF3h7o1uiS236
+JhQ7mfcliCkhp/1PIklBIMPcCp0zl+s9wMv2hX7w1Pah9QAAAIEAz6YgU9Xute+J
++dBwoWxEQ+igR6KE55Um7O9AvSrqnCm9r7lSFsXC2ErYOxoDSJ3yIBEV0b4XAGn6
+tbbVIs3jS8BnLHxclAHQecOx1PGn7PKbnPW0oJRq/X9QCIEelKYvlykpayn7uZoo
+TXqcDaPZxfPpmPdye8chVJvdygi7kPEAAAAMY3BvQExSMS53dWUzAQIDBAUGBw==
+"""
+
+rpki_ssh_pub = """
+AAAAB3NzaC1yc2EAAAADAQABAAABAQDB4PJ+UMVHirITARNsmRnZllz6wk2INO9i
+nAaxYiSO7j2UlLEd7XEp/wWHB/Iy7jRKe3XIOVGaabPgKxsuBu5kYw+9cbXV7fj4
+LSlJVS+kXpqpFN4uXWkNErtGeOCbey74jxJEtBHipssbpVdY4W5WnCKpsTEtpTSE
+VhM80/50Cs2mxYQQqyiGTqlNd2GDdXNane8IyOXYlOyENreUPunbEhJIBF4RjR+d
+8QCZDMfhnoMjDAZ0W4xahAiD6gUEz0BGs7b8UiNGzPoB5xH9Z5TvYkTDhomJzX9w
+AlADo+JAEfCS6jdaWXW1unF5FmgHY1AbbYRPIku+F9Nqig0tP0el
+"""
class TestProtocolsRPKI(VyOSUnitTestSHIM.TestCase):
@classmethod
@@ -44,10 +81,6 @@ class TestProtocolsRPKI(VyOSUnitTestSHIM.TestCase):
self.cli_delete(base_path)
self.cli_commit()
- # Nothing RPKI specific should be left over in the config
- # frrconfig = self.getFRRconfig('rpki')
- # self.assertNotIn('rpki', frrconfig)
-
# check process health and continuity
self.assertEqual(self.daemon_pid, process_named_running(PROCESS_NAME))
@@ -107,14 +140,17 @@ class TestProtocolsRPKI(VyOSUnitTestSHIM.TestCase):
},
}
+ self.cli_set(['pki', 'openssh', rpki_key_name, 'private', 'key', rpki_ssh_key.replace('\n','')])
+ self.cli_set(['pki', 'openssh', rpki_key_name, 'public', 'key', rpki_ssh_pub.replace('\n','')])
+ self.cli_set(['pki', 'openssh', rpki_key_name, 'public', 'type', rpki_key_type])
+
self.cli_set(base_path + ['polling-period', polling])
- for peer, peer_config in cache.items():
- self.cli_set(base_path + ['cache', peer, 'port', peer_config['port']])
- self.cli_set(base_path + ['cache', peer, 'preference', peer_config['preference']])
- self.cli_set(base_path + ['cache', peer, 'ssh', 'username', peer_config['username']])
- self.cli_set(base_path + ['cache', peer, 'ssh', 'public-key-file', rpki_ssh_pub])
- self.cli_set(base_path + ['cache', peer, 'ssh', 'private-key-file', rpki_ssh_key])
+ for cache_name, cache_config in cache.items():
+ self.cli_set(base_path + ['cache', cache_name, 'port', cache_config['port']])
+ self.cli_set(base_path + ['cache', cache_name, 'preference', cache_config['preference']])
+ self.cli_set(base_path + ['cache', cache_name, 'ssh', 'username', cache_config['username']])
+ self.cli_set(base_path + ['cache', cache_name, 'ssh', 'key', rpki_key_name])
# commit changes
self.cli_commit()
@@ -123,12 +159,13 @@ class TestProtocolsRPKI(VyOSUnitTestSHIM.TestCase):
frrconfig = self.getFRRconfig('rpki')
self.assertIn(f'rpki polling_period {polling}', frrconfig)
- for peer, peer_config in cache.items():
- port = peer_config['port']
- preference = peer_config['preference']
- username = peer_config['username']
- self.assertIn(f'rpki cache {peer} {port} {username} {rpki_ssh_key} {rpki_ssh_pub} preference {preference}', frrconfig)
+ for cache_name, cache_config in cache.items():
+ port = cache_config['port']
+ preference = cache_config['preference']
+ username = cache_config['username']
+ self.assertIn(f'rpki cache {cache_name} {port} {username} /run/frr/id_rpki_{cache_name} /run/frr/id_rpki_{cache_name}.pub preference {preference}', frrconfig)
+ self.cli_delete(['pki', 'openssh'])
def test_rpki_verify_preference(self):
cache = {
@@ -150,10 +187,5 @@ class TestProtocolsRPKI(VyOSUnitTestSHIM.TestCase):
with self.assertRaises(ConfigSessionError):
self.cli_commit()
-
if __name__ == '__main__':
- # Create OpenSSH keypair used in RPKI tests
- if not os.path.isfile(rpki_ssh_key):
- cmd(f'ssh-keygen -t rsa -f {rpki_ssh_key} -N ""')
-
unittest.main(verbosity=2)
diff --git a/src/conf_mode/protocols_rpki.py b/src/conf_mode/protocols_rpki.py
index 0fc14e868..72ab2d454 100755
--- a/src/conf_mode/protocols_rpki.py
+++ b/src/conf_mode/protocols_rpki.py
@@ -1,6 +1,6 @@
#!/usr/bin/env python3
#
-# Copyright (C) 2021 VyOS maintainers and contributors
+# Copyright (C) 2021-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
@@ -14,13 +14,14 @@
# 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 os
-
from sys import exit
from vyos.config import Config
+from vyos.pki import wrap_openssh_public_key
+from vyos.pki import wrap_openssh_private_key
from vyos.template import render_to_string
-from vyos.utils.dict import dict_search
+from vyos.utils.dict import dict_search_args
+from vyos.utils.file import write_file
from vyos import ConfigError
from vyos import frr
from vyos import airbag
@@ -33,7 +34,8 @@ def get_config(config=None):
conf = Config()
base = ['protocols', 'rpki']
- rpki = conf.get_config_dict(base, key_mangling=('-', '_'), get_first_key=True)
+ rpki = conf.get_config_dict(base, key_mangling=('-', '_'),
+ get_first_key=True, with_pki=True)
# Bail out early if configuration tree does not exist
if not conf.exists(base):
rpki.update({'deleted' : ''})
@@ -63,22 +65,37 @@ def verify(rpki):
preferences.append(preference)
if 'ssh' in peer_config:
- files = ['private_key_file', 'public_key_file']
- for file in files:
- if file not in peer_config['ssh']:
- raise ConfigError('RPKI+SSH requires username and public/private ' \
- 'key file to be defined!')
+ if 'username' not in peer_config['ssh']:
+ raise ConfigError('RPKI+SSH requires username to be defined!')
+
+ if 'key' not in peer_config['ssh'] or 'openssh' not in rpki['pki']:
+ raise ConfigError('RPKI+SSH requires key to be defined!')
- filename = peer_config['ssh'][file]
- if not os.path.exists(filename):
- raise ConfigError(f'RPKI SSH {file.replace("-","-")} "{filename}" does not exist!')
+ if peer_config['ssh']['key'] not in rpki['pki']['openssh']:
+ raise ConfigError('RPKI+SSH key not found on PKI subsystem!')
return None
def generate(rpki):
if not rpki:
return
+
+ if 'cache' in rpki:
+ for cache, cache_config in rpki['cache'].items():
+ if 'ssh' in cache_config:
+ key_name = cache_config['ssh']['key']
+ public_key_data = dict_search_args(rpki['pki'], 'openssh', key_name, 'public', 'key')
+ public_key_type = dict_search_args(rpki['pki'], 'openssh', key_name, 'public', 'type')
+ private_key_data = dict_search_args(rpki['pki'], 'openssh', key_name, 'private', 'key')
+
+ cache_config['ssh']['public_key_file'] = f'/run/frr/id_rpki_{cache}.pub'
+ cache_config['ssh']['private_key_file'] = f'/run/frr/id_rpki_{cache}'
+
+ write_file(cache_config['ssh']['public_key_file'], wrap_openssh_public_key(public_key_data, public_key_type))
+ write_file(cache_config['ssh']['private_key_file'], wrap_openssh_private_key(private_key_data))
+
rpki['new_frr_config'] = render_to_string('frr/rpki.frr.j2', rpki)
+
return None
def apply(rpki):