← Back to team overview

cloud-init-dev team mailing list archive

[Merge] ~tore.lonoy/cloud-init:hashed-chpasswd-support into cloud-init:master

 

Tore has proposed merging ~tore.lonoy/cloud-init:hashed-chpasswd-support into cloud-init:master.

Commit message:
Add support for setting hashed passwords

This change will add support for hashed passwords in cc_set_passwords.
It checks if a password is a hash with this if/regxp statement:
re.match(r'\$[1,2a,2y,5,6](\$.+){2}', p) is not None and ":" not in p:

chpasswd needs to know if the password is hashed or not, so two lists
is created so chpasswd is feed with the correct one.

Requested reviews:
  cloud init development team (cloud-init-dev)
Related bugs:
  Bug #1570325 in cloud-init: "RFE: chpasswd in cloud-init should support hashed passwords"
  https://bugs.launchpad.net/cloud-init/+bug/1570325

For more details, see:
https://code.launchpad.net/~tore.lonoy/cloud-init/+git/cloud-init/+merge/310051

Currently only static or randomly generated passwords are supported,
adding support for hashed passwords enables the user to store password
in they configuration a little more secure then using plain-text.

I have been unable to run all the tests on the change, but I've verified
that it works by running these test manually:
* setting static password
* setting static and random
* setting hashed password
* setting hashed and static password

This is my first commit to any open-source project.
-- 
Your team cloud init development team is requested to review the proposed merge of ~tore.lonoy/cloud-init:hashed-chpasswd-support into cloud-init:master.
diff --git a/cloudinit/config/cc_set_passwords.py b/cloudinit/config/cc_set_passwords.py
index 6fc0051..db1255f 100755
--- a/cloudinit/config/cc_set_passwords.py
+++ b/cloudinit/config/cc_set_passwords.py
@@ -35,7 +35,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::
@@ -59,11 +60,13 @@ enabled, disabled, or left to system defaults using ``ssh_pwauth``.
     chpasswd:
         list:
             - user1:password1
-            - user2:Random
+            - user2:RANDOM
             - user3:password3
             - user4:R
+            - user4:$6$rL..$ej...
 """
 
+import re
 import sys
 
 from cloudinit.distros import ug_util
@@ -105,6 +108,8 @@ def handle(_name, cfg, cloud, log, args):
     errors = []
     if plist:
         plist_in = []
+        hashed_plist_in = []
+        hashed_users = []
         randlist = []
         users = []
         for line in plist.splitlines():
@@ -112,17 +117,34 @@ def handle(_name, cfg, cloud, log, args):
             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)
+            elif re.match(r'\$[1,2a,2y,5,6](\$.+){2}', p) is not None and ":" not in p:
+                hashed_plist_in.append("%s:%s" % (u, p))
+                hashed_users.append(u)
+            else:
+                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 190029e..c298249 100644
--- a/doc/examples/cloud-config.txt
+++ b/doc/examples/cloud-config.txt
@@ -431,6 +431,7 @@ syslog_fix_perms: syslog:root
 #  list: |
 #    user1:password1
 #    user2:RANDOM
+#    user3:$6$rL...b$OCJ...
 #  expire: True
 # ssh_pwauth: [ True, False, "" or "unchanged" ]
 #