blob: 7b9c0e8d493ec323fb3770806db23b13b15e306c [file] [log] [blame]
From: varsha teratipally <teratipally@google.com>
Date: Thu, 3 Dec 2020 23:52:59 +0000
Subject: [PATCH] Make UID generation more stable/predictable.
Below is the original commit message:
-----------------------------------------------------------------------
This patch modifies users-groups with the goal of making it behave better in
configuration where /etc/passwd is stateless. Specifically it:
- adds 'uid' options so that UIDs can be set from cloud-config, that is
now recommended and a warning is generated if some users do not have that
option;
- reserves range [2000, 5000) for UIDs created by cloud-init;
- makes sure that users are created in the alphabetical order to provide
more predictable and consistent UIDs;
- adds a requirement that if homedir already exists the UID assigned to user
must be the same as the owner of that directory, this is to protect from
assigning incorrect UIDs after config changes.
Original Author: Andrey Ulanov <andreyu@google.com>
Original Date: Thu Feb 25 18:41:48 2016 -0800
-----------------------------------------------------------------------
check uid value's sanity and specify gid range
Original Author: Edward Hyunkoo Jee <edjee@google.com>
Original Date: Fri Apr 05 00:00:00 2019 -0800
-----------------------------------------------------------------------
cloudinit/config/cc_users_groups.py | 32 +++++++++++++++++++++++++++++
cloudinit/distros/__init__.py | 23 +++++++++++++++++++--
2 files changed, 53 insertions(+), 2 deletions(-)
diff --git a/cloudinit/config/cc_users_groups.py b/cloudinit/config/cc_users_groups.py
index 13764e60..d0339510 100644
--- a/cloudinit/config/cc_users_groups.py
+++ b/cloudinit/config/cc_users_groups.py
@@ -128,6 +128,9 @@ from cloudinit import log as logging
from cloudinit.settings import PER_INSTANCE
+import os
+import pwd
+
LOG = logging.getLogger(__name__)
frequency = PER_INSTANCE
@@ -139,6 +142,8 @@ def handle(name, cfg, cloud, _log, _args):
cloud_keys = cloud.get_public_ssh_keys() or []
for (name, members) in groups.items():
cloud.distro.create_group(name, members)
+
+ # First create all users that have UID explicitly specified in cloud-config.
for (user, config) in users.items():
ssh_redirect_user = config.pop("ssh_redirect_user", False)
if ssh_redirect_user:
@@ -162,6 +167,33 @@ def handle(name, cfg, cloud, _log, _args):
else:
config['ssh_redirect_user'] = default_user
config['cloud_public_ssh_keys'] = cloud_keys
+ if 'uid' in config:
+ config['uid'] = str(config['uid'])
+ cloud.distro.create_user(user, **config)
+
+ # dict is an unordered container. To make UIDs assigned to users more
+ # predictable we sort them by the name and create accounts in that order.
+ nouids = []
+ for user in sorted(users):
+ config = users[user]
+ if 'uid' in config:
+ continue
+ nouids.append(user)
+
cloud.distro.create_user(user, **config)
+ pw = pwd.getpwnam(user)
+
+ homedir = config['homedir'] if 'homedir' in config else ('/home/%s' % user)
+ if os.path.isdir(homedir):
+ stats = os.stat(homedir)
+ if stats.st_uid != pw.pw_uid:
+ LOG.error('UID %d was assigned to user %s, but homedir %s '
+ 'is owned by %d', pw.pw_uid, user, homedir, stats.st_uid)
+ raise
+
+ if nouids:
+ LOG.warn('No explicit UID specified for the following users: %s. '
+ 'UID may change after reboot.', ', '.join(nouids))
+
# vi: ts=4 expandtab
diff --git a/cloudinit/distros/__init__.py b/cloudinit/distros/__init__.py
index 92598a2d..004b24ce 100755
--- a/cloudinit/distros/__init__.py
+++ b/cloudinit/distros/__init__.py
@@ -384,6 +384,10 @@ class Distro(metaclass=abc.ABCMeta):
# XXX need to make add_user idempotent somehow as we
# still want to add groups or modify SSH keys on pre-existing
# users in the image.
+
+ UID_GID_MIN = 2000
+ UID_GID_MAX = 4999
+
if util.is_user(name):
LOG.info("User %s already exists, skipping.", name)
return
@@ -393,8 +397,23 @@ class Distro(metaclass=abc.ABCMeta):
else:
create_groups = True
- useradd_cmd = ['useradd', name]
- log_useradd_cmd = ['useradd', name]
+ if 'uid' in kwargs:
+ try:
+ uid = int(kwargs['uid'])
+ if uid < UID_GID_MIN or uid > UID_GID_MAX:
+ LOG.warn('UID %d is not in [%d, %d]',
+ uid, UID_GID_MIN, UID_GID_MAX)
+ except ValueError as e:
+ LOG.error("Wrong uid: %s", kwargs['uid'])
+ return
+
+ useradd_cmd = ['useradd', name,
+ '-K', 'UID_MIN=%d' % UID_GID_MIN,
+ '-K', 'UID_MAX=%d' % UID_GID_MAX,
+ '-K', 'GID_MIN=%d' % UID_GID_MIN,
+ '-K', 'GID_MAX=%d' % UID_GID_MAX]
+
+ log_useradd_cmd = useradd_cmd[:]
if util.system_is_snappy():
useradd_cmd.append('--extrausers')
log_useradd_cmd.append('--extrausers')
--
2.29.2.576.ga3fc446d84-goog