Skip to content

Commit fbce438

Browse files
authored
fix: SSH not disabled issue on AzureLinux and add E2E to guard (#7190)
1 parent 0ae0f92 commit fbce438

101 files changed

Lines changed: 242 additions & 98 deletions

File tree

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

e2e/scenario_test.go

Lines changed: 76 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -710,6 +710,82 @@ func Test_Ubuntu2204_EntraIDSSH_Scriptless(t *testing.T) {
710710
})
711711
}
712712

713+
func Test_Ubuntu2204_DisableSSH(t *testing.T) {
714+
RunScenario(t, &Scenario{
715+
Description: "Tests that a node using Ubuntu 2204 VHD with SSH disabled can be properly bootstrapped and SSH daemon is disabled",
716+
Config: Config{
717+
Cluster: ClusterKubenet,
718+
VHD: config.VHDUbuntu2204Gen2Containerd,
719+
BootstrapConfigMutator: func(nbc *datamodel.NodeBootstrappingConfiguration) {
720+
nbc.SSHStatus = datamodel.SSHOff
721+
},
722+
SkipSSHConnectivityValidation: true, // Skip SSH connectivity validation since SSH is down
723+
SkipDefaultValidation: true, // Skip default validation since it requires SSH connectivity
724+
Validator: func(ctx context.Context, s *Scenario) {
725+
// Validate SSH daemon is disabled via RunCommand
726+
ValidateSSHServiceDisabled(ctx, s)
727+
},
728+
},
729+
})
730+
}
731+
732+
func Test_AzureLinuxV2_DisableSSH(t *testing.T) {
733+
RunScenario(t, &Scenario{
734+
Description: "Tests that a node using AzureLinuxV2 VHD with SSH disabled can be properly bootstrapped and SSH daemon is disabled",
735+
Config: Config{
736+
Cluster: ClusterKubenet,
737+
VHD: config.VHDAzureLinuxV2Gen2,
738+
BootstrapConfigMutator: func(nbc *datamodel.NodeBootstrappingConfiguration) {
739+
nbc.SSHStatus = datamodel.SSHOff
740+
},
741+
SkipSSHConnectivityValidation: true, // Skip SSH connectivity validation since SSH is down
742+
SkipDefaultValidation: true, // Skip default validation since it requires SSH connectivity
743+
Validator: func(ctx context.Context, s *Scenario) {
744+
// Validate SSH daemon is disabled via RunCommand
745+
ValidateSSHServiceDisabled(ctx, s)
746+
},
747+
},
748+
})
749+
}
750+
751+
func Test_MarinerV2_DisableSSH(t *testing.T) {
752+
RunScenario(t, &Scenario{
753+
Description: "Tests that a node using MarinerV2 VHD with SSH disabled can be properly bootstrapped and SSH daemon is disabled",
754+
Config: Config{
755+
Cluster: ClusterKubenet,
756+
VHD: config.VHDCBLMarinerV2Gen2,
757+
BootstrapConfigMutator: func(nbc *datamodel.NodeBootstrappingConfiguration) {
758+
nbc.SSHStatus = datamodel.SSHOff
759+
},
760+
SkipSSHConnectivityValidation: true, // Skip SSH connectivity validation since SSH is down
761+
SkipDefaultValidation: true, // Skip default validation since it requires SSH connectivity
762+
Validator: func(ctx context.Context, s *Scenario) {
763+
// Validate SSH daemon is disabled via RunCommand
764+
ValidateSSHServiceDisabled(ctx, s)
765+
},
766+
},
767+
})
768+
}
769+
770+
func Test_Flatcar_DisableSSH(t *testing.T) {
771+
RunScenario(t, &Scenario{
772+
Description: "Tests that a node using Flatcar VHD with SSH disabled can be properly bootstrapped and SSH daemon is disabled",
773+
Config: Config{
774+
Cluster: ClusterKubenet,
775+
VHD: config.VHDFlatcarGen2,
776+
BootstrapConfigMutator: func(nbc *datamodel.NodeBootstrappingConfiguration) {
777+
nbc.SSHStatus = datamodel.SSHOff
778+
},
779+
SkipSSHConnectivityValidation: true, // Skip SSH connectivity validation since SSH is down
780+
SkipDefaultValidation: true, // Skip default validation since it requires SSH connectivity
781+
Validator: func(ctx context.Context, s *Scenario) {
782+
// Validate SSH daemon is disabled via RunCommand
783+
ValidateSSHServiceDisabled(ctx, s)
784+
},
785+
},
786+
})
787+
}
788+
713789
func Test_Ubuntu2204_AirGap(t *testing.T) {
714790
RunScenario(t, &Scenario{
715791
Description: "Tests that a node using the Ubuntu 2204 VHD and is airgap can be properly bootstrapped",

e2e/validators.go

Lines changed: 65 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1091,6 +1091,71 @@ fi`)},
10911091
s.T.Logf("PubkeyAuthentication is properly disabled as expected")
10921092
}
10931093

1094+
// ValidateSSHServiceDisabled validates that the SSH daemon service is disabled and stopped on the node
1095+
func ValidateSSHServiceDisabled(ctx context.Context, s *Scenario) {
1096+
s.T.Helper()
1097+
1098+
// Use VMSS RunCommand to check SSH service status directly on the node
1099+
// Ubuntu uses 'ssh' as service name, while AzureLinux and Mariner use 'sshd'
1100+
runPoller, err := config.Azure.VMSSVM.BeginRunCommand(ctx, *s.Runtime.Cluster.Model.Properties.NodeResourceGroup, s.Runtime.VMSSName, "0", armcompute.RunCommandInput{
1101+
CommandID: to.Ptr("RunShellScript"),
1102+
Script: []*string{to.Ptr(`#!/bin/bash
1103+
# Determine the correct SSH service name based on the distro
1104+
# Ubuntu uses 'ssh', AzureLinux and Mariner use 'sshd'
1105+
if [ -f /etc/os-release ]; then
1106+
. /etc/os-release
1107+
if [[ "$ID" == "ubuntu" ]]; then
1108+
SSH_SERVICE="ssh"
1109+
else
1110+
SSH_SERVICE="sshd"
1111+
fi
1112+
else
1113+
# Default to sshd if we can't determine the OS
1114+
SSH_SERVICE="sshd"
1115+
fi
1116+
1117+
echo "Detected SSH service name: $SSH_SERVICE"
1118+
1119+
# Check SSH service status
1120+
status_output=$(systemctl status "$SSH_SERVICE" 2>&1)
1121+
echo "SSH service status output:"
1122+
echo "$status_output"
1123+
1124+
# Check if the service is inactive (dead) and disabled
1125+
if echo "$status_output" | grep -q "Active: inactive (dead)"; then
1126+
if echo "$status_output" | grep -q "Loaded:.*disabled"; then
1127+
echo "SUCCESS: SSH service is disabled and stopped"
1128+
exit 0
1129+
else
1130+
echo "FAILED: SSH service is inactive but not disabled"
1131+
exit 1
1132+
fi
1133+
else
1134+
echo "FAILED: SSH service is not inactive"
1135+
exit 1
1136+
fi`)},
1137+
}, nil)
1138+
require.NoError(s.T, err, "Failed to run command to check SSH service status")
1139+
1140+
runResp, err := runPoller.PollUntilDone(ctx, nil)
1141+
require.NoError(s.T, err, "Failed to complete command to check SSH service status")
1142+
1143+
// Parse the response to check the result
1144+
respJson, err := runResp.MarshalJSON()
1145+
require.NoError(s.T, err, "Failed to marshal run command response")
1146+
s.T.Logf("Run command output: %s", string(respJson))
1147+
1148+
// Parse the JSON response to extract the output
1149+
respString := string(respJson)
1150+
1151+
// Check if the command execution was successful by looking for our success message in the output
1152+
if !strings.Contains(respString, "SUCCESS: SSH service is disabled and stopped") {
1153+
s.T.Fatalf("SSH service is not properly disabled and stopped. Full response: %s", respString)
1154+
}
1155+
1156+
s.T.Logf("SSH service is properly disabled and stopped as expected")
1157+
}
1158+
10941159
func ValidateNvidiaDCGMExporterSystemDServiceRunning(ctx context.Context, s *Scenario) {
10951160
s.T.Helper()
10961161
command := []string{

parts/linux/cloud-init/artifacts/cse_config.sh

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -942,7 +942,10 @@ ensureGPUDrivers() {
942942
}
943943

944944
disableSSH() {
945+
# On ubuntu, the ssh service is named "ssh.service"
945946
systemctlDisableAndStop ssh || exit $ERR_DISABLE_SSH
947+
# On AzureLinux, the ssh service is named "sshd.service"
948+
systemctlDisableAndStop sshd || exit $ERR_DISABLE_SSH
946949
}
947950

948951
configureSSHPubkeyAuth() {

0 commit comments

Comments
 (0)