diff --git a/docs/topics/clusterdefinitions.md b/docs/topics/clusterdefinitions.md index b1c886fc6ed..afb908736ba 100644 --- a/docs/topics/clusterdefinitions.md +++ b/docs/topics/clusterdefinitions.md @@ -576,7 +576,7 @@ A cluster can have 0 to 12 agent pool profiles. Agent Pool Profiles are used for | Name | Required | Description | | -------------------------------- | -------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | adminUsername | yes | Describes the username to be used on all linux clusters | -| ssh.publicKeys[].keyData | yes | The public SSH key used for authenticating access to all Linux nodes in the cluster | +| ssh.publicKeys.keyData | yes | The public SSH key used for authenticating access to all Linux nodes in the cluster | | secrets | no | Specifies an array of key vaults to pull secrets from and what secrets to pull from each | | customSearchDomain.name | no | describes the search domain to be used on all linux clusters | | customSearchDomain.realmUser | no | describes the realm user with permissions to update dns registries on Windows Server DNS | @@ -585,47 +585,6 @@ A cluster can have 0 to 12 agent pool profiles. Agent Pool Profiles are used for Here are instructions for [generating a public/private key pair][ssh] for `ssh.publicKeys.keyData`. - -#### Notes on SSH public keys - -At least one SSH key is required, but multiple are supported when deploying Kubernetes. - -Here's a minimal example using just one key: - -``` - "linuxProfile": { - "adminUsername": "azureuser", - "ssh": { - "publicKeys": [ - { - "keyData": "ssh-rsa AAAA...w==" - } - ] - } - }, -``` - - -And an example using two keys. - - -```json - "linuxProfile": { - "adminUsername": "azureuser", - "ssh": { - "publicKeys": [ - { - "keyData": "ssh-rsa AAAA...w==" - }, - { - "keyData": "ssh-rsa AAAA...w==" - } - ] - } - }, -``` - - #### secrets `secrets` details which certificates to install on the masters and nodes in the cluster. @@ -661,8 +620,7 @@ https://{keyvaultname}.vault.azure.net:443/secrets/{secretName}/{version} | windowsSku | no | SKU usedto find Windows VM to deploy from marketplace. Default: `Datacenter-Core-1809-with-Containers-smalldisk` | | imageVersion | no | Specific image version to deploy from marketplace. Default: `latest` | | windowsImageSourceURL | no | Path to an existing Azure storage blob with a sysprepped VHD. This is used to test pre-release or customized VHD files that you have uploaded to Azure. If provided, the above 4 parameters are ignored. | -| sshEnabled | no | If set to `true`, OpenSSH will be installed on windows nodes to allow for ssh remoting. **Only for Windows version 1809 or 2019** . The same SSH authorized public key(s) will be added from [linuxProfile.ssh.publicKeys](#linuxProfile) | - +| sshEnabled | no | If set to `true`, OpenSSH will be installed on windows nodes to allow for ssh remoting. **Only for Windows version 1809 or 2019** | #### Choosing a Windows version diff --git a/parts/k8s/kubernetesagentresourcesvmas.t b/parts/k8s/kubernetesagentresourcesvmas.t index 6fe28bccd63..d6695fdd931 100644 --- a/parts/k8s/kubernetesagentresourcesvmas.t +++ b/parts/k8s/kubernetesagentresourcesvmas.t @@ -189,7 +189,14 @@ {{GetKubernetesAgentCustomData .}} "linuxConfiguration": { "disablePasswordAuthentication": true, - "ssh": {{ GetSshPublicKeys }} + "ssh": { + "publicKeys": [ + { + "keyData": "[parameters('sshRSAPublicKey')]", + "path": "[variables('sshKeyPath')]" + } + ] + } } {{if HasLinuxSecrets}} , diff --git a/parts/k8s/kubernetesagentresourcesvmss.t b/parts/k8s/kubernetesagentresourcesvmss.t index 4afcd5a1767..41f5b8d5e59 100644 --- a/parts/k8s/kubernetesagentresourcesvmss.t +++ b/parts/k8s/kubernetesagentresourcesvmss.t @@ -115,7 +115,14 @@ {{GetKubernetesAgentCustomData .}} "linuxConfiguration": { "disablePasswordAuthentication": true, - "ssh": {{ GetSshPublicKeys }} + "ssh": { + "publicKeys": [ + { + "keyData": "[parameters('sshRSAPublicKey')]", + "path": "[variables('sshKeyPath')]" + } + ] + } } {{if HasLinuxSecrets}} , diff --git a/parts/k8s/kubernetesmasterresources.t b/parts/k8s/kubernetesmasterresources.t index ea45ec9d7f2..6171bc590cb 100644 --- a/parts/k8s/kubernetesmasterresources.t +++ b/parts/k8s/kubernetesmasterresources.t @@ -889,7 +889,14 @@ {{GetKubernetesMasterCustomData .}} "linuxConfiguration": { "disablePasswordAuthentication": true, - "ssh": {{ GetSshPublicKeys }} + "ssh": { + "publicKeys": [ + { + "keyData": "[parameters('sshRSAPublicKey')]", + "path": "[variables('sshKeyPath')]" + } + ] + } } {{if .LinuxProfile.HasSecrets}} , diff --git a/parts/k8s/kubernetesmasterresourcesvmss.t b/parts/k8s/kubernetesmasterresourcesvmss.t index fc95b7a2765..1aacf51c0c0 100644 --- a/parts/k8s/kubernetesmasterresourcesvmss.t +++ b/parts/k8s/kubernetesmasterresourcesvmss.t @@ -536,7 +536,14 @@ {{GetKubernetesMasterCustomData .}} "linuxConfiguration": { "disablePasswordAuthentication": true, - "ssh": {{ GetSshPublicKeys }} + "ssh": { + "publicKeys": [ + { + "keyData": "[parameters('sshRSAPublicKey')]", + "path": "[variables('sshKeyPath')]" + } + ] + } } {{if .LinuxProfile.HasSecrets}} , diff --git a/parts/k8s/kuberneteswindowssetup.ps1 b/parts/k8s/kuberneteswindowssetup.ps1 index 540658bf0c8..2a7f4695174 100644 --- a/parts/k8s/kuberneteswindowssetup.ps1 +++ b/parts/k8s/kuberneteswindowssetup.ps1 @@ -48,9 +48,6 @@ param( # These globals will not change between nodes in the same cluster, so they are not # passed as powershell parameters -## SSH public keys to add to authorized_keys -$global:SSHKeys = @( {{ GetSshPublicKeysPowerShell }} ) - ## Certificates generated by aks-engine $global:CACertificate = "{{WrapAsParameter "caCertificate"}}" $global:AgentCertificate = "{{WrapAsParameter "clientCertificate"}}" @@ -250,7 +247,8 @@ try $sshEnabled = [System.Convert]::ToBoolean("{{ WindowsSSHEnabled }}") if ( $sshEnabled ) { - Install-OpenSSH -SSHKeys $SSHKeys + $SSHKey = "{{ WrapAsParameter "sshRSAPublicKey" }}" + Install-OpenSSH -SSHKey $SSHKey } Write-Log "Disable Internet Explorer compat mode and set homepage" diff --git a/parts/k8s/windowsinstallopensshfunc.ps1 b/parts/k8s/windowsinstallopensshfunc.ps1 index 463151dfe72..a3b9cb0ae24 100644 --- a/parts/k8s/windowsinstallopensshfunc.ps1 +++ b/parts/k8s/windowsinstallopensshfunc.ps1 @@ -1,8 +1,8 @@ function Install-OpenSSH { Param( - [Parameter(Mandatory = $true)][string[]] - $SSHKeys + [Parameter(Mandatory = $true)][string] + $SSHKey ) $adminpath = "c:\ProgramData\ssh" @@ -26,10 +26,8 @@ Install-OpenSSH { } Write-Host "$adminpath found." - Write-Host "Adding keys to: $adminpath\$adminfile ..." - $SSHKeys | foreach-object { - Add-Content $adminpath\$adminfile $_ - } + Write-Host "Adding key to: $adminpath\$adminfile ..." + Add-Content $adminpath\$adminfile $SSHKey Write-Host "Setting required permissions..." icacls $adminpath\$adminfile /remove "NT AUTHORITY\Authenticated Users" diff --git a/pkg/api/vlabs/types.go b/pkg/api/vlabs/types.go index e47ec5832f0..4627fde771a 100644 --- a/pkg/api/vlabs/types.go +++ b/pkg/api/vlabs/types.go @@ -129,7 +129,7 @@ type CertificateProfile struct { type LinuxProfile struct { AdminUsername string `json:"adminUsername" validate:"required"` SSH struct { - PublicKeys []PublicKey `json:"publicKeys" validate:"required,min=1"` + PublicKeys []PublicKey `json:"publicKeys" validate:"required,len=1"` } `json:"ssh" validate:"required"` Secrets []KeyVaultSecrets `json:"secrets,omitempty"` ScriptRootURL string `json:"scriptroot,omitempty"` diff --git a/pkg/api/vlabs/validate.go b/pkg/api/vlabs/validate.go index 83abca24d00..338abb66f43 100644 --- a/pkg/api/vlabs/validate.go +++ b/pkg/api/vlabs/validate.go @@ -479,10 +479,8 @@ func (a *Properties) validateZones() error { } func (a *Properties) validateLinuxProfile() error { - for _, publicKey := range a.LinuxProfile.SSH.PublicKeys { - if e := validate.Var(publicKey.KeyData, "required"); e != nil { - return errors.New("KeyData in LinuxProfile.SSH.PublicKeys cannot be empty string") - } + if e := validate.Var(a.LinuxProfile.SSH.PublicKeys[0].KeyData, "required"); e != nil { + return errors.New("KeyData in LinuxProfile.SSH.PublicKeys cannot be empty string") } return validateKeyVaultSecrets(a.LinuxProfile.Secrets, false) } diff --git a/pkg/api/vlabs/validate_test.go b/pkg/api/vlabs/validate_test.go index 5b69b8ccfa3..98f10d5f897 100644 --- a/pkg/api/vlabs/validate_test.go +++ b/pkg/api/vlabs/validate_test.go @@ -732,7 +732,7 @@ func Test_Properties_ValidateNetworkPluginPlusPolicy(t *testing.T) { func TestProperties_ValidateLinuxProfile(t *testing.T) { cs := getK8sDefaultContainerService(true) cs.Properties.LinuxProfile.SSH = struct { - PublicKeys []PublicKey `json:"publicKeys" validate:"required,min=1"` + PublicKeys []PublicKey `json:"publicKeys" validate:"required,len=1"` }{ PublicKeys: []PublicKey{{}}, } @@ -742,23 +742,6 @@ func TestProperties_ValidateLinuxProfile(t *testing.T) { if err.Error() != expectedMsg { t.Errorf("expected error message : %s to be thrown, but got : %s", expectedMsg, err.Error()) } - - cs.Properties.LinuxProfile.SSH = struct { - PublicKeys []PublicKey `json:"publicKeys" validate:"required,min=1"` - }{ - PublicKeys: []PublicKey{ - { - KeyData: "not empty", - }, - {}, - }, - } - expectedMsg = "KeyData in LinuxProfile.SSH.PublicKeys cannot be empty string" - err = cs.Validate(true) - - if err.Error() != expectedMsg { - t.Errorf("expected error message : %s to be thrown, but got : %s", expectedMsg, err.Error()) - } } func TestProperties_ValidateInvalidExtensions(t *testing.T) { @@ -1055,7 +1038,7 @@ func getK8sDefaultContainerService(hasWindows bool) *ContainerService { LinuxProfile: &LinuxProfile{ AdminUsername: "azureuser", SSH: struct { - PublicKeys []PublicKey `json:"publicKeys" validate:"required,min=1"` + PublicKeys []PublicKey `json:"publicKeys" validate:"required,len=1"` }{ PublicKeys: []PublicKey{{ KeyData: "publickeydata", diff --git a/pkg/engine/template_generator.go b/pkg/engine/template_generator.go index 9323f2d603f..49c39c42e13 100644 --- a/pkg/engine/template_generator.go +++ b/pkg/engine/template_generator.go @@ -7,7 +7,6 @@ import ( "archive/zip" "bytes" "encoding/base64" - "encoding/json" "fmt" "runtime/debug" "sort" @@ -21,7 +20,6 @@ import ( "github.com/Azure/aks-engine/pkg/api/common" "github.com/Azure/aks-engine/pkg/helpers" "github.com/Azure/aks-engine/pkg/i18n" - "github.com/Azure/azure-sdk-for-go/services/compute/mgmt/2018-10-01/compute" "github.com/pkg/errors" log "github.com/sirupsen/logrus" ) @@ -645,45 +643,6 @@ func (t *TemplateGenerator) getTemplateFuncMap(cs *api.ContainerService) templat "GetB64sshdConfig": func() string { return getBase64CustomScript(sshdConfig) }, - "GetSshPublicKeys": func() string { - // This generates the publicKeys array described at https://docs.microsoft.com/en-us/rest/api/compute/virtualmachines/createorupdate#sshconfiguration - // "ssh": { - // "publicKeys": [ - // { - // "keyData": "[parameters('sshRSAPublicKey')]", - // "path": "[variables('sshKeyPath')]" - // } - // ] - // } - publicKeyPath := "[variables('sshKeyPath')]" - publicKeys := []compute.SSHPublicKey{} - for _, publicKey := range cs.Properties.LinuxProfile.SSH.PublicKeys { - publicKeyTrimmed := strings.TrimSpace(publicKey.KeyData) - publicKeys = append(publicKeys, compute.SSHPublicKey{ - Path: &publicKeyPath, - KeyData: &publicKeyTrimmed, - }) - } - ssh := compute.SSHConfiguration{ - PublicKeys: &publicKeys, - } - sshJSON, err := json.Marshal(ssh) - if err != nil { - panic(err) - } - return string(sshJSON) - }, - "GetSshPublicKeysPowerShell": func() string { - str := "" - lastItem := len(cs.Properties.LinuxProfile.SSH.PublicKeys) - 1 - for i, publicKey := range cs.Properties.LinuxProfile.SSH.PublicKeys { - str += `"` + strings.TrimSpace(publicKey.KeyData) + `"` - if i < lastItem { - str += ", " - } - } - return str - }, "GetKubernetesMasterPreprovisionYaml": func() string { str := "" if cs.Properties.MasterProfile.PreprovisionExtension != nil {