summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorChloe Surett <chloe@surett.me>2025-11-17 11:57:09 -0500
committerChristian Breunig <christian@breunig.cc>2026-01-15 16:25:45 +0100
commit2473e1bfdeeb0ea7cc47a14811c29cc4801c8038 (patch)
tree8bb10b93d70a567f1f0e24bb2625a12e310cb48a
parent0c373c7c9cf0fff573e5acc5642f6af63c311da2 (diff)
downloadvyos-1x-2473e1bfdeeb0ea7cc47a14811c29cc4801c8038.tar.gz
vyos-1x-2473e1bfdeeb0ea7cc47a14811c29cc4801c8038.zip
ssh: T7483: Add fido2 PubkeyAuthOptions
-rw-r--r--data/templates/ssh/sshd_config.j214
-rw-r--r--interface-definitions/service_ssh.xml.in19
-rwxr-xr-xpython/vyos/template.py2
-rwxr-xr-xsmoketest/scripts/cli/test_service_ssh.py17
4 files changed, 51 insertions, 1 deletions
diff --git a/data/templates/ssh/sshd_config.j2 b/data/templates/ssh/sshd_config.j2
index d5d155340..32f7e23e7 100644
--- a/data/templates/ssh/sshd_config.j2
+++ b/data/templates/ssh/sshd_config.j2
@@ -72,6 +72,20 @@ HostKeyAlgorithms {{ hostkey_algorithm | join(',') }}
PubkeyAcceptedAlgorithms {{ pubkey_accepted_algorithm | join(',') }}
{% endif %}
+{% if fido is vyos_defined %}
+{% set configured_pubkey_options = [] %}
+{% if fido.pin_required is vyos_defined %}
+{% do configured_pubkey_options.append('verify-required') %}
+{% endif %}
+{% if fido.touch_required is vyos_defined %}
+{% do configured_pubkey_options.append('touch-required') %}
+{% endif %}
+{% if configured_pubkey_options | length > 0 %}
+# Sets one or more public key authentication options.
+PubkeyAuthOptions {{ configured_pubkey_options | join(' ') }}
+{% endif %}
+{% endif %}
+
{% if mac is vyos_defined %}
# Specifies the available MAC (message authentication code) algorithms
MACs {{ mac | join(',') }}
diff --git a/interface-definitions/service_ssh.xml.in b/interface-definitions/service_ssh.xml.in
index 9fd9e32c3..7a1348404 100644
--- a/interface-definitions/service_ssh.xml.in
+++ b/interface-definitions/service_ssh.xml.in
@@ -61,6 +61,25 @@
<valueless/>
</properties>
</leafNode>
+ <node name="fido">
+ <properties>
+ <help>FIDO2 SSH options</help>
+ </properties>
+ <children>
+ <leafNode name="pin-required">
+ <properties>
+ <help>Require FIDO2 keys to attest that a user has been verified (e.g. via a PIN)</help>
+ <valueless/>
+ </properties>
+ </leafNode>
+ <leafNode name="touch-required">
+ <properties>
+ <help>Require FIDO2 keys to attest that a user is physically present</help>
+ <valueless/>
+ </properties>
+ </leafNode>
+ </children>
+ </node>
<node name="dynamic-protection">
<properties>
<help>Allow dynamic protection</help>
diff --git a/python/vyos/template.py b/python/vyos/template.py
index 128471f42..5c4ef9658 100755
--- a/python/vyos/template.py
+++ b/python/vyos/template.py
@@ -55,7 +55,7 @@ def _get_environment(location=None):
loader=loc_loader,
trim_blocks=True,
undefined=ChainableUndefined,
- extensions=['jinja2.ext.loopcontrols']
+ extensions=['jinja2.ext.loopcontrols', 'jinja2.ext.do']
)
env.filters.update(_FILTERS)
env.tests.update(_TESTS)
diff --git a/smoketest/scripts/cli/test_service_ssh.py b/smoketest/scripts/cli/test_service_ssh.py
index 8cd4a2178..72f828093 100755
--- a/smoketest/scripts/cli/test_service_ssh.py
+++ b/smoketest/scripts/cli/test_service_ssh.py
@@ -494,5 +494,22 @@ class TestServiceSSH(VyOSUnitTestSHIM.TestCase):
self.assertNotIn('none', authorize_principals_file_config)
self.assertFalse(os.path.exists(f'/home/{test_user}/.ssh/authorized_principals'))
+ def test_ssh_fido(self):
+ # Order does matter for this test because of how the template
+ # collects and maps the options.
+ opt_map = {
+ 'pin-required': 'verify-required',
+ 'touch-required': 'touch-required',
+ }
+ expected = 'PubkeyAuthOptions '
+ for k, v in opt_map.items():
+ self.cli_set(base_path + ['fido', k])
+ expected = f'{expected}{v} '
+ expected = expected[:-1]
+ self.cli_commit()
+ tmp_sshd_conf = read_file(SSHD_CONF)
+ self.assertIn(expected, tmp_sshd_conf)
+
+
if __name__ == '__main__':
unittest.main(verbosity=2, failfast=VyOSUnitTestSHIM.TestCase.debug_on())