summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rwxr-xr-xcloudinit/config/cc_set_passwords.py48
-rw-r--r--doc/examples/cloud-config.txt9
-rw-r--r--tests/cloud_tests/configs/modules/set_password_list.yaml3
-rw-r--r--tests/cloud_tests/configs/modules/set_password_list_string.yaml3
-rw-r--r--tests/cloud_tests/testcases/base.py4
5 files changed, 53 insertions, 14 deletions
diff --git a/cloudinit/config/cc_set_passwords.py b/cloudinit/config/cc_set_passwords.py
index 8440e593..eb0bdab0 100755
--- a/cloudinit/config/cc_set_passwords.py
+++ b/cloudinit/config/cc_set_passwords.py
@@ -23,7 +23,8 @@ If the ``list`` key is provided, a list of
``username:password`` pairs can be specified. The usernames specified
must already exist on the system, or have been created using the
``cc_users_groups`` module. A password can be randomly generated using
-``username:RANDOM`` or ``username:R``. Password ssh authentication can be
+``username:RANDOM`` or ``username:R``. A hashed password can be specified
+using ``username:$6$salt$hash``. Password ssh authentication can be
enabled, disabled, or left to system defaults using ``ssh_pwauth``.
.. note::
@@ -60,8 +61,10 @@ enabled, disabled, or left to system defaults using ``ssh_pwauth``.
- user2:RANDOM
- user3:password3
- user4:R
+ - user4:$6$rL..$ej...
"""
+import re
import sys
from cloudinit.distros import ug_util
@@ -112,24 +115,43 @@ def handle(_name, cfg, cloud, log, args):
errors = []
if plist:
plist_in = []
+ hashed_plist_in = []
+ hashed_users = []
randlist = []
users = []
+ prog = re.compile(r'\$[1,2a,2y,5,6](\$.+){2}')
for line in plist:
u, p = line.split(':', 1)
- if p == "R" or p == "RANDOM":
- p = rand_user_password()
- randlist.append("%s:%s" % (u, p))
- plist_in.append("%s:%s" % (u, p))
- users.append(u)
+ if prog.match(p) is not None and ":" not in p:
+ hashed_plist_in.append("%s:%s" % (u, p))
+ hashed_users.append(u)
+ else:
+ if p == "R" or p == "RANDOM":
+ p = rand_user_password()
+ randlist.append("%s:%s" % (u, p))
+ plist_in.append("%s:%s" % (u, p))
+ users.append(u)
ch_in = '\n'.join(plist_in) + '\n'
- try:
- log.debug("Changing password for %s:", users)
- util.subp(['chpasswd'], ch_in)
- except Exception as e:
- errors.append(e)
- util.logexc(log, "Failed to set passwords with chpasswd for %s",
- users)
+ if users:
+ try:
+ log.debug("Changing password for %s:", users)
+ util.subp(['chpasswd'], ch_in)
+ except Exception as e:
+ errors.append(e)
+ util.logexc(
+ log, "Failed to set passwords with chpasswd for %s", users)
+
+ hashed_ch_in = '\n'.join(hashed_plist_in) + '\n'
+ if hashed_users:
+ try:
+ log.debug("Setting hashed password for %s:", hashed_users)
+ util.subp(['chpasswd', '-e'], hashed_ch_in)
+ except Exception as e:
+ errors.append(e)
+ util.logexc(
+ log, "Failed to set hashed passwords with chpasswd for %s",
+ hashed_users)
if len(randlist):
blurb = ("Set the following 'random' passwords\n",
diff --git a/doc/examples/cloud-config.txt b/doc/examples/cloud-config.txt
index c03f1026..bd84c641 100644
--- a/doc/examples/cloud-config.txt
+++ b/doc/examples/cloud-config.txt
@@ -426,14 +426,21 @@ syslog_fix_perms: syslog:root
#
# there is also an option to set multiple users passwords, using 'chpasswd'
# That looks like the following, with 'expire' set to 'True' by default.
-# to not expire users passwords, set 'expire' to 'False':
+# to not expire users passwords, set 'expire' to 'False'. Also possible
+# to set hashed password, here account 'user3' has a password it set to
+# 'cloud-init', hashed with SHA-256:
# chpasswd:
# list: |
# user1:password1
# user2:RANDOM
+# user3:$5$eriogqzq$Dg7PxHsKGzziuEGkZgkLvacjuEFeljJ.rLf.hZqKQLA
# expire: True
# ssh_pwauth: [ True, False, "" or "unchanged" ]
#
+# Hashed passwords can be generated in multiple ways, example with python3:
+# python3 -c 'import crypt,getpass; print(crypt.crypt(getpass.getpass(), crypt.mksalt(crypt.METHOD_SHA512)))'
+# Newer versions of 'mkpasswd' will also work: mkpasswd -m sha-512 password
+#
# So, a simple working example to allow login via ssh, and not expire
# for the default user would look like:
password: passw0rd
diff --git a/tests/cloud_tests/configs/modules/set_password_list.yaml b/tests/cloud_tests/configs/modules/set_password_list.yaml
index a1eadd75..a2a89c9d 100644
--- a/tests/cloud_tests/configs/modules/set_password_list.yaml
+++ b/tests/cloud_tests/configs/modules/set_password_list.yaml
@@ -21,11 +21,14 @@ cloud_config: |
# sha256 gojanego
passwd: "$5$iW$XsxmWCdpwIW8Yhv.Jn/R3uk6A4UaicfW5Xp7C9p9pg."
lock_passwd: false
+ - name: "mikey"
+ lock_passwd: false
chpasswd:
list:
- tom:mypassword123!
- dick:RANDOM
- harry:RANDOM
+ - mikey:$5$xZ$B2YGGEx2AOf4PeW48KC6.QyT1W2B4rZ9Qbltudtha89
collect_scripts:
shadow: |
#!/bin/bash
diff --git a/tests/cloud_tests/configs/modules/set_password_list_string.yaml b/tests/cloud_tests/configs/modules/set_password_list_string.yaml
index cbb71bee..c2a0f631 100644
--- a/tests/cloud_tests/configs/modules/set_password_list_string.yaml
+++ b/tests/cloud_tests/configs/modules/set_password_list_string.yaml
@@ -21,11 +21,14 @@ cloud_config: |
# sha256 gojanego
passwd: "$5$iW$XsxmWCdpwIW8Yhv.Jn/R3uk6A4UaicfW5Xp7C9p9pg."
lock_passwd: false
+ - name: "mikey"
+ lock_passwd: false
chpasswd:
list: |
tom:mypassword123!
dick:RANDOM
harry:RANDOM
+ mikey:$5$xZ$B2YGGEx2AOf4PeW48KC6.QyT1W2B4rZ9Qbltudtha89
collect_scripts:
shadow: |
#!/bin/bash
diff --git a/tests/cloud_tests/testcases/base.py b/tests/cloud_tests/testcases/base.py
index 51ce2b41..64d5507a 100644
--- a/tests/cloud_tests/testcases/base.py
+++ b/tests/cloud_tests/testcases/base.py
@@ -98,6 +98,9 @@ class PasswordListTest(CloudTestCase):
self.assertEqual([], dupes)
self.assertEqual(jane_enc, users['jane'])
+ mikey_enc = "$5$xZ$B2YGGEx2AOf4PeW48KC6.QyT1W2B4rZ9Qbltudtha89"
+ self.assertEqual(mikey_enc, users['mikey'])
+
# shadow entry is $N$salt$, so we encrypt with the same format
# and salt and expect the result.
tom = "mypassword123!"
@@ -124,6 +127,7 @@ class PasswordListTest(CloudTestCase):
self.assertIn('dick:', out)
self.assertIn('harry:', out)
self.assertIn('jane:', out)
+ self.assertIn('mikey:', out)
def test_sshd_config(self):
"""Test sshd config allows passwords"""