diff --git a/api/types/installers/agentless-installer.sh.tmpl b/api/types/installers/agentless-installer.sh.tmpl index a215a8d400eb7..61a1628ff40f7 100644 --- a/api/types/installers/agentless-installer.sh.tmpl +++ b/api/types/installers/agentless-installer.sh.tmpl @@ -4,6 +4,32 @@ set -o errexit set -o pipefail set -o nounset +upgrade_endpoint="{{ .PublicProxyAddr }}/v1/webapi/automaticupgrades/channel/default" + +# upgrade_endpoint_fetch loads the specified value from the upgrade endpoint. the only +# currently supported values are 'version' and 'critical'. +upgrade_endpoint_fetch() { + host_path="${upgrade_endpoint}/${1}" + + if sf_output="$(curl --proto '=https' --tlsv1.2 -sSf "https://${host_path}")"; then + # emit output with empty lines and extra whitespace removed + echo "$sf_output" | grep -v -e '^[[:space:]]*$' | awk '{$1=$1};1' + return 0 + else + return 1 + fi +} + +# get_target_version loads the current value of the /version endpoint. +get_target_version() { + if tv_output="$(upgrade_endpoint_fetch version)"; then + # emit version string with leading 'v' removed if one is present + echo "${tv_output#v}" + return 0 + fi + return 1 +} + run_teleport() { TOKEN="$1" PRINCIPALS="$2" @@ -81,10 +107,8 @@ get_labels() { install_teleport() { . /etc/os-release - PACKAGE_LIST="jq {{ .TeleportPackage }}" - if [[ "{{ .AutomaticUpgrades }}" == "true" ]]; then - PACKAGE_LIST="${PACKAGE_LIST} {{ .TeleportPackage }}-updater" - fi + TELEPORT_PACKAGE="{{ .TeleportPackage }}" + TELEPORT_UPDATER_PACKAGE="{{ .TeleportPackage }}-updater" if [ "$ID" = "debian" ] || [ "$ID" = "ubuntu" ]; then # old versions of ubuntu require that keys get added by `apt-key add`, without @@ -99,7 +123,25 @@ install_teleport() { echo "deb [signed-by=/usr/share/keyrings/teleport-archive-keyring.asc] https://apt.releases.teleport.dev/${ID?} ${VERSION_CODENAME?} {{ .RepoChannel }}" | sudo tee /etc/apt/sources.list.d/teleport.list >/dev/null fi sudo apt-get update - sudo apt-get install -y ${PACKAGE_LIST} + + # shellcheck disable=SC2050 + if [ "{{ .AutomaticUpgrades }}" = "true" ]; then + # automatic upgrades + if ! target_version="$(get_target_version)"; then + # error getting the target version + sudo apt-get install -y "$TELEPORT_PACKAGE" jq "$TELEPORT_UPDATER_PACKAGE" + elif [ "$target_version" == "none" ]; then + # no target version advertised + sudo apt-get install -y "$TELEPORT_PACKAGE" jq "$TELEPORT_UPDATER_PACKAGE" + else + # successfully retrieved target version + sudo apt-get install -y "$TELEPORT_PACKAGE=$target_version" jq "$TELEPORT_UPDATER_PACKAGE=$target_version" + fi + else + # no automatic upgrades + sudo apt-get install -y "$TELEPORT_PACKAGE" + fi + elif [ "$ID" = "amzn" ] || [ "$ID" = "rhel" ]; then if [ "$ID" = "rhel" ]; then VERSION_ID=$(echo "$VERSION_ID" | sed 's/\..*//') # convert version numbers like '7.2' to only include the major version @@ -107,7 +149,25 @@ install_teleport() { sudo yum install -y yum-utils sudo yum-config-manager --add-repo \ "$(rpm --eval "https://yum.releases.teleport.dev/$ID/$VERSION_ID/Teleport/%{_arch}/{{ .RepoChannel }}/teleport.repo")" - sudo yum install -y ${PACKAGE_LIST} + + # shellcheck disable=SC2050 + if [ "{{ .AutomaticUpgrades }}" = "true" ]; then + # automatic upgrades + if ! target_version="$(get_target_version)"; then + # error getting the target version + sudo yum install -y "$TELEPORT_PACKAGE" jq "$TELEPORT_UPDATER_PACKAGE" + elif [ "$target_version" == "none" ]; then + # no target version advertised + sudo yum install -y "$TELEPORT_PACKAGE" jq "$TELEPORT_UPDATER_PACKAGE" + else + # successfully retrieved target version + sudo yum install -y "$TELEPORT_PACKAGE-$target_version" jq "$TELEPORT_UPDATER_PACKAGE-$target_version" + fi + else + # no automatic upgrades + sudo yum install -y "$TELEPORT_PACKAGE" + fi + elif [ "$ID" = "sles" ] || [ "$ID" = "opensuse-tumbleweed" ] || [ "$ID" = "opensuse-leap" ]; then if [ "$ID" = "opensuse-tumbleweed" ]; then VERSION_ID="15" # tumbleweed uses dated VERSION_IDs like 20230702 @@ -117,7 +177,23 @@ install_teleport() { sudo rpm --import "https://zypper.releases.teleport.dev/gpg" sudo zypper --non-interactive addrepo "$(rpm --eval "https://yum.releases.teleport.dev/sles/$VERSION_ID/Teleport/%{_arch}/{{ .RepoChannel }}/teleport.repo")" sudo zypper --gpg-auto-import-keys refresh - sudo zypper --non-interactive install ${PACKAGE_LIST} + # shellcheck disable=SC2050 + if [ "{{ .AutomaticUpgrades }}" = "true" ]; then + # automatic upgrades + if ! target_version="$(get_target_version)"; then + # error getting the target version + sudo zypper --non-interactive install -y "$TELEPORT_PACKAGE" jq "$TELEPORT_UPDATER_PACKAGE" + elif [ "$target_version" == "none" ]; then + # no target version advertised + sudo zypper --non-interactive install -y "$TELEPORT_PACKAGE" jq "$TELEPORT_UPDATER_PACKAGE" + else + # successfully retrieved target version + sudo zypper --non-interactive install -y "$TELEPORT_PACKAGE-$target_version" jq "$TELEPORT_UPDATER_PACKAGE-$target_version" + fi + else + # no automatic upgrades + sudo zypper --non-interactive install -y "$TELEPORT_PACKAGE" + fi else echo "Unsupported distro: $ID" exit 1 diff --git a/api/types/installers/installer.sh.tmpl b/api/types/installers/installer.sh.tmpl index 8416ac27090d9..1ba6aa865b58c 100644 --- a/api/types/installers/installer.sh.tmpl +++ b/api/types/installers/installer.sh.tmpl @@ -2,6 +2,32 @@ set -eu +upgrade_endpoint="{{ .PublicProxyAddr }}/v1/webapi/automaticupgrades/channel/default" + +# upgrade_endpoint_fetch loads the specified value from the upgrade endpoint. the only +# currently supported values are 'version' and 'critical'. +upgrade_endpoint_fetch() { + host_path="${upgrade_endpoint}/${1}" + + if sf_output="$(curl --proto '=https' --tlsv1.2 -sSf "https://${host_path}")"; then + # emit output with empty lines and extra whitespace removed + echo "$sf_output" | grep -v -e '^[[:space:]]*$' | awk '{$1=$1};1' + return 0 + else + return 1 + fi +} + +# get_target_version loads the current value of the /version endpoint. +get_target_version() { + if tv_output="$(upgrade_endpoint_fetch version)"; then + # emit version string with leading 'v' removed if one is present + echo "${tv_output#v}" + return 0 + fi + return 1 +} + on_ec2() { IMDS_TOKEN=$(curl -m5 -sS -X PUT "http://169.254.169.254/latest/api/token" -H "X-aws-ec2-metadata-token-ttl-seconds: 300") [ -z "$IMDS_TOKEN" ] && return 1 @@ -27,10 +53,8 @@ on_gcp() { . /etc/os-release - PACKAGE_LIST="{{ .TeleportPackage }} jq" - if [[ "{{ .AutomaticUpgrades }}" == "true" ]]; then - PACKAGE_LIST="${PACKAGE_LIST} {{ .TeleportPackage }}-updater" - fi + TELEPORT_PACKAGE="{{ .TeleportPackage }}" + TELEPORT_UPDATER_PACKAGE="{{ .TeleportPackage }}-updater" if [ "$ID" = "debian" ] || [ "$ID" = "ubuntu" ]; then # old versions of ubuntu require that keys get added by `apt-key add`, without @@ -46,7 +70,25 @@ on_gcp() { echo "deb [signed-by=/usr/share/keyrings/teleport-archive-keyring.asc] https://apt.releases.teleport.dev/${ID?} ${VERSION_CODENAME?} {{ .RepoChannel }}" | sudo tee /etc/apt/sources.list.d/teleport.list >/dev/null fi sudo apt-get update - sudo apt-get install -y ${PACKAGE_LIST} + + # shellcheck disable=SC2050 + if [ "{{ .AutomaticUpgrades }}" = "true" ]; then + # automatic upgrades + if ! target_version="$(get_target_version)"; then + # error getting the target version + sudo apt-get install -y "$TELEPORT_PACKAGE" jq "$TELEPORT_UPDATER_PACKAGE" + elif [ "$target_version" == "none" ]; then + # no target version advertised + sudo apt-get install -y "$TELEPORT_PACKAGE" jq "$TELEPORT_UPDATER_PACKAGE" + else + # successfully retrieved target version + sudo apt-get install -y "$TELEPORT_PACKAGE=$target_version" jq "$TELEPORT_UPDATER_PACKAGE=$target_version" + fi + else + # no automatic upgrades + sudo apt-get install -y "$TELEPORT_PACKAGE" + fi + elif [ "$ID" = "amzn" ] || [ "$ID" = "rhel" ]; then if [ "$ID" = "rhel" ]; then VERSION_ID=${VERSION_ID//\.*/} # convert version numbers like '7.2' to only include the major version @@ -54,7 +96,25 @@ on_gcp() { sudo yum install -y yum-utils sudo yum-config-manager --add-repo \ "$(rpm --eval "https://yum.releases.teleport.dev/$ID/$VERSION_ID/Teleport/%{_arch}/{{ .RepoChannel }}/teleport.repo")" - sudo yum install -y ${PACKAGE_LIST} + + # shellcheck disable=SC2050 + if [ "{{ .AutomaticUpgrades }}" = "true" ]; then + # automatic upgrades + if ! target_version="$(get_target_version)"; then + # error getting the target version + sudo yum install -y "$TELEPORT_PACKAGE" jq "$TELEPORT_UPDATER_PACKAGE" + elif [ "$target_version" == "none" ]; then + # no target version advertised + sudo yum install -y "$TELEPORT_PACKAGE" jq "$TELEPORT_UPDATER_PACKAGE" + else + # successfully retrieved target version + sudo yum install -y "$TELEPORT_PACKAGE-$target_version" jq "$TELEPORT_UPDATER_PACKAGE-$target_version" + fi + else + # no automatic upgrades + sudo yum install -y "$TELEPORT_PACKAGE" + fi + elif [ "$ID" = "sles" ] || [ "$ID" = "opensuse-tumbleweed" ] || [ "$ID" = "opensuse-leap" ]; then if [ "$ID" = "opensuse-tumbleweed" ]; then VERSION_ID="15" # tumbleweed uses dated VERSION_IDs like 20230702 @@ -65,6 +125,24 @@ on_gcp() { sudo zypper --non-interactive addrepo "$(rpm --eval "https://zypper.releases.teleport.dev/sles/$VERSION_ID/Teleport/%{_arch}/{{ .RepoChannel }}/teleport.repo")" sudo zypper --gpg-auto-import-keys refresh sudo zypper --non-interactive install ${PACKAGE_LIST} + + # shellcheck disable=SC2050 + if [ "{{ .AutomaticUpgrades }}" = "true" ]; then + # automatic upgrades + if ! target_version="$(get_target_version)"; then + # error getting the target version + sudo zypper --non-interactive install -y "$TELEPORT_PACKAGE" jq "$TELEPORT_UPDATER_PACKAGE" + elif [ "$target_version" == "none" ]; then + # no target version advertised + sudo zypper --non-interactive install -y "$TELEPORT_PACKAGE" jq "$TELEPORT_UPDATER_PACKAGE" + else + # successfully retrieved target version + sudo zypper --non-interactive install -y "$TELEPORT_PACKAGE-$target_version" jq "$TELEPORT_UPDATER_PACKAGE-$target_version" + fi + else + # no automatic upgrades + sudo zypper --non-interactive install -y "$TELEPORT_PACKAGE" + fi else echo "Unsupported distro: $ID" exit 1 diff --git a/lib/web/apiserver_test.go b/lib/web/apiserver_test.go index 983f84753ef7a..998f5a2b718db 100644 --- a/lib/web/apiserver_test.go +++ b/lib/web/apiserver_test.go @@ -2619,10 +2619,13 @@ echo AutomaticUpgrades: {{ .AutomaticUpgrades }} require.Contains(t, responseString, "stable/cloud") require.NotContains(t, responseString, "stable/v") require.Contains(t, responseString, ""+ - " PACKAGE_LIST=\"teleport-ent jq\"\n"+ - " if [[ \"true\" == \"true\" ]]; then\n"+ - " PACKAGE_LIST=\"${PACKAGE_LIST} teleport-ent-updater\"\n"+ - " fi\n", + " # shellcheck disable=SC2050\n"+ + " if [ \"true\" = \"true\" ]; then\n"+ + " # automatic upgrades\n", + ) + require.Contains(t, responseString, ""+ + " TELEPORT_PACKAGE=\"teleport-ent\"\n"+ + " TELEPORT_UPDATER_PACKAGE=\"teleport-ent-updater\"\n", ) }) @@ -2636,10 +2639,13 @@ echo AutomaticUpgrades: {{ .AutomaticUpgrades }} require.Contains(t, responseString, "stable/cloud") require.NotContains(t, responseString, "stable/v") require.Contains(t, responseString, ""+ - " PACKAGE_LIST=\"jq teleport-ent\"\n"+ - " if [[ \"true\" == \"true\" ]]; then\n"+ - " PACKAGE_LIST=\"${PACKAGE_LIST} teleport-ent-updater\"\n"+ - " fi\n", + " # shellcheck disable=SC2050\n"+ + " if [ \"true\" = \"true\" ]; then\n"+ + " # automatic upgrades\n", + ) + require.Contains(t, responseString, ""+ + " TELEPORT_PACKAGE=\"teleport-ent\"\n"+ + " TELEPORT_UPDATER_PACKAGE=\"teleport-ent-updater\"\n", ) }) }) @@ -2750,10 +2756,13 @@ echo AutomaticUpgrades: {{ .AutomaticUpgrades }} require.NotContains(t, responseString, "stable/cloud") require.Contains(t, responseString, "stable/v") require.Contains(t, responseString, ""+ - " PACKAGE_LIST=\"teleport jq\"\n"+ - " if [[ \"false\" == \"true\" ]]; then\n"+ - " PACKAGE_LIST=\"${PACKAGE_LIST} teleport-updater\"\n"+ - " fi", + " # shellcheck disable=SC2050\n"+ + " if [ \"false\" = \"true\" ]; then\n"+ + " # automatic upgrades\n", + ) + require.Contains(t, responseString, ""+ + " TELEPORT_PACKAGE=\"teleport\"\n"+ + " TELEPORT_UPDATER_PACKAGE=\"teleport-updater\"\n", ) }) t.Run("default-agentless-installer", func(t *testing.T) { @@ -2766,10 +2775,13 @@ echo AutomaticUpgrades: {{ .AutomaticUpgrades }} require.NotContains(t, responseString, "stable/cloud") require.Contains(t, responseString, "stable/v") require.Contains(t, responseString, ""+ - " PACKAGE_LIST=\"jq teleport\"\n"+ - " if [[ \"false\" == \"true\" ]]; then\n"+ - " PACKAGE_LIST=\"${PACKAGE_LIST} teleport-updater\"\n"+ - " fi\n", + " # shellcheck disable=SC2050\n"+ + " if [ \"false\" = \"true\" ]; then\n"+ + " # automatic upgrades\n", + ) + require.Contains(t, responseString, ""+ + " TELEPORT_PACKAGE=\"teleport\"\n"+ + " TELEPORT_UPDATER_PACKAGE=\"teleport-updater\"\n", ) }) })