From a1da3303f951bc2ea3c2463d40e061027a9006c7 Mon Sep 17 00:00:00 2001 From: Michael Hudson-Doyle Date: Fri, 12 Feb 2021 11:19:07 +1300 Subject: [PATCH 1/5] add no_keys_to_console option to suppress cc_keys_to_console LP: #1915460 --- cloudinit/config/cc_keys_to_console.py | 5 +++++ doc/examples/cloud-config-ssh-keys.txt | 9 +++++++++ .../modules/keys_to_console_disabled.py | 16 ++++++++++++++++ .../modules/keys_to_console_disabled.yaml | 14 ++++++++++++++ 4 files changed, 44 insertions(+) create mode 100644 tests/cloud_tests/testcases/modules/keys_to_console_disabled.py create mode 100644 tests/cloud_tests/testcases/modules/keys_to_console_disabled.yaml diff --git a/cloudinit/config/cc_keys_to_console.py b/cloudinit/config/cc_keys_to_console.py index 0f2be52bac0..d998a729e2c 100644 --- a/cloudinit/config/cc_keys_to_console.py +++ b/cloudinit/config/cc_keys_to_console.py @@ -51,6 +51,11 @@ def _get_helper_tool_path(distro): def handle(name, cfg, cloud, log, _args): + if util.is_true(cfg.get('no_keys_to_console', False)): + log.debug(("Skipping module named %s, " + "logging of SSH host keys disabled"), name) + return + helper_path = _get_helper_tool_path(cloud.distro) if not os.path.exists(helper_path): log.warning(("Unable to activate module %s," diff --git a/doc/examples/cloud-config-ssh-keys.txt b/doc/examples/cloud-config-ssh-keys.txt index aad8b683a09..ffd2c23c097 100644 --- a/doc/examples/cloud-config-ssh-keys.txt +++ b/doc/examples/cloud-config-ssh-keys.txt @@ -42,3 +42,12 @@ ssh_keys: -----END DSA PRIVATE KEY----- dsa_public: ssh-dss AAAAB3NzaC1kc3MAAACBAM/Ycu7ulMTEvz1RLIzTbrhELJZf8Iwua6TFfQl1ubb1rHwUElOkus7xMhdVjms8AmbV1Meem7ImE69T0bszy09QAG3NImHgZVIeXBoJ/JzByku/1NcOBYilKP7oSIcLJpGUHX8IGn1GJoH7XRBwVub6Vqm4RP78C7q9IOn0hG2VAAAAFQCDEfCrnL1GGzhCPsr/uS1vbt8/wQAAAIEAjSrok/4m8mbBkVp4IwxXFdRuqJKSj8/WWxos00Ednn/ww5QibysHYULrOKJ1+54mmpMyp5CZICUQELCfCt5ScZ9GsqgmnI80Q1h3Xkwbo3kn7PzWwRwcV6muvJn4PcZ71WM+rdN/c2EorAINDTbjRo97NueM94WbiYdtjHFxn0YAAACAXmLIFSQgiAPu459rCKxT46tHJtM0QfnNiEnQLbFluefZ/yiI4DI38UzTCOXLhUA7ybmZha+D/csj15Y9/BNFuO7unzVhikCQV9DTeXX46pG4s1o23JKC/QaYWNMZ7kTRv+wWow9MhGiVdML4ZN4XnifuO5krqAybngIy66PMEoQ= smoser@localhost + +# By default, the fingerprints of the authorized keys for the users +# cloud-init adds are printed to the console. Setting +# no_ssh_fingerprints to true suppresses this output. +no_ssh_fingerprints: false + +# By default, (most) ssh host keys are printed to the console. Setting +# no_keys_to_console to true suppresses this output. +no_keys_to_console: false diff --git a/tests/cloud_tests/testcases/modules/keys_to_console_disabled.py b/tests/cloud_tests/testcases/modules/keys_to_console_disabled.py new file mode 100644 index 00000000000..811c2bfbc1e --- /dev/null +++ b/tests/cloud_tests/testcases/modules/keys_to_console_disabled.py @@ -0,0 +1,16 @@ +# This file is part of cloud-init. See LICENSE file for license information. + +"""cloud-init Integration Test Verify Script.""" +from tests.cloud_tests.testcases import base + + +class TestKeysToConsole(base.CloudTestCase): + """Test proper keys are included and excluded to console.""" + + def test_excluded_keys(self): + """Test keys are not in output.""" + out = self.get_data_file('syslog') + self.assertNotIn('(DSA)', out) + self.assertNotIn('(ECDSA)', out) + +# vi: ts=4 expandtab diff --git a/tests/cloud_tests/testcases/modules/keys_to_console_disabled.yaml b/tests/cloud_tests/testcases/modules/keys_to_console_disabled.yaml new file mode 100644 index 00000000000..e62cbe2a6f5 --- /dev/null +++ b/tests/cloud_tests/testcases/modules/keys_to_console_disabled.yaml @@ -0,0 +1,14 @@ +# +# Hide printing of ssh key and fingerprints for specific keys +# +required_features: + - syslog +cloud_config: | + #cloud-config + no_keys_to_console: true +collect_scripts: + syslog: | + #!/bin/bash + cat /var/log/syslog + +# vi: ts=4 expandtab From 40a56556ef7eb177c5d0390feae0fd8c18022856 Mon Sep 17 00:00:00 2001 From: Daniel Watkins Date: Mon, 22 Feb 2021 13:15:14 -0500 Subject: [PATCH 2/5] cc_keys_to_console: use ssh namespace for configuration --- cloudinit/config/cc_keys_to_console.py | 2 +- .../config/tests/test_keys_to_console.py | 34 +++++++++++++++++++ doc/examples/cloud-config-ssh-keys.txt | 5 +-- 3 files changed, 38 insertions(+), 3 deletions(-) create mode 100644 cloudinit/config/tests/test_keys_to_console.py diff --git a/cloudinit/config/cc_keys_to_console.py b/cloudinit/config/cc_keys_to_console.py index d998a729e2c..646d1f67e34 100644 --- a/cloudinit/config/cc_keys_to_console.py +++ b/cloudinit/config/cc_keys_to_console.py @@ -51,7 +51,7 @@ def _get_helper_tool_path(distro): def handle(name, cfg, cloud, log, _args): - if util.is_true(cfg.get('no_keys_to_console', False)): + if util.is_false(cfg.get("ssh", {}).get("emit_keys_to_console", True)): log.debug(("Skipping module named %s, " "logging of SSH host keys disabled"), name) return diff --git a/cloudinit/config/tests/test_keys_to_console.py b/cloudinit/config/tests/test_keys_to_console.py new file mode 100644 index 00000000000..4083fc54cb0 --- /dev/null +++ b/cloudinit/config/tests/test_keys_to_console.py @@ -0,0 +1,34 @@ +"""Tests for cc_keys_to_console.""" +from unittest import mock + +import pytest + +from cloudinit.config import cc_keys_to_console + + +class TestHandle: + """Tests for cloudinit.config.cc_keys_to_console.handle. + + TODO: These tests only cover the emit_keys_to_console config option, they + should be expanded to cover the full functionality. + """ + + @mock.patch("cloudinit.config.cc_keys_to_console.util.multi_log") + @mock.patch("cloudinit.config.cc_keys_to_console.os.path.exists") + @mock.patch("cloudinit.config.cc_keys_to_console.subp.subp") + @pytest.mark.parametrize("cfg,subp_called", [ + ({}, True), # Default to emitting keys + ({"ssh": {}}, True), # Default even if we have the parent key + ({"ssh": {"emit_keys_to_console": True}}, True), # Explicitly enabled + ({"ssh": {"emit_keys_to_console": False}}, False), # Disabled + ]) + def test_emit_keys_to_console_config( + self, m_subp, m_path_exists, _m_multi_log, cfg, subp_called + ): + # Ensure we always find the helper + m_path_exists.return_value = True + m_subp.return_value = ("", "") + + cc_keys_to_console.handle("name", cfg, mock.Mock(), mock.Mock(), ()) + + assert subp_called == (m_subp.call_count == 1) diff --git a/doc/examples/cloud-config-ssh-keys.txt b/doc/examples/cloud-config-ssh-keys.txt index ffd2c23c097..bfe5ab44bea 100644 --- a/doc/examples/cloud-config-ssh-keys.txt +++ b/doc/examples/cloud-config-ssh-keys.txt @@ -49,5 +49,6 @@ ssh_keys: no_ssh_fingerprints: false # By default, (most) ssh host keys are printed to the console. Setting -# no_keys_to_console to true suppresses this output. -no_keys_to_console: false +# emit_keys_to_console to false suppresses this output. +ssh: + emit_keys_to_console: false From 8fcc0ece3712ff8dff452dfb9d923180174087b4 Mon Sep 17 00:00:00 2001 From: Daniel Watkins Date: Mon, 22 Feb 2021 13:45:06 -0500 Subject: [PATCH 3/5] integration_tests: port cc_keys_to_console cloud tests --- .../modules/test_keys_to_console.py | 26 +++++++++++++++++++ 1 file changed, 26 insertions(+) create mode 100644 tests/integration_tests/modules/test_keys_to_console.py diff --git a/tests/integration_tests/modules/test_keys_to_console.py b/tests/integration_tests/modules/test_keys_to_console.py new file mode 100644 index 00000000000..d072f2777fc --- /dev/null +++ b/tests/integration_tests/modules/test_keys_to_console.py @@ -0,0 +1,26 @@ +"""Integration tests for the cc_keys_to_console module. + +(This is ported from +``tests/cloud_tests/testcases/modules/keys_to_console.yaml``.)""" +import pytest + +BLACKLIST_USER_DATA = """\ +#cloud-config +ssh_fp_console_blacklist: [ssh-dss, ssh-dsa, ecdsa-sha2-nistp256] +ssh_key_console_blacklist: [ssh-dss, ssh-dsa, ecdsa-sha2-nistp256] +""" + + + +@pytest.mark.user_data(BLACKLIST_USER_DATA) +class TestKeysToConsoleBlacklist: + """Test that the blacklist options work as expected.""" + @pytest.mark.parametrize("key_type", ["DSA", "ECDSA"]) + def test_excluded_keys(self, class_client, key_type): + syslog = class_client.read_from_file("/var/log/syslog") + assert "({})".format(key_type) not in syslog + + @pytest.mark.parametrize("key_type", ["ED25519", "RSA"]) + def test_included_keys(self, class_client, key_type): + syslog = class_client.read_from_file("/var/log/syslog") + assert "({})".format(key_type) in syslog From ad019142a27ec1c3e6ddac16d80c10354ed6d5a4 Mon Sep 17 00:00:00 2001 From: Daniel Watkins Date: Mon, 22 Feb 2021 13:53:34 -0500 Subject: [PATCH 4/5] integration_tests: add tests for disabling cc_keys_to_console --- .../modules/test_keys_to_console.py | 22 +++++++++++++++++++ 1 file changed, 22 insertions(+) diff --git a/tests/integration_tests/modules/test_keys_to_console.py b/tests/integration_tests/modules/test_keys_to_console.py index d072f2777fc..298c9e6daca 100644 --- a/tests/integration_tests/modules/test_keys_to_console.py +++ b/tests/integration_tests/modules/test_keys_to_console.py @@ -10,6 +10,11 @@ ssh_key_console_blacklist: [ssh-dss, ssh-dsa, ecdsa-sha2-nistp256] """ +DISABLED_USER_DATA = """\ +#cloud-config +ssh: + emit_keys_to_console: false +""" @pytest.mark.user_data(BLACKLIST_USER_DATA) @@ -24,3 +29,20 @@ def test_excluded_keys(self, class_client, key_type): def test_included_keys(self, class_client, key_type): syslog = class_client.read_from_file("/var/log/syslog") assert "({})".format(key_type) in syslog + + +@pytest.mark.user_data(DISABLED_USER_DATA) +class TestKeysToConsoleDisabled: + """Test that output can be fully disabled.""" + @pytest.mark.parametrize("key_type", ["DSA", "ECDSA", "ED25519", "RSA"]) + def test_keys_excluded(self, class_client, key_type): + syslog = class_client.read_from_file("/var/log/syslog") + assert "({})".format(key_type) not in syslog + + def test_header_excluded(self, class_client): + syslog = class_client.read_from_file("/var/log/syslog") + assert "BEGIN SSH HOST KEY FINGERPRINTS" not in syslog + + def test_footer_excluded(self, class_client): + syslog = class_client.read_from_file("/var/log/syslog") + assert "END SSH HOST KEY FINGERPRINTS" not in syslog From 7b9d8d1ae0ab168427486324c43cda2d0fc3555c Mon Sep 17 00:00:00 2001 From: Daniel Watkins Date: Mon, 22 Feb 2021 13:55:01 -0500 Subject: [PATCH 5/5] Drop cloud_tests --- .../modules/keys_to_console_disabled.py | 16 ---------------- .../modules/keys_to_console_disabled.yaml | 14 -------------- 2 files changed, 30 deletions(-) delete mode 100644 tests/cloud_tests/testcases/modules/keys_to_console_disabled.py delete mode 100644 tests/cloud_tests/testcases/modules/keys_to_console_disabled.yaml diff --git a/tests/cloud_tests/testcases/modules/keys_to_console_disabled.py b/tests/cloud_tests/testcases/modules/keys_to_console_disabled.py deleted file mode 100644 index 811c2bfbc1e..00000000000 --- a/tests/cloud_tests/testcases/modules/keys_to_console_disabled.py +++ /dev/null @@ -1,16 +0,0 @@ -# This file is part of cloud-init. See LICENSE file for license information. - -"""cloud-init Integration Test Verify Script.""" -from tests.cloud_tests.testcases import base - - -class TestKeysToConsole(base.CloudTestCase): - """Test proper keys are included and excluded to console.""" - - def test_excluded_keys(self): - """Test keys are not in output.""" - out = self.get_data_file('syslog') - self.assertNotIn('(DSA)', out) - self.assertNotIn('(ECDSA)', out) - -# vi: ts=4 expandtab diff --git a/tests/cloud_tests/testcases/modules/keys_to_console_disabled.yaml b/tests/cloud_tests/testcases/modules/keys_to_console_disabled.yaml deleted file mode 100644 index e62cbe2a6f5..00000000000 --- a/tests/cloud_tests/testcases/modules/keys_to_console_disabled.yaml +++ /dev/null @@ -1,14 +0,0 @@ -# -# Hide printing of ssh key and fingerprints for specific keys -# -required_features: - - syslog -cloud_config: | - #cloud-config - no_keys_to_console: true -collect_scripts: - syslog: | - #!/bin/bash - cat /var/log/syslog - -# vi: ts=4 expandtab