diff --git a/CHANGELOG.md b/CHANGELOG.md index d9f2952..a93e434 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,8 +1,16 @@ # CHANGELOG -## YYYY-MM-DD - Tiny Cloud vX.Y.Z +## 2025-12-DD - Tiny Cloud v3.2.3 -* Correctly identify empty `user-data` content instead of flagging it as "unknown". +#### GOOGLE CLOUD BEHAVIOR CHANGE +* ***NOTE***: Google Cloud SSH keys are installed for per specified logins, + instead of dumping them all into `$CLOUD_USER`'s `.ssh/authorized_keys`. + This matches `cloud-init`'s behavior and Google's intentions. Resolves + [#73](https://gitlab.alpinelinux.org/alpine/cloud/tiny-cloud/-/issues/73). + +#### OTHER CHANGES +* Correctly identify empty `user-data` content instead of flagging it as + "unknown". ## 2025-06-11 - Tiny Cloud v3.2.2 diff --git a/lib/tiny-cloud/cloud/gcp/imds b/lib/tiny-cloud/cloud/gcp/imds index 56853fb..5ef1721 100644 --- a/lib/tiny-cloud/cloud/gcp/imds +++ b/lib/tiny-cloud/cloud/gcp/imds @@ -21,8 +21,8 @@ _imds_header() { _imds_ssh_keys() { local ssh_keys + # NOTE:keys are prefixed with ":" for ssh_keys in $IMDS_SSH_KEYS; do - # ignore errors and strip leading ':' imds -e "$ssh_keys" | cut -d: -f2- done | sort -u } diff --git a/lib/tiny-cloud/cloud/gcp/init b/lib/tiny-cloud/cloud/gcp/init new file mode 100644 index 0000000..a7706a6 --- /dev/null +++ b/lib/tiny-cloud/cloud/gcp/init @@ -0,0 +1,51 @@ +# GCP - Init Functions +# vim:set filetype=sh: +# shellcheck shell=sh + +# NOTE: overrides lib/tiny-cloud function +# GCP ssh keys have a leading ":" we should check/honor +init__set_ssh_keys() { + local sshkeys="$(imds @ssh-keys)" + if [ -z "$sshkeys" ]; then + log -i -t "$phase" warning "$ACTION: no ssh key found" + return + fi + local userkey + local got_default + local tmp_dir=$(mktmp -d "$ROOT/run/tiny-cloud/ssh-XXXXXX") + mkdir -p "$tmp_dir" + chmod 700 "$tmp_dir" + for userkey in $sshkeys; do + local user=$(echo "$userkey" | cut -d: -f1) + local key=$(echo "$userkey" | cut -d: -f2) + local pwent="$(getent passwd "$user")" + if [ -z "$pwent" ]; then + log -i -t "$phase" warning "$ACTION: failed to find login $user" + continue + elif [ "$user" = "$CLOUD_USER" ]; then + got_default=1 + fi + local group=$(echo "$pwent" | cut -d: -f4) + local tmp_file="$tmp_dir/$user" + touch "$tmp_file" + chmod 600 "$tmp_file" + $MOCK chown -R "$user/$group" "$tmp_file" + echo "$key" >> "$tmp_file" + done + for user in "$tmp_dir"/*; do + local tmp_file="$tmp_dir/$user" + local pwent="$(getent passwd "$user")" + local ssh_dir="${ROOT}$(echo "$pwent" | cut -d: -f6)/.ssh" + if [ ! -d "$ssh_dir" ]; then + mkdir -p "$ssh_dir" + chmod 700 "$ssh_dir" + fi + local keys_file="$ssh_dir/authorized_keys" + cp -a "$tmp_file" "$keys_file" + log -i -t "$phase" info "$ACTION: installed ssh keys for $user" + done + rm -rf "$tmp_dir" + if [ -z "$got_default" ]; then + log -i -t "$phase" warning "$ACTION: no SSH keys found for $CLOUD_USER" + fi +} diff --git a/tests/init.test b/tests/init.test index 258f2fa..67aee7e 100755 --- a/tests/init.test +++ b/tests/init.test @@ -21,6 +21,7 @@ init_tests \ save_userdata_compressed \ set_hostname \ set_ssh_keys \ + set_ssh_keys_gcp \ userdata_type \ run_userdata \ autodetect_aws_cmdline \ @@ -189,6 +190,33 @@ set_ssh_keys_body() { cat home/alpine/.ssh/authorized_keys } +set_ssh_keys_gcp_body() { + fake_bin getent <<-EOF + #!/bin/sh + echo "alpine:x:1000:1000:Linux User,,,:/home/alpine:/bin/sh" + echo "foo:x:1001:1001:Other Linux User,,,:/home/foo:/bin/sh" + EOF + fake_metadata_gcp <<-EOF + project: + attributes: + ssh-keys: + - alpine:ssh-ed25519 keydata1 + - bar:ssh-rsa barfoo + instance: + attributes: + ssh-keys: + - alpine:ssh-ed25519 keydata2 + - foo:ssh-rsa foobar + EOF + # TODO: need to figure out what to check + CLOUD="gcp" atf_check \ + -o match:"chown.*/\.ssh" \ + sh -c ". \"$lib\"; init__set_ssh_keys" + atf_check -o match:"^ssh-ed25519 keydata" \ + -o match:"^ssh-rsa foobar" \ + cat home/alpine/.ssh/authorized_keys +} + userdata_type_body() { mkdir -p var/lib/cloud for c in $PROVIDERS; do