{"record":{"id":"45dc29614d2a0c80","repo":"kubernetes/kops","slug":"found-vmss-without-ssh-config","errorCode":null,"errorMessage":"found VMSS without SSH config","messagePattern":"found VMSS without SSH config","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"upup/pkg/fi/cloudup/azuretasks/vmscaleset.go","lineNumber":172,"sourceCode":"\tvar loadBalancerID *azure.LoadBalancerID\n\tif ipConfig.Properties.LoadBalancerBackendAddressPools != nil {\n\t\tfor _, i := range ipConfig.Properties.LoadBalancerBackendAddressPools {\n\t\t\tif !strings.Contains(*i.ID, \"api\") {\n\t\t\t\tcontinue\n\t\t\t}\n\t\t\tloadBalancerID, err = azure.ParseLoadBalancerID(*i.ID)\n\t\t\tif err != nil {\n\t\t\t\treturn nil, fmt.Errorf(\"failed to parse loadbalancer ID %s\", *i.ID)\n\t\t\t}\n\t\t}\n\t}\n\n\tosProfile := profile.OSProfile\n\tif osProfile.LinuxConfiguration == nil {\n\t\treturn nil, fmt.Errorf(\"found VMSS without Linux config\")\n\t}\n\tif osProfile.LinuxConfiguration.SSH == nil {\n\t\treturn nil, fmt.Errorf(\"found VMSS without SSH config\")\n\t}\n\tif osProfile.LinuxConfiguration.SSH.PublicKeys == nil {\n\t\treturn nil, fmt.Errorf(\"found VMSS without SSH public keys\")\n\t}\n\tsshKeys := osProfile.LinuxConfiguration.SSH.PublicKeys\n\tif len(sshKeys) != 1 {\n\t\treturn nil, fmt.Errorf(\"expecting exactly 1 SSH key for %q, found %d: %+v\", *s.Name, len(sshKeys), sshKeys)\n\t}\n\n\tvar userData []byte\n\tif profile.UserData != nil {\n\t\tuserData, err = base64.StdEncoding.DecodeString(*profile.UserData)\n\t\tif err != nil {\n\t\t\treturn nil, fmt.Errorf(\"failed to decode user data: %w\", err)\n\t\t}\n\t}\n\n\tvmss := &VMScaleSet{","sourceCodeStart":154,"sourceCodeEnd":190,"githubUrl":"https://github.com/kubernetes/kops/blob/4c8573c808a73d578c5eadc86d410646ea0b0d73/upup/pkg/fi/cloudup/azuretasks/vmscaleset.go#L154-L190","documentation":"After confirming LinuxConfiguration exists, Find() requires osProfile.linuxConfiguration.ssh to be present so it can read the authorized public keys. A nil SSH block means the scale set has no SSH configuration at all, which kOps treats as unmodelable and returns this error.","triggerScenarios":"Find() on a VMSS where linuxConfiguration is set but linuxConfiguration.ssh is nil — e.g. linuxConfiguration created with only disablePasswordAuthentication and no ssh sub-object, or stripped by external tooling.","commonSituations":"Custom ARM/Bicep/Terraform definitions of node pools omitting the ssh block; drift after manual portal edits; test fixtures that populate linuxConfiguration partially.","solutions":["Reconcile the scale set via `kops update cluster --yes` so SSH config is regenerated from the cluster spec.","If authored externally, add the ssh block with at least one publicKey under linuxConfiguration.","Check the SSH key data in the cluster spec (`kops get cluster -oyaml`, sshPublicKey field) and update it if it was removed.","Fix test fixtures to include SSHConfiguration with PublicKeys."],"exampleFix":"// before\n\"linuxConfiguration\": { \"disablePasswordAuthentication\": true }\n// after\n\"linuxConfiguration\": { \"disablePasswordAuthentication\": true, \"ssh\": { \"publicKeys\": [ { \"path\": \"/home/azureuser/.ssh/authorized_keys\", \"keyData\": \"ssh-rsa AAAA...\" } ] } }","handlingStrategy":"validation","validationCode":"if vmss.Properties.VirtualMachineProfile.OSProfile.LinuxConfiguration.SSH == nil {\n  return fmt.Errorf(\"VMSS %s lacks SSH configuration\", fi.ValueOf(vmss.Name))\n}","typeGuard":"func hasSSHConfig(lc *compute.VirtualMachineScaleSetLinuxConfiguration) bool {\n  return lc != nil && lc.SSH != nil\n}","tryCatchPattern":null,"preventionTips":["Always include the ssh block when defining linuxConfiguration externally","Set sshPublicKey in the cluster spec and let kops render SSH config","Avoid editors/tooling that strip nested ARM fields","Cover the ssh block in template/unit tests"],"tags":["azure","vmss","ssh","osprofile"],"backgroundTag":"vmss-missing-ssh-config","analyzedSha":"4c8573c808a73d578c5eadc86d410646ea0b0d73","analyzedAt":"2026-09-05T04:13:19.212Z","contentChangedAt":"2026-09-05T04:13:19.212Z","schemaVersion":2},"datasetVersion":"2026-09-12T07:17:12.445Z"}