1
0
Fork 0
mirror of https://gitlab.alpinelinux.org/alpine/aports.git synced 2025-07-24 03:35:38 +03:00
aports/community/cloud-init/04-add-doas.patch
Dermot Bradley b1df42614c community/cloud-init: upgrade to 22.4
Upgrade cloud-init version.

Remove dependency on eudev as now mdev and mdevd are also supported.
2022-11-18 00:46:39 +00:00

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" %}