Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
9 changes: 7 additions & 2 deletions api/types/installers/agentless-installer.sh.tmpl
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,11 @@ set -o nounset

. /etc/os-release

PACKAGE_LIST="{{ .TeleportPackage }}"
if [[ "{{ .AutomaticUpgrades }}" == "true" ]]; then
PACKAGE_LIST="${PACKAGE_LIST} {{ .TeleportPackage }}-updater"
fi

if [ "$ID" = "debian" ] || [ "$ID" = "ubuntu" ]; then
# old versions of ubuntu require that keys get added by `apt-key add`, without
# adding the key apt shows a key signing error when installing teleport.
Expand All @@ -25,14 +30,14 @@ set -o nounset
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 {{ .TeleportPackage }}
sudo apt-get install -y ${PACKAGE_LIST}
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
fi
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 {{ .TeleportPackage }}
sudo yum install -y ${PACKAGE_LIST}
else
echo "Unsupported distro: $ID"
exit 1
Expand Down
9 changes: 7 additions & 2 deletions api/types/installers/installer.sh.tmpl
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,11 @@ on_azure() {

. /etc/os-release

PACKAGE_LIST="{{ .TeleportPackage }} jq"
if [[ "{{ .AutomaticUpgrades }}" == "true" ]]; then
PACKAGE_LIST="${PACKAGE_LIST} {{ .TeleportPackage }}-updater"
fi

# old versions of ubuntu require that keys get added by `apt-key add`, without
# adding the key apt shows a key signing error when installing teleport.
LEGACY_UBUNTU=false
Expand All @@ -41,14 +46,14 @@ on_azure() {
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 {{ .TeleportPackage }} jq
sudo apt-get install -y ${PACKAGE_LIST}
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
fi
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 {{ .TeleportPackage }} jq
sudo yum install -y ${PACKAGE_LIST}
else
echo "Unsupported distro: $ID"
exit 1
Expand Down
3 changes: 3 additions & 0 deletions api/types/installers/installers.go
Original file line number Diff line number Diff line change
Expand Up @@ -56,4 +56,7 @@ type Template struct {
TeleportPackage string
// RepoChannel is the repo's channel name to install.
RepoChannel string
// AutomaticUpgrades indicates whether Automatic Upgrades are enabled or disabled.
// Its value is either `true` or `false`.
AutomaticUpgrades string
}
12 changes: 8 additions & 4 deletions lib/web/apiserver.go
Original file line number Diff line number Diff line change
Expand Up @@ -1594,11 +1594,15 @@ func (h *Handler) installer(w http.ResponseWriter, r *http.Request, p httprouter
repoChannel = stableCloudChannelRepo
}

// TODO(marco): remove BuildType check when teleport-upgrade (oss) package is available in apt/yum repos.
automaticUpgrades := feats.AutomaticUpgrades && modules.GetModules().BuildType() == modules.BuildEnterprise

tmpl := installers.Template{
PublicProxyAddr: h.PublicProxyAddr(),
MajorVersion: version,
TeleportPackage: teleportPackage,
RepoChannel: repoChannel,
PublicProxyAddr: h.PublicProxyAddr(),
MajorVersion: version,
TeleportPackage: teleportPackage,
RepoChannel: repoChannel,
AutomaticUpgrades: strconv.FormatBool(automaticUpgrades),
}
err = instTmpl.Execute(w, tmpl)
return nil, trace.Wrap(err)
Expand Down
59 changes: 29 additions & 30 deletions lib/web/apiserver_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -2432,20 +2432,22 @@ func TestPingAutomaticUpgrades(t *testing.T) {

// TestInstallerRepoChannel ensures the returned installer script has the proper repo channel
func TestInstallerRepoChannel(t *testing.T) {
s := newWebSuiteWithConfig(t, webSuiteConfig{
authPreferenceSpec: &types.AuthPreferenceSpecV2{
Type: constants.Local,
SecondFactor: constants.SecondFactorOn,
Webauthn: &types.Webauthn{RPID: "localhost"},
},
})

wc := s.client(t)
t.Run("documented variables are injected", func(t *testing.T) {
s := newWebSuiteWithConfig(t, webSuiteConfig{
authPreferenceSpec: &types.AuthPreferenceSpecV2{
Type: constants.Local,
SecondFactor: constants.SecondFactorOn,
Webauthn: &types.Webauthn{RPID: "localhost"},
},
})
wc := s.client(t)
// Variables documented here: https://goteleport.com/docs/server-access/guides/ec2-discovery/#step-67-optional-customize-the-default-installer-script
err := s.server.Auth().SetInstaller(s.ctx, types.MustNewInstallerV1("custom", `#!/usr/bin/env bash
echo {{ .PublicProxyAddr }}
echo Teleport-{{ .MajorVersion }}
echo Repository Channel: {{ .RepoChannel }}
echo AutomaticUpgrades: {{ .AutomaticUpgrades }}
`))
require.NoError(t, err)

Expand All @@ -2457,21 +2459,15 @@ echo Repository Channel: {{ .RepoChannel }}
// Variables must be injected
require.Contains(t, responseString, "echo Teleport-v")
require.Contains(t, responseString, "echo Repository Channel: stable/v")
require.Contains(t, responseString, "echo AutomaticUpgrades: false")
})
t.Run("cloud with automatic upgrades", func(t *testing.T) {
modules.SetTestModules(t, &modules.TestModules{TestFeatures: modules.Features{
Cloud: true,
AutomaticUpgrades: true,
}})

s := newWebSuiteWithConfig(t, webSuiteConfig{
authPreferenceSpec: &types.AuthPreferenceSpecV2{
Type: constants.Local,
SecondFactor: constants.SecondFactorOn,
Webauthn: &types.Webauthn{RPID: "localhost"},
},
})
wc := s.client(t)
modules.SetTestModules(t, &modules.TestModules{
TestBuildType: modules.BuildEnterprise,
TestFeatures: modules.Features{
Cloud: true,
AutomaticUpgrades: true,
}})

t.Run("default-installer", func(t *testing.T) {
re, err := wc.Get(s.ctx, wc.Endpoint("webapi", "scripts", "installer", "default-installer"), url.Values{})
Expand All @@ -2482,6 +2478,12 @@ echo Repository Channel: {{ .RepoChannel }}
// The repo's channel to use is stable/cloud
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",
)
})
t.Run("default-agentless-installer", func(t *testing.T) {
re, err := wc.Get(s.ctx, wc.Endpoint("webapi", "scripts", "installer", "default-agentless-installer"), url.Values{})
Expand All @@ -2492,6 +2494,12 @@ echo Repository Channel: {{ .RepoChannel }}
// The repo's channel to use is stable/cloud
require.Contains(t, responseString, "stable/cloud")
require.NotContains(t, responseString, "stable/v")
require.Contains(t, responseString, ""+
" PACKAGE_LIST=\"teleport-ent\"\n"+
" if [[ \"true\" == \"true\" ]]; then\n"+
" PACKAGE_LIST=\"${PACKAGE_LIST} teleport-ent-updater\"\n"+
" fi\n",
)
})
})
t.Run("cloud without automatic upgrades", func(t *testing.T) {
Expand All @@ -2500,15 +2508,6 @@ echo Repository Channel: {{ .RepoChannel }}
AutomaticUpgrades: false,
}})

s := newWebSuiteWithConfig(t, webSuiteConfig{
authPreferenceSpec: &types.AuthPreferenceSpecV2{
Type: constants.Local,
SecondFactor: constants.SecondFactorOn,
Webauthn: &types.Webauthn{RPID: "localhost"},
},
})
wc := s.client(t)

t.Run("default-installer", func(t *testing.T) {
re, err := wc.Get(s.ctx, wc.Endpoint("webapi", "scripts", "installer", "default-installer"), url.Values{})
require.NoError(t, err)
Expand Down
11 changes: 11 additions & 0 deletions lib/web/join_tokens.go
Original file line number Diff line number Diff line change
Expand Up @@ -78,6 +78,13 @@ type scriptSettings struct {
joinMethod string
databaseInstallMode bool
stableCloudChannelRepo bool
installUpdater bool
}

// automaticUpgrades returns whether automaticUpgrades should be enabled.
func automaticUpgrades(features proto.Features) bool {
// TODO(marco): remove BuildType check when teleport-updater (oss) package is available in apt/yum repos.
return features.AutomaticUpgrades && modules.GetModules().BuildType() == modules.BuildEnterprise
}

func (h *Handler) createTokenHandle(w http.ResponseWriter, r *http.Request, params httprouter.Params, ctx *SessionContext) (interface{}, error) {
Expand Down Expand Up @@ -209,6 +216,7 @@ func (h *Handler) getNodeJoinScriptHandle(w http.ResponseWriter, r *http.Request
appInstallMode: false,
joinMethod: r.URL.Query().Get("method"),
stableCloudChannelRepo: useStableCloudChannelRepo,
installUpdater: automaticUpgrades(h.ClusterFeatures),
}

script, err := getJoinScript(r.Context(), settings, h.GetProxyClient())
Expand Down Expand Up @@ -253,6 +261,7 @@ func (h *Handler) getAppJoinScriptHandle(w http.ResponseWriter, r *http.Request,
appName: name,
appURI: uri,
stableCloudChannelRepo: useStableCloudChannelRepo,
installUpdater: automaticUpgrades(h.ClusterFeatures),
}

script, err := getJoinScript(r.Context(), settings, h.GetProxyClient())
Expand Down Expand Up @@ -280,6 +289,7 @@ func (h *Handler) getDatabaseJoinScriptHandle(w http.ResponseWriter, r *http.Req
token: params.ByName("token"),
databaseInstallMode: true,
stableCloudChannelRepo: useStableCloudChannelRepo,
installUpdater: automaticUpgrades(h.ClusterFeatures),
}

script, err := getJoinScript(r.Context(), settings, h.GetProxyClient())
Expand Down Expand Up @@ -406,6 +416,7 @@ func getJoinScript(ctx context.Context, settings scriptSettings, m nodeAPIGetter
"caPins": strings.Join(caPins, ","),
"packageName": packageName,
"repoChannel": repoChannel,
"installUpdater": strconv.FormatBool(settings.installUpdater),
"version": version,
"appInstallMode": strconv.FormatBool(settings.appInstallMode),
"appName": settings.appName,
Expand Down
66 changes: 66 additions & 0 deletions lib/web/join_tokens_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -926,6 +926,34 @@ func TestJoinScript(t *testing.T) {
})

t.Run("using repo", func(t *testing.T) {
t.Run("installUpdater set to true, list of packages must include updater package", func(t *testing.T) {
script, err := getJoinScript(context.Background(), scriptSettings{token: validToken, installUpdater: true}, m)
require.NoError(t, err)

require.Contains(t, script, ""+
" PACKAGE_LIST=${TELEPORT_PACKAGE_NAME}\n"+
" # (warning): This expression is constant. Did you forget the $ on a variable?\n"+
" # Disabling the warning above because expression is templated.\n"+
" # shellcheck disable=SC2050\n"+
" if [[ \"true\" == \"true\" ]]; then\n"+
" PACKAGE_LIST=\"${PACKAGE_LIST} ${TELEPORT_PACKAGE_NAME}-updater\"\n"+
" fi\n",
)
})
t.Run("installUpdater set to false, list of packages must not include updater package", func(t *testing.T) {
script, err := getJoinScript(context.Background(), scriptSettings{token: validToken, installUpdater: false}, m)
require.NoError(t, err)

require.Contains(t, script, ""+
" PACKAGE_LIST=${TELEPORT_PACKAGE_NAME}\n"+
" # (warning): This expression is constant. Did you forget the $ on a variable?\n"+
" # Disabling the warning above because expression is templated.\n"+
" # shellcheck disable=SC2050\n"+
" if [[ \"false\" == \"true\" ]]; then\n"+
" PACKAGE_LIST=\"${PACKAGE_LIST} ${TELEPORT_PACKAGE_NAME}-updater\"\n"+
" fi\n",
)
})
t.Run("cloud and automatic upgrades", func(t *testing.T) {
script, err := getJoinScript(context.Background(), scriptSettings{token: validToken, stableCloudChannelRepo: true}, m)
require.NoError(t, err)
Expand All @@ -949,6 +977,44 @@ func TestJoinScript(t *testing.T) {

}

func TestAutomaticUpgrades(t *testing.T) {
t.Run("enterprise and automatic upgrades enabled", func(t *testing.T) {
modules.SetTestModules(t, &modules.TestModules{
TestBuildType: modules.BuildEnterprise,
TestFeatures: modules.Features{
AutomaticUpgrades: true,
},
})

got := automaticUpgrades(*modules.GetModules().Features().ToProto())
require.True(t, got)
})
t.Run("enterprise but automatic upgrades disabled", func(t *testing.T) {
modules.SetTestModules(t, &modules.TestModules{
TestBuildType: modules.BuildEnterprise,
TestFeatures: modules.Features{
AutomaticUpgrades: false,
},
})

got := automaticUpgrades(*modules.GetModules().Features().ToProto())
require.False(t, got)
})

// There's no `teleport-updater` (oss) package yet, so even if automatic upgrades are enabled it must return false.
t.Run("automatic upgrades enabled but build is OSS", func(t *testing.T) {
modules.SetTestModules(t, &modules.TestModules{
TestBuildType: modules.BuildEnterprise,
TestFeatures: modules.Features{
AutomaticUpgrades: false,
},
})

got := automaticUpgrades(*modules.GetModules().Features().ToProto())
require.False(t, got)
})
}

func TestIsSameAzureRuleSet(t *testing.T) {
tests := []struct {
name string
Expand Down
12 changes: 10 additions & 2 deletions lib/web/scripts/node-join/install.sh
Original file line number Diff line number Diff line change
Expand Up @@ -851,6 +851,14 @@ install_from_repo() {
REPO_CHANNEL=stable/v"${TELEPORT_VERSION//.*/}"
fi

PACKAGE_LIST=${TELEPORT_PACKAGE_NAME}
# (warning): This expression is constant. Did you forget the $ on a variable?
# Disabling the warning above because expression is templated.
# shellcheck disable=SC2050
if [[ "{{.installUpdater}}" == "true" ]]; then
PACKAGE_LIST="${PACKAGE_LIST} ${TELEPORT_PACKAGE_NAME}-updater"
fi

# Populate $ID, $VERSION_ID, $VERSION_CODENAME and other env vars identifying the OS.
# shellcheck disable=SC1091
. /etc/os-release
Expand All @@ -872,7 +880,7 @@ install_from_repo() {
https://apt.releases.teleport.dev/${ID} ${VERSION_CODENAME} ${REPO_CHANNEL}" > /etc/apt/sources.list.d/teleport.list
fi
apt-get update
apt-get install -y ${TELEPORT_PACKAGE_NAME}
apt-get install -y ${PACKAGE_LIST}
elif [ "$ID" = "amzn" ] || [ "$ID" = "rhel" ] || [ "$ID" = "centos" ] ; then
if [ "$ID" = "rhel" ]; then
VERSION_ID="${VERSION_ID//.*/}" # convert version numbers like '7.2' to only include the major version
Expand All @@ -885,7 +893,7 @@ install_from_repo() {
# See: https://github.com/gravitational/teleport/issues/22581
yum --disablerepo="*" --enablerepo="teleport" clean metadata

yum install -y ${TELEPORT_PACKAGE_NAME}
yum install -y ${PACKAGE_LIST}
else
echo "Unsupported distro: $ID"
exit 1
Expand Down