diff --git a/src/pylorax/api/compose.py b/src/pylorax/api/compose.py index 9adf09c3..4926a49e 100644 --- a/src/pylorax/api/compose.py +++ b/src/pylorax/api/compose.py @@ -122,6 +122,8 @@ def write_ks_root(f, user): :type f: open file object :param user: A blueprint user dictionary :type user: dict + :returns: True if it wrote a rootpw command to the kickstart + :rtype: bool If the entry contains a ssh key, use sshkey to write it If it contains password, use rootpw to set it @@ -129,6 +131,8 @@ def write_ks_root(f, user): root cannot be used with the user command. So only key and password are supported for root. """ + wrote_rootpw = False + # ssh key uses the sshkey kickstart command if "key" in user: f.write('sshkey --user %s "%s"\n' % (user["name"], user["key"])) @@ -137,9 +141,13 @@ def write_ks_root(f, user): if any(user["password"].startswith(prefix) for prefix in ["$2b$", "$6$", "$5$"]): log.debug("Detected pre-crypted password") f.write('rootpw --iscrypted "%s"\n' % user["password"]) + wrote_rootpw = True else: log.debug("Detected plaintext password") f.write('rootpw --plaintext "%s"\n' % user["password"]) + wrote_rootpw = True + + return wrote_rootpw def write_ks_user(f, user): """ Write kickstart user and sshkey entry @@ -221,6 +229,7 @@ def add_customizations(f, recipe): :raises: RuntimeError if there was a problem writing to the kickstart """ if "customizations" not in recipe: + f.write('rootpw --lock\n') return customizations = recipe["customizations"] @@ -238,6 +247,8 @@ def add_customizations(f, recipe): # Creating a user also creates a group. Make a list of the names for later user_groups = [] + # kickstart requires a rootpw line + wrote_rootpw = False if "user" in customizations: # only name is required, everything else is optional for user in customizations["user"]: @@ -246,7 +257,7 @@ def add_customizations(f, recipe): # root is special, cannot use normal user command for it if user["name"] == "root": - write_ks_root(f, user) + wrote_rootpw = write_ks_root(f, user) continue write_ks_user(f, user) @@ -259,6 +270,10 @@ def add_customizations(f, recipe): else: log.warning("Skipping group %s, already created by user", group["name"]) + # Lock the root account if no root user password has been specified + if not wrote_rootpw: + f.write('rootpw --lock\n') + def start_build(cfg, dnflock, gitlock, branch, recipe_name, compose_type, test_mode=0): """ Start the build diff --git a/tests/pylorax/test_compose.py b/tests/pylorax/test_compose.py index 99f9522c..af265a83 100644 --- a/tests/pylorax/test_compose.py +++ b/tests/pylorax/test_compose.py @@ -95,6 +95,7 @@ name = "tester" KS_USER_ALL = '''sshkey --user tester "A SSH KEY FOR THE USER" user --name tester --homedir /opt/users/tester/ --iscrypted --password "$6$CHO2$3rN8eviE2t50lmVyBYihTgVRHcaecmeCk31LeOUleVK/R/aeWVHVZDi26zAH.o0ywBKH9Tc0/wm7sW/q39uyd1" --shell /usr/bin/zsh --uid 1013 --gid 4242 --gecos "a test user account" +rootpw --lock ''' # ROOT TESTS @@ -117,9 +118,14 @@ class CustomizationsTestCase(unittest.TestCase): add_customizations(f, r) self.assertTrue(result not in f.getvalue(), f.getvalue()) + def test_no_customizations(self): + """Test not setting any customizations""" + self.assertCustomization(BASE_RECIPE, "rootpw --lock") + def test_set_hostname(self): """Test setting the hostname""" self.assertCustomization(HOSTNAME, "network --hostname=testhostname") + self.assertCustomization(HOSTNAME, "rootpw --lock") def test_set_sshkey(self): """Test setting sshkey without user""" @@ -128,42 +134,52 @@ class CustomizationsTestCase(unittest.TestCase): def test_sshkey_only(self): """Test adding a sshkey to an existing user account""" self.assertCustomization(USER + USER_KEY, 'sshkey --user tester "A SSH KEY FOR THE USER"') + self.assertCustomization(USER + USER_KEY, "rootpw --lock") def test_create_user(self): """Test creating a user with no options""" self.assertCustomization(USER, "user --name tester") + self.assertCustomization(USER, "rootpw --lock") def test_create_user_desc(self): """Test creating a user with a description""" self.assertCustomization(USER + USER_DESC, '--gecos "a test user account"') + self.assertCustomization(USER + USER_DESC, "rootpw --lock") def test_create_user_crypt(self): """Test creating a user with a pre-crypted password""" self.assertCustomization(USER + USER_CRYPT, '--password "$6$CHO2$3r') + self.assertCustomization(USER + USER_CRYPT, "rootpw --lock") def test_create_user_plain(self): """Test creating a user with a plaintext password""" self.assertCustomization(USER + USER_PLAIN, '--password "plainpassword"') + self.assertCustomization(USER + USER_PLAIN, "rootpw --lock") def test_create_user_home(self): """Test creating user with a home directory""" self.assertCustomization(USER + USER_HOME, "--homedir /opt/users/tester/") + self.assertCustomization(USER + USER_HOME, "rootpw --lock") def test_create_user_shell(self): """Test creating user with shell set""" self.assertCustomization(USER + USER_SHELL, "--shell /usr/bin/zsh") + self.assertCustomization(USER + USER_SHELL, "rootpw --lock") def test_create_user_uid(self): """Test creating user with uid set""" self.assertCustomization(USER + USER_UID, "--uid 1013") + self.assertCustomization(USER + USER_UID, "rootpw --lock") def test_create_user_gid(self): """Test creating user with gid set""" self.assertCustomization(USER + USER_GID, "--gid 4242") + self.assertCustomization(USER + USER_GID, "rootpw --lock") def test_create_user_groups(self): """Test creating user with group membership""" self.assertCustomization(USER + USER_GROUPS, "--groups wheel,users") + self.assertCustomization(USER + USER_GROUPS, "rootpw --lock") def test_user_same_group(self): """Test creating a group with the same name as a user""" @@ -171,6 +187,7 @@ class CustomizationsTestCase(unittest.TestCase): # Creating a group with the same name should skip the group creation self.assertCustomization(USER_GROUP, "user --name tester") self.assertNotCustomization(USER_GROUP, "group --name tester") + self.assertCustomization(USER_GROUP, "rootpw --lock") def test_create_user_all(self): """Test creating user with all settings""" @@ -182,21 +199,27 @@ class CustomizationsTestCase(unittest.TestCase): def test_create_group(self): """Test creating group without gid set""" self.assertCustomization(GROUP, "group --name testgroup") + self.assertCustomization(GROUP, "rootpw --lock") def test_create_group_gid(self): """Test creating group with gid set""" self.assertCustomization(GROUP_GID, "group --name testgroup --gid 1011") + self.assertCustomization(GROUP_GID, "rootpw --lock") def test_root_crypt(self): self.assertCustomization(ROOT_CRYPT, 'rootpw --iscrypted "$6$CHO2$3r') + self.assertNotCustomization(ROOT_CRYPT, "rootpw --lock") def test_root_plain(self): self.assertCustomization(ROOT_PLAIN, 'rootpw --plaintext "plainpassword"') + self.assertNotCustomization(ROOT_PLAIN, "rootpw --lock") def test_root_crypt_key(self): self.assertCustomization(ROOT_CRYPT_KEY, 'rootpw --iscrypted "$6$CHO2$3r') self.assertCustomization(ROOT_CRYPT_KEY, 'sshkey --user root "A SSH KEY FOR THE USER"') + self.assertNotCustomization(ROOT_CRYPT_KEY, "rootpw --lock") def test_root_plain_key(self): self.assertCustomization(ROOT_PLAIN_KEY, 'rootpw --plaintext "plainpassword"') self.assertCustomization(ROOT_PLAIN_KEY, 'sshkey --user root "A SSH KEY FOR THE USER"') + self.assertNotCustomization(ROOT_PLAIN_KEY, "rootpw --lock")