aboutsummaryrefslogtreecommitdiff
path: root/libexec/nuageinit
diff options
context:
space:
mode:
Diffstat (limited to 'libexec/nuageinit')
-rw-r--r--libexec/nuageinit/nuage.lua128
-rwxr-xr-xlibexec/nuageinit/nuageinit36
-rw-r--r--libexec/nuageinit/nuageinit.719
-rw-r--r--libexec/nuageinit/tests/nuage.sh1
-rw-r--r--libexec/nuageinit/tests/nuageinit.sh13
-rw-r--r--libexec/nuageinit/tests/utils.sh1
6 files changed, 189 insertions, 9 deletions
diff --git a/libexec/nuageinit/nuage.lua b/libexec/nuageinit/nuage.lua
index 48f54b120615..3eeb2ea0b44c 100644
--- a/libexec/nuageinit/nuage.lua
+++ b/libexec/nuageinit/nuage.lua
@@ -2,11 +2,23 @@
-- SPDX-License-Identifier: BSD-2-Clause
--
-- Copyright(c) 2022-2025 Baptiste Daroussin <bapt@FreeBSD.org>
+-- Copyright(c) 2025 Jesús Daniel Colmenares Oviedo <dtxdf@FreeBSD.org>
local unistd = require("posix.unistd")
local sys_stat = require("posix.sys.stat")
local lfs = require("lfs")
+local function getlocalbase()
+ local f = io.popen("sysctl -in user.localbase 2> /dev/null")
+ local localbase = f:read("*l")
+ f:close()
+ if localbase == nil or localbase:len() == 0 then
+ -- fallback
+ localbase = "/usr/local"
+ end
+ return localbase
+end
+
local function decode_base64(input)
local b = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/'
input = string.gsub(input, '[^'..b..'=]', '')
@@ -127,6 +139,58 @@ local function splitlist(list)
return ret
end
+local function splitlines(s)
+ local ret = {}
+
+ for line in string.gmatch(s, "[^\n]+") do
+ ret[#ret + 1] = line
+ end
+
+ return ret
+end
+
+local function getgroups()
+ local ret = {}
+
+ local root = os.getenv("NUAGE_FAKE_ROOTDIR")
+ local cmd = "pw "
+ if root then
+ cmd = cmd .. "-R " .. root .. " "
+ end
+
+ local f = io.popen(cmd .. "groupshow -a 2> /dev/null | cut -d: -f1")
+ local groups = f:read("*a")
+ f:close()
+
+ return splitlines(groups)
+end
+
+local function checkgroup(group)
+ local groups = getgroups()
+
+ for _, group2chk in ipairs(groups) do
+ if group == group2chk then
+ return true
+ end
+ end
+
+ return false
+end
+
+local function purge_group(groups)
+ local ret = {}
+
+ for _, group in ipairs(groups) do
+ if checkgroup(group) then
+ ret[#ret + 1] = group
+ else
+ warnmsg("ignoring non-existent group '" .. group .. "'")
+ end
+ end
+
+ return ret
+end
+
local function adduser(pwd)
if (type(pwd) ~= "table") then
warnmsg("Argument should be a table")
@@ -152,7 +216,14 @@ local function adduser(pwd)
local extraargs = ""
if pwd.groups then
local list = splitlist(pwd.groups)
- extraargs = " -G " .. table.concat(list, ",")
+ -- pw complains if the group does not exist, so if the user
+ -- specifies one that cannot be found, nuageinit will generate
+ -- an exception and exit, unlike cloud-init, which only issues
+ -- a warning but creates the user anyway.
+ list = purge_group(list)
+ if #list > 0 then
+ extraargs = " -G " .. table.concat(list, ",")
+ end
end
-- pw will automatically create a group named after the username
-- do not add a -g option in this case
@@ -276,11 +347,59 @@ local function addsshkey(homedir, key)
end
end
+local function adddoas(pwd)
+ local chmodetcdir = false
+ local chmoddoasconf = false
+ local root = os.getenv("NUAGE_FAKE_ROOTDIR")
+ local localbase = getlocalbase()
+ local etcdir = localbase .. "/etc"
+ if root then
+ etcdir= root .. etcdir
+ end
+ local doasconf = etcdir .. "/doas.conf"
+ local doasconf_attr = lfs.attributes(doasconf)
+ if doasconf_attr == nil then
+ chmoddoasconf = true
+ local dirattrs = lfs.attributes(etcdir)
+ if dirattrs == nil then
+ local r, err = mkdir_p(etcdir)
+ if not r then
+ return nil, err .. " (creating " .. etcdir .. ")"
+ end
+ chmodetcdir = true
+ end
+ end
+ local f = io.open(doasconf, "a")
+ if not f then
+ warnmsg("impossible to open " .. doasconf)
+ return
+ end
+ if type(pwd.doas) == "string" then
+ local rule = pwd.doas
+ rule = rule:gsub("%%u", pwd.name)
+ f:write(rule .. "\n")
+ elseif type(pwd.doas) == "table" then
+ for _, str in ipairs(pwd.doas) do
+ local rule = str
+ rule = rule:gsub("%%u", pwd.name)
+ f:write(rule .. "\n")
+ end
+ end
+ f:close()
+ if chmoddoasconf then
+ chmod(doasconf, "0640")
+ end
+ if chmodetcdir then
+ chmod(etcdir, "0755")
+ end
+end
+
local function addsudo(pwd)
local chmodsudoersd = false
local chmodsudoers = false
local root = os.getenv("NUAGE_FAKE_ROOTDIR")
- local sudoers_dir = "/usr/local/etc/sudoers.d"
+ local localbase = getlocalbase()
+ local sudoers_dir = localbase .. "/etc/sudoers.d"
if root then
sudoers_dir= root .. sudoers_dir
end
@@ -311,10 +430,10 @@ local function addsudo(pwd)
end
f:close()
if chmodsudoers then
- chmod(sudoers, "0640")
+ chmod(sudoers, "0440")
end
if chmodsudoersd then
- chmod(sudoers, "0740")
+ chmod(sudoers_dir, "0750")
end
end
@@ -584,6 +703,7 @@ local n = {
update_packages = update_packages,
upgrade_packages = upgrade_packages,
addsudo = addsudo,
+ adddoas = adddoas,
addfile = addfile
}
diff --git a/libexec/nuageinit/nuageinit b/libexec/nuageinit/nuageinit
index 70b27cb33d87..f29fa8ba1bac 100755
--- a/libexec/nuageinit/nuageinit
+++ b/libexec/nuageinit/nuageinit
@@ -3,8 +3,10 @@
-- SPDX-License-Identifier: BSD-2-Clause-FreeBSD
--
-- Copyright(c) 2022-2025 Baptiste Daroussin <bapt@FreeBSD.org>
+-- Copyright(c) 2025 Jesús Daniel Colmenares Oviedo <dtxdf@FreeBSD.org>
local nuage = require("nuage")
+local lfs = require("lfs")
local ucl = require("ucl")
local yaml = require("lyaml")
@@ -139,6 +141,9 @@ local function users(obj)
if u.sudo then
nuage.addsudo(u)
end
+ if u.doas then
+ nuage.adddoas(u)
+ end
else
nuage.warn("invalid type : " .. type(u) .. " for users entry number " .. n)
end
@@ -582,6 +587,26 @@ local function config2_network(p)
routing:close()
end
+local function parse_network_config()
+ local nc_file = ni_path .. "/network-config"
+ local nc_file_attr = lfs.attributes(nc_file)
+ if nc_file_attr == nil then
+ return
+ end
+ local f, err = io.open(nc_file)
+ if err then
+ nuage.err("error parsing nocloud network-config: " .. err)
+ end
+ local obj = yaml.load(f:read("*a"))
+ f:close()
+ if not obj then
+ nuage.err("error parsing nocloud network-config")
+ end
+ local netobj = {}
+ netobj["network"] = obj
+ return netobj
+end
+
if citype == "config-2" then
local parser = ucl.parser()
local res, err = parser:parse_file(ni_path .. "/meta_data.json")
@@ -678,7 +703,16 @@ if line == "#cloud-config" then
end
for i = 1, #calls_table do
- calls_table[i](obj)
+ if citype == "nocloud" and calls_table[i] == network_config then
+ netobj = parse_network_config()
+ if netobj == nil then
+ network_config(obj)
+ else
+ network_config(netobj)
+ end
+ else
+ calls_table[i](obj)
+ end
end
elseif line:sub(1, 2) == "#!" then
-- delay for execution at rc.local time --
diff --git a/libexec/nuageinit/nuageinit.7 b/libexec/nuageinit/nuageinit.7
index f27b8bc06042..b527c984970c 100644
--- a/libexec/nuageinit/nuageinit.7
+++ b/libexec/nuageinit/nuageinit.7
@@ -1,6 +1,7 @@
.\" SPDX-License-Identifier: BSD-2-Clause
.\"
.\" Copyright (c) 2025 Baptiste Daroussin <bapt@FreeBSD.org>
+.\" Copyright (c) 2025 Jesús Daniel Colmenares Oviedo <dtxdf@FreeBSD.org>
.\"
.Dd June 26, 2025
.Dt NUAGEINIT 7
@@ -182,6 +183,13 @@ configuration in
.Pa /etc/ssh/sshd_config
.It Ic network
Network configuration parameters.
+.Pp
+Specifying the following parameters from a file named
+.Pa network-config
+takes precedence over their specification from the
+.Ic network
+parameter of
+.Pa user-data Ns .
.Bl -tag -width "ethernets"
.It Ic ethernets
Mapping representing a generic configuration for existing network interfaces.
@@ -296,13 +304,18 @@ The encrypted password for the user.
.It Ic plain_text_passwd
The password in plain text for the user.
Ignored if an encrypted password is already provided.
-.It Ic groups
-The list of other groups the user should belong to.
.It Ic locked
Boolean to determine if the user account should be locked.
.It Ic sudo
A string or an array of strings which should be appended to
-.Pa /usr/local/etc/sudoers.d/90-nuageinit-users
+.Pa ${LOCALBASE}/etc/sudoers.d/90-nuageinit-users
+.It Ic doas
+A string or an array of strings which should be appended to
+.Pa ${LOCALBASE}/etc/doas.conf
+.Pp
+Instead of hardcoding the username, you can use
+.Sy %u Ns ,
+which will be replaced by the current username.
.El
.Pp
A special case exist: if the entry is a simple string with the value
diff --git a/libexec/nuageinit/tests/nuage.sh b/libexec/nuageinit/tests/nuage.sh
index b709d25532ff..57d83b62928a 100644
--- a/libexec/nuageinit/tests/nuage.sh
+++ b/libexec/nuageinit/tests/nuage.sh
@@ -1,5 +1,6 @@
#-
# Copyright (c) 2022-2025 Baptiste Daroussin <bapt@FreeBSD.org>
+# Copyright (c) 2025 Jesús Daniel Colmenares Oviedo <dtxdf@FreeBSD.org>
#
# SPDX-License-Identifier: BSD-2-Clause
#
diff --git a/libexec/nuageinit/tests/nuageinit.sh b/libexec/nuageinit/tests/nuageinit.sh
index 98593f7d75b0..2b7c5226c97a 100644
--- a/libexec/nuageinit/tests/nuageinit.sh
+++ b/libexec/nuageinit/tests/nuageinit.sh
@@ -1,5 +1,6 @@
#-
# Copyright (c) 2022-2025 Baptiste Daroussin <bapt@FreeBSD.org>
+# Copyright (c) 2025 Jesús Daniel Colmenares Oviedo <dtxdf@FreeBSD.org>
#
# SPDX-License-Identifier: BSD-2-Clause
#
@@ -119,12 +120,16 @@ users:
gecos: Foo B. Bar
primary_group: foobar
sudo: ALL=(ALL) NOPASSWD:ALL
+ doas: permit persist %u as root
groups: users
passwd: $6$j212wezy$7H/1LT4f9/N3wpgNunhsIqtMj62OKiS3nyNwuizouQc3u7MbYCarYeAHWYPYb2FT.lbioDm2RrkJPb9BZMN1O/
- name: bla
sudo:
- "ALL=(ALL) NOPASSWD:/usr/sbin/pw"
- "ALL=(ALL) ALL"
+ doas:
+ - "deny %u as foobar"
+ - "permit persist %u as root cmd whoami"
EOF
atf_check /usr/libexec/nuageinit "${PWD}"/media/nuageinit nocloud
atf_check /usr/libexec/nuageinit "${PWD}"/media/nuageinit postnet
@@ -147,7 +152,13 @@ EOF
sed -i "" "s/freebsd:.*:1001/freebsd:freebsd:1001/" "${PWD}"/etc/master.passwd
atf_check -o file:expectedpasswd cat "${PWD}"/etc/master.passwd
atf_check -o file:expectedgroup cat "${PWD}"/etc/group
- atf_check -o inline:"foobar ALL=(ALL) NOPASSWD:ALL\nbla ALL=(ALL) NOPASSWD:/usr/sbin/pw\nbla ALL=(ALL) ALL\n" cat ${PWD}/usr/local/etc/sudoers.d/90-nuageinit-users
+ localbase=`sysctl -ni user.localbase 2> /dev/null`
+ if [ -z "${localbase}" ]; then
+ # fallback
+ localbase="/usr/local"
+ fi
+ atf_check -o inline:"foobar ALL=(ALL) NOPASSWD:ALL\nbla ALL=(ALL) NOPASSWD:/usr/sbin/pw\nbla ALL=(ALL) ALL\n" cat "${PWD}/${localbase}/etc/sudoers.d/90-nuageinit-users"
+ atf_check -o inline:"permit persist foobar as root\ndeny bla as foobar\npermit persist bla as root cmd whoami\n" cat "${PWD}/${localbase}/etc/doas.conf"
}
nocloud_network_head()
diff --git a/libexec/nuageinit/tests/utils.sh b/libexec/nuageinit/tests/utils.sh
index 26f117d81d60..76cd7e045473 100644
--- a/libexec/nuageinit/tests/utils.sh
+++ b/libexec/nuageinit/tests/utils.sh
@@ -1,5 +1,6 @@
#-
# Copyright (c) 2022 Baptiste Daroussin <bapt@FreeBSD.org>
+# Copyright (c) 2025 Jesús Daniel Colmenares Oviedo <dtxdf@FreeBSD.org>
#
# SPDX-License-Identifier: BSD-2-Clause
#