Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
235 changes: 124 additions & 111 deletions cloudinit/config/cc_users_groups.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,72 +4,48 @@
#
# This file is part of cloud-init. See LICENSE file for license information.

"""
Users and Groups
----------------
**Summary:** configure users and groups
"Users and Groups: Configure users and groups"

from textwrap import dedent

from cloudinit import log as logging
from cloudinit.config.schema import MetaSchema, get_meta_doc

# Ensure this is aliased to a name not 'distros'
# since the module attribute 'distros'
# is a list of distros that are supported, not a sub-module
from cloudinit.distros import ug_util
from cloudinit.settings import PER_INSTANCE

MODULE_DESCRIPTION = """\
This module configures users and groups. For more detailed information on user
options, see the ``Including users and groups`` config example.

Groups to add to the system can be specified as a list under the ``groups``
key. Each entry in the list should either contain a the group name as a string,
or a dictionary with the group name as the key and a list of users who should
be members of the group as the value. **Note**: Groups are added before users,
so any users in a group list must already exist on the system.

The ``users`` config key takes a list of users to configure. The first entry in
this list is used as the default user for the system. To preserve the standard
default user for the distro, the string ``default`` may be used as the first
entry of the ``users`` list. Each entry in the ``users`` list, other than a
``default`` entry, should be a dictionary of options for the user. Supported
config keys for an entry in ``users`` are as follows:

- ``name``: The user's login name
- ``expiredate``: Optional. Date on which the user's account will be
disabled. Default: none
- ``gecos``: Optional. Comment about the user, usually a comma-separated
string of real name and contact information. Default: none
- ``groups``: Optional. Additional groups to add the user to. Default: none
- ``homedir``: Optional. Home dir for user. Default is ``/home/<username>``
- ``inactive``: Optional. Number of days after a password expires until
the account is permanently disabled. Default: none
- ``lock_passwd``: Optional. Disable password login. Default: true
- ``no_create_home``: Optional. Do not create home directory. Default:
false
- ``no_log_init``: Optional. Do not initialize lastlog and faillog for
user. Default: false
- ``no_user_group``: Optional. Do not create group named after user.
Default: false
- ``passwd``: Hash of user password
- ``primary_group``: Optional. Primary group for user. Default to new group
named after user.
- ``selinux_user``: Optional. SELinux user for user's login. Default to
default SELinux user.
- ``shell``: Optional. The user's login shell. The default is to set no
shell, which results in a system-specific default being used.
- ``snapuser``: Optional. Specify an email address to create the user as
a Snappy user through ``snap create-user``. If an Ubuntu SSO account is
associated with the address, username and SSH keys will be requested from
there. Default: none
- ``ssh_authorized_keys``: Optional. List of SSH keys to add to user's
authkeys file. Default: none. This key can not be combined with
``ssh_redirect_user``.
- ``ssh_import_id``: Optional. SSH id to import for user. Default: none.
This key can not be combined with ``ssh_redirect_user``.
- ``ssh_redirect_user``: Optional. Boolean set to true to disable SSH
logins for this user. When specified, all cloud meta-data public SSH
keys will be set up in a disabled state for this username. Any SSH login
as this username will timeout and prompt with a message to login instead
as the configured <default_username> for this instance. Default: false.
This key can not be combined with ``ssh_import_id`` or
``ssh_authorized_keys``.
- ``sudo``: Optional. Sudo rule to use, list of sudo rules to use or False.
Default: none. An absence of sudo key, or a value of none or false
will result in no sudo rules being written for the user.
- ``system``: Optional. Create user as system user with no home directory.
Default: false
- ``uid``: Optional. The user's ID. Default: The next available value.
options, see the :ref:`Including users and groups<yaml_examples>` config
example.

Groups to add to the system can be specified under the ``groups`` key as
a string of comma-separated groups to create, or a list. Each item in
the list should either contain a string of a single group to create,
or a dictionary with the group name as the key and string of a single user as
a member of that group or a list of users who should be members of the group.

.. note::
Groups are added before users, so any users in a group list must
already exist on the system.

Users to add can be specified as a string or list under the ``users`` key.
Each entry in the list should either be a string or a dictionary. If a string
is specified, that string can be comma-separated usernames to create or the
reserved string ``default`` which represents the primary admin user used to
access the system. The ``default`` user varies per distribution and is
generally configured in ``/etc/cloud/cloud.cfg`` by the ``default_user`` key.

Each ``users`` dictionary item must contain either a ``name`` or ``snapuser``
key, otherwise it will be ignored. Omission of ``default`` as the first item
in the ``users`` list skips creation the default user. If no ``users`` key is
provided the default behavior is to create the default user via this config::

users:
- default

.. note::
Specifying a hash of a user's password with ``passwd`` is a security risk
Expand All @@ -85,60 +61,97 @@
to already-existing users: ``plain_text_passwd``, ``hashed_passwd``,
``lock_passwd``, ``sudo``, ``ssh_authorized_keys``, ``ssh_redirect_user``.

**Internal name:** ``cc_users_groups``

**Module frequency:** per instance

**Supported distros:** all

**Config keys**::

groups:
- <group>: [<user>, <user>]
- <group>
The ``user`` key can be used to override the ``default_user`` configuration
defined in ``/etc/cloud/cloud.cfg``. The ``user`` value should be a dictionary
which supports the same config keys as the ``users`` dictionary items.
"""

users:
meta: MetaSchema = {
"id": "cc_users_groups",
"name": "Users and Groups",
"title": "Configure users and groups",
"description": MODULE_DESCRIPTION,
"distros": ["all"],
"examples": [
dedent(
"""\
# Add the ``default_user`` from /etc/cloud/cloud.cfg.
# This is also the default behavior of cloud-init when no `users` key
# is provided.
users:
- default
"""
),
dedent(
"""\
# Add the 'admingroup' with members 'root' and 'sys' and an empty
# group cloud-users.
groups:
- admingroup: [root,sys]
- cloud-users
"""
),
dedent(
"""\
# Skip creation of the <default> user and only create newsuper.
# Password-based login is rejected, but the github user TheRealFalcon
# and the launchpad user falcojr can SSH as newsuper. The default
# shell for newsuper is bash instead of system default.
users:
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think it'd be worthwhile to add the default user to the example and make it the first example. Something like this is probably the most common use case, so I think it makes sense to have it be first. We could remove default from example 3.

- name: newsuper
gecos: Big Stuff
groups: users, admin
sudo: ALL=(ALL) NOPASSWD:ALL
shell: /bin/bash
lock_passwd: true
ssh_import_id:
- lp:falcojr
- gh:TheRealFalcon
"""
),
dedent(
"""\
# On a system with SELinux enabled, add youruser and set the
# SELinux user to 'staff_u'. When omitted on SELinux, the system will
# select the configured default SELinux user.
users:
- default
# User explicitly omitted from sudo permission; also default behavior.
- name: <some_restricted_user>
- name: youruser
selinux_user: staff_u
"""
),
dedent(
"""\
# To redirect a legacy username to the <default> user for a
# distribution, ssh_redirect_user will accept an SSH connection and
# emit a message telling the client to ssh as the <default> user.
# SSH clients will get the message:
users:
- default
- name: nosshlogins
ssh_redirect_user: true
"""
),
dedent(
"""\
# Override any ``default_user`` config in /etc/cloud/cloud.cfg with
# supplemental config options.
# This config will make the default user to mynewdefault and change
# the user to not have sudo rights.
ssh_import_id: [chad.smith]
user:
name: mynewdefault
sudo: false
- name: <username>
expiredate: '<date>'
gecos: <comment>
groups: <additional groups>
homedir: <home directory>
inactive: '<number of days>'
lock_passwd: <true/false>
no_create_home: <true/false>
no_log_init: <true/false>
no_user_group: <true/false>
passwd: <password>
primary_group: <primary group>
selinux_user: <selinux username>
shell: <shell path>
snapuser: <email>
ssh_redirect_user: <true/false>
ssh_authorized_keys:
- <key>
- <key>
ssh_import_id: <id>
sudo: <sudo config>
system: <true/false>
uid: <user id>
"""
"""
),
],
"frequency": PER_INSTANCE,
}

from cloudinit import log as logging

# Ensure this is aliased to a name not 'distros'
# since the module attribute 'distros'
# is a list of distros that are supported, not a sub-module
from cloudinit.distros import ug_util
from cloudinit.settings import PER_INSTANCE
__doc__ = get_meta_doc(meta)

LOG = logging.getLogger(__name__)

frequency = PER_INSTANCE


def handle(name, cfg, cloud, _log, _args):
(users, groups) = ug_util.normalize_users_groups(cfg, cloud.distro)
Expand Down
Loading