git: f85d08682782 - main - nuageinint: implement ssh_pwauth

From: Baptiste Daroussin <bapt_at_FreeBSD.org>
Date: Wed, 23 Apr 2025 14:29:19 UTC
The branch main has been updated by bapt:

URL: https://cgit.FreeBSD.org/src/commit/?id=f85d08682782f7ef49aecf2edacd81184561de87

commit f85d08682782f7ef49aecf2edacd81184561de87
Author:     Baptiste Daroussin <bapt@FreeBSD.org>
AuthorDate: 2025-04-17 16:04:26 +0000
Commit:     Baptiste Daroussin <bapt@FreeBSD.org>
CommitDate: 2025-04-23 14:29:02 +0000

    nuageinint: implement ssh_pwauth
    
    ssh_pwauth sets the value in sshd_config for the password authentication
    This implementation tries to avoid touching the file if cloudinit
    request for what is already the default value.
    
    MFC After:      3 days
    Sponsored by:   OVHCloud
    Reviewed by:    kevans, jlduran
    Differential Revision:  https://reviews.freebsd.org/D49875
---
 libexec/nuageinit/nuage.lua          | 36 +++++++++++++++++++++++-
 libexec/nuageinit/nuageinit          |  7 +++++
 libexec/nuageinit/tests/nuageinit.sh | 54 ++++++++++++++++++++++++++++++++++++
 3 files changed, 96 insertions(+), 1 deletion(-)

diff --git a/libexec/nuageinit/nuage.lua b/libexec/nuageinit/nuage.lua
index 978de02a63fc..fffd1b6d23aa 100644
--- a/libexec/nuageinit/nuage.lua
+++ b/libexec/nuageinit/nuage.lua
@@ -228,6 +228,39 @@ local function addsshkey(homedir, key)
 	end
 end
 
