mirror of
https://gitlab.alpinelinux.org/alpine/aports.git
synced 2025-07-24 03:35:38 +03:00
Upgrade cloud-init version. Remove dependency on eudev as now mdev and mdevd are also supported.
191 lines
7.2 KiB
Diff
191 lines
7.2 KiB
Diff
From: Dermot Bradley <dermot_bradley@yahoo.com>
|
|
Date: Thu, 26 Aug 2021 00:58 +0100
|
|
Subject: [PATCH] cloud-init: Add doas support
|
|
|
|
Add doas support to users_groups module.
|
|
|
|
---
|
|
|
|
diff -aur a/cloudinit/config/cc_users_groups.py b/cloudinit/config/cc_users_groups.py
|
|
--- a/cloudinit/config/cc_users_groups.py
|
|
+++ b/cloudinit/config/cc_users_groups.py
|
|
@@ -55,14 +55,20 @@
|
|
if the cloud-config can be intercepted. SSH authentication is preferred.
|
|
|
|
.. note::
|
|
+ If specifying a doas rule for a user, ensure that the syntax for the rule
|
|
+ is valid, as the only checking performed by cloud-init is to ensure that
|
|
+ the user referenced in the rule is the correct user.
|
|
+
|
|
+.. note::
|
|
If specifying a sudo rule for a user, ensure that the syntax for the rule
|
|
is valid, as it is not checked by cloud-init.
|
|
|
|
.. note::
|
|
Most of these configuration options will not be honored if the user
|
|
already exists. The following options are the exceptions; they are applied
|
|
- to already-existing users: ``plain_text_passwd``, ``hashed_passwd``,
|
|
- ``lock_passwd``, ``sudo``, ``ssh_authorized_keys``, ``ssh_redirect_user``.
|
|
+ to already-existing users: ``plain_text_passwd``, ``doas``,
|
|
+ ``hashed_passwd``, ``lock_passwd``, ``sudo``, ``ssh_authorized_keys``,
|
|
+ ``ssh_redirect_user``.
|
|
|
|
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
|
|
diff -aur a/cloudinit/config/schemas/schema-cloud-config-v1.json b/cloudinit/config/schemas/schema-cloud-config-v1.json
|
|
--- a/cloudinit/config/schemas/schema-cloud-config-v1.json
|
|
+++ b/cloudinit/config/schemas/schema-cloud-config-v1.json
|
|
@@ -142,6 +142,14 @@
|
|
"description": "The user's login name. Required otherwise user creation will be skipped for this user.",
|
|
"type": "string"
|
|
},
|
|
+ "doas": {
|
|
+ "description": "List of Doas rules to use. Absence of a doas value will result in no doas rules added for this user.",
|
|
+ "type": "array",
|
|
+ "items": {
|
|
+ "type": "string"
|
|
+ },
|
|
+ "minItems": 1
|
|
+ },
|
|
"expiredate": {
|
|
"default": null,
|
|
"description": "Optional. Date on which the user's account will be disabled. Default: ``null``",
|
|
diff -aur a/cloudinit/distros/__init__.py b/cloudinit/distros/__init__.py
|
|
--- a/cloudinit/distros/__init__.py
|
|
+++ b/cloudinit/distros/__init__.py
|
|
@@ -84,6 +84,7 @@
|
|
pip_package_name = "python3-pip"
|
|
usr_lib_exec = "/usr/lib"
|
|
hosts_fn = "/etc/hosts"
|
|
+ ci_doas_fn = "/etc/doas.d/cloud-init.conf"
|
|
ci_sudoers_fn = "/etc/sudoers.d/90-cloud-init-users"
|
|
hostname_conf_fn = "/etc/hostname"
|
|
tz_zone_dir = "/usr/share/zoneinfo"
|
|
@@ -643,6 +644,7 @@
|
|
* ``plain_text_passwd``
|
|
* ``hashed_passwd``
|
|
* ``lock_passwd``
|
|
+ * ``doas``
|
|
* ``sudo``
|
|
* ``ssh_authorized_keys``
|
|
* ``ssh_redirect_user``
|
|
@@ -668,6 +670,11 @@
|
|
if kwargs.get("lock_passwd", True):
|
|
self.lock_passwd(name)
|
|
|
|
+ # Configure doas access
|
|
+ if 'doas' in kwargs:
|
|
+ if kwargs['doas']:
|
|
+ self.write_doas_rules(name, kwargs['doas'])
|
|
+
|
|
# Configure sudo access
|
|
if "sudo" in kwargs:
|
|
if kwargs["sudo"]:
|
|
@@ -773,6 +780,85 @@
|
|
cmd = ["chpasswd"] + (["-e"] if hashed else [])
|
|
subp.subp(cmd, payload)
|
|
|
|
+ def ensure_doas_dir(self, path):
|
|
+ # Ensure the directory actually exists
|
|
+ util.ensure_dir(path, 0o750)
|
|
+
|
|
+ def is_doas_rule_valid(self, user, rule):
|
|
+ rule_pattern = r"^(?:permit|deny)" + \
|
|
+ r"(?:\s+(?:nolog|nopass|persist|keepenv|setenv \{[^}]+\})+)*" + \
|
|
+ r"\s+([a-zA-Z0-9_]+)+" + \
|
|
+ r"(?:\s+as\s+[a-zA-Z0-9_]+)*" + \
|
|
+ r"(?:\s+cmd\s+[^\s]+(?:\s+args\s+[^\s]+(?:\s*[^\s]+)*)*)*" + \
|
|
+ r"\s*$"
|
|
+
|
|
+ LOG.debug("Checking if user '%s' is referenced in doas rule %r",
|
|
+ user, rule)
|
|
+
|
|
+ valid_match = re.search(rule_pattern, rule)
|
|
+ if valid_match:
|
|
+ LOG.debug("User '%s' referenced in doas rule",
|
|
+ valid_match.group(1))
|
|
+ if valid_match.group(1) == user:
|
|
+ LOG.debug("Correct user is referenced in doas rule")
|
|
+ return True
|
|
+ else:
|
|
+ LOG.debug("Incorrect user '%s' is referenced in doas rule",
|
|
+ valid_match.group(1))
|
|
+ return False
|
|
+ else:
|
|
+ LOG.debug("Doas rule does not appear to reference any user")
|
|
+ return False
|
|
+
|
|
+ def write_doas_rules(self, user, rules, doas_file=None):
|
|
+ if not doas_file:
|
|
+ doas_file = self.ci_doas_fn
|
|
+
|
|
+ if isinstance(rules, (list, tuple)):
|
|
+ for rule in rules:
|
|
+ if not self.is_doas_rule_valid(user, rule):
|
|
+ msg = "Invalid Doas rule %r for user '%s', not writing any Doas rules for user!" % (rule, user)
|
|
+ LOG.error(msg)
|
|
+ return
|
|
+ elif isinstance(rules, str):
|
|
+ if not self.is_doas_rule_valid(user, rule):
|
|
+ msg = "Invalid Doas rule %r for user '%s', not writing any Doas rules for user!" % (rule, user)
|
|
+ LOG.error(msg)
|
|
+ return
|
|
+
|
|
+ lines = [
|
|
+ "",
|
|
+ "# User rules for %s" % user,
|
|
+ ]
|
|
+ if isinstance(rules, (list, tuple)):
|
|
+ for rule in rules:
|
|
+ lines.append("%s" % rule)
|
|
+ elif isinstance(rules, str):
|
|
+ lines.append("%s" % rules)
|
|
+ else:
|
|
+ msg = "Can not create Doas rule addition with type %r"
|
|
+ raise TypeError(msg % (type_utils.obj_name(rules)))
|
|
+ content = "\n".join(lines)
|
|
+ content += "\n" # trailing newline
|
|
+
|
|
+ self.ensure_doas_dir(os.path.dirname(doas_file))
|
|
+ if not os.path.exists(doas_file):
|
|
+ contents = [
|
|
+ util.make_header(),
|
|
+ content,
|
|
+ ]
|
|
+ try:
|
|
+ util.write_file(doas_file, "\n".join(contents), mode=0o440)
|
|
+ except IOError as e:
|
|
+ util.logexc(LOG, "Failed to write Doas file %s", doas_file)
|
|
+ raise e
|
|
+ else:
|
|
+ try:
|
|
+ util.append_file(doas_file, content)
|
|
+ except IOError as e:
|
|
+ util.logexc(LOG, "Failed to append Doas file %s", doas_file)
|
|
+ raise e
|
|
+
|
|
def ensure_sudo_dir(self, path, sudo_base="/etc/sudoers"):
|
|
# Ensure the dir is included and that
|
|
# it actually exists as a directory
|
|
diff -aur a/config/cloud.cfg.tmpl b/config/cloud.cfg.tmpl
|
|
--- a/config/cloud.cfg.tmpl
|
|
+++ b/config/cloud.cfg.tmpl
|
|
@@ -277,6 +277,9 @@
|
|
lock_passwd: True
|
|
gecos: {{ variant }} Cloud User
|
|
{% endif %}
|
|
+{% if variant == "alpine" %}
|
|
+ doas: ["permit nopass alpine"]
|
|
+{% endif %}
|
|
{% if variant == "suse" %}
|
|
groups: [cdrom, users]
|
|
{% elif variant == "gentoo" %}
|
|
@@ -284,7 +287,7 @@
|
|
primary_group: users
|
|
no_user_group: true
|
|
{% elif variant == "alpine" %}
|
|
- groups: [adm, sudo]
|
|
+ groups: [adm, sudo, wheel]
|
|
{% elif variant == "arch" %}
|
|
groups: [wheel, users]
|
|
{% elif variant == "openmandriva" %}
|