+local function update_sshd_config(key, value)
+	local sshd_config = "/etc/ssh/sshd_config"
+	local root = os.getenv("NUAGE_FAKE_ROOTDIR")
+	if root then
+		sshd_config = root .. sshd_config
+	end
+	local f = assert(io.open(sshd_config, "r+"))
+	local tgt = assert(io.open(sshd_config .. ".nuageinit", "w"))
+	local found = false
+	local pattern = "^%s*"..key:lower().."%s+(%w+)%s*#?.*$"
+	while true do
+		local line = f:read()
+		if line == nil then break end
+		local _, _, val = line:lower():find(pattern)
+		if val then
+			found = true
+			if val == value then
+				assert(tgt:write(line .. "\n"))
+			else
+				assert(tgt:write(key .. " " .. value .. "\n"))
+			end
+		else
+			assert(tgt:write(line .. "\n"))
+		end
+	end
+	if not found then
+		assert(tgt:write(key .. " " .. value .. "\n"))
+	end
+	assert(f:close())
+	assert(tgt:close())
+	os.rename(sshd_config .. ".nuageinit", sshd_config)
+end
+
 local n = {
 	warn = warnmsg,
 	err = errmsg,
@@ -236,7 +269,8 @@ local n = {
 	sethostname = sethostname,
 	adduser = adduser,
 	addgroup = addgroup,
-	addsshkey = addsshkey
+	addsshkey = addsshkey,
+	update_sshd_config = update_sshd_config
 }
 
 return n
diff --git a/libexec/nuageinit/nuageinit b/libexec/nuageinit/nuageinit
index 88e8b6c4c2cd..341330e68128 100755
--- a/libexec/nuageinit/nuageinit
+++ b/libexec/nuageinit/nuageinit
@@ -352,6 +352,13 @@ if line == "#cloud-config" then
 		network:close()
 		routing:close()
 	end
+	if obj.ssh_pwauth ~= nil then
+		local value = "no"
+		if obj.ssh_pwauth then
+			value = "yes"
+		end
+		nuage.update_sshd_config("PasswordAuthentication", value)
+	end
 else
 	local res, err = os.execute(path .. "/" .. ud)
 	if not res then
diff --git a/libexec/nuageinit/tests/nuageinit.sh b/libexec/nuageinit/tests/nuageinit.sh
index 7e1310c4f0f9..d3b1d5e6df2e 100644
--- a/libexec/nuageinit/tests/nuageinit.sh
+++ b/libexec/nuageinit/tests/nuageinit.sh
@@ -19,6 +19,7 @@ atf_test_case config2_pubkeys_meta_data
 atf_test_case config2_network
 atf_test_case config2_network_static_v4
 atf_test_case config2_ssh_keys
+atf_test_case nocloud_userdata_cloudconfig_ssh_pwauth
 
 args_body()
 {
@@ -459,6 +460,58 @@ blabla
 	atf_check -o inline:"${_expected}" cat ${PWD}/etc/ssh/ssh_host_ed25519_key.pub
 }
 
+
+nocloud_userdata_cloudconfig_ssh_pwauth_head()
+{
+	atf_set "require.user" root
+}
+nocloud_userdata_cloudconfig_ssh_pwauth_body()
+{
+	mkdir -p etc
+	cat > etc/master.passwd << EOF
+root:*:0:0::0:0:Charlie &:/root:/bin/sh
+sys:*:1:0::0:0:Sys:/home/sys:/bin/sh
+EOF
+	pwd_mkdb -d etc "${PWD}"/etc/master.passwd
+	cat > etc/group << EOF
+wheel:*:0:root
+users:*:1:
+EOF
+	mkdir -p media/nuageinit
+	printf "instance-id: iid-local01\n" > "${PWD}"/media/nuageinit/meta-data
+	cat > media/nuageinit/user-data << 'EOF'
+#cloud-config
+ssh_pwauth: true
+EOF
+	mkdir -p etc/ssh/
+	touch etc/ssh/sshd_config
+
+	atf_check -o empty -e empty /usr/libexec/nuageinit "${PWD}"/media/nuageinit nocloud
+	atf_check -o inline:"PasswordAuthentication yes\n" cat etc/ssh/sshd_config
+
+	# Same value we don't touch anything
+	printf "   PasswordAuthentication yes # I want password\n" > etc/ssh/sshd_config
+	atf_check -o empty -e empty /usr/libexec/nuageinit "${PWD}"/media/nuageinit nocloud
+	atf_check -o inline:"   PasswordAuthentication yes # I want password\n" cat etc/ssh/sshd_config
+
+	printf "   PasswordAuthentication no # Should change\n" > etc/ssh/sshd_config
+	atf_check -o empty -e empty /usr/libexec/nuageinit "${PWD}"/media/nuageinit nocloud
+	atf_check -o inline:"PasswordAuthentication yes\n" cat etc/ssh/sshd_config
+
+	cat > media/nuageinit/user-data << 'EOF'
+#cloud-config
+ssh_pwauth: false
+EOF
+
+	printf "   PasswordAuthentication no # no passwords\n" > etc/ssh/sshd_config
+	atf_check -o empty -e empty /usr/libexec/nuageinit "${PWD}"/media/nuageinit nocloud
+	atf_check -o inline:"   PasswordAuthentication no # no passwords\n" cat etc/ssh/sshd_config
+
+	printf "   PasswordAuthentication yes # Should change\n" > etc/ssh/sshd_config
+	atf_check -o empty -e empty /usr/libexec/nuageinit "${PWD}"/media/nuageinit nocloud
+	atf_check -o inline:"PasswordAuthentication no\n" cat etc/ssh/sshd_config
+}
+
 atf_init_test_cases()
 {
 	atf_add_test_case args
@@ -474,4 +527,5 @@ atf_init_test_cases()
 	atf_add_test_case config2_network
 	atf_add_test_case config2_network_static_v4
 	atf_add_test_case config2_ssh_keys
+	atf_add_test_case nocloud_userdata_cloudconfig_ssh_pwauth
 }