diff --git a/docs/topics/rotate-certs.md b/docs/topics/rotate-certs.md index 85a4d994d..7a7146cbc 100644 --- a/docs/topics/rotate-certs.md +++ b/docs/topics/rotate-certs.md @@ -103,6 +103,10 @@ This helps protect against man-in-the-middle attacks, where an attacker may atte Starting with AKS Engine v0.77.0, `StrictHostKeyChecking` will be enforced during the execution of the `aks-engine-azurestack rotate-certs` command. Hence, new entries will be appended to the local `known_hosts` file if no SSH sessions to the remove host were established in the past. +Starting with AKS Engine v0.79.0, file `~/.ssh/known_hosts` is kept unchanged. +Instead, AKS Engine creates a copy in `~/.aks-engine-azurestack/known_hosts` and new entries are added to this file. +Every AKS Engine command execution refreshes the content of `~/.aks-engine-azurestack/known_hosts`. + ### Generating certificates `aks-engine-azurestack rotate-certs` is able to generate the new set of certificates that will be deployed to the cluster based on the information found in the API model. diff --git a/docs/tutorials/cli-overview.md b/docs/tutorials/cli-overview.md index a62c4443a..7bc02dd9f 100644 --- a/docs/tutorials/cli-overview.md +++ b/docs/tutorials/cli-overview.md @@ -119,42 +119,6 @@ We generally recommend that you manage node pool scaling dynamically using the ` Detailed documentation on `aks-engine-azurestack scale` can be found [here](../topics/scale.md). -### `aks-engine-azurestack update` - -The `aks-engine-azurestack update` command will update the VMSS model of a node pool according to a modified configuration of the aks-engine-generated `apimodel.json`. The updated node configuration will not take affect on any existing nodes, but will be applied to all future, new nodes created by VMSS scale out operations. Use this command to update the node configuration (such as the OS configuration, VM SKU, or Kubernetes kubelet configuration) of an existing VMSS node pool. - -Note: `aks-engine-azurestack update` **can not** be used to update the control plane! To update control plane VM configuration, see [`aks-engine-azurestack upgrade --control-plane-only` documentation here](../topics/upgrade.md#when-should-i-use-aks-engine-upgrade---control-plane-only). - - -```sh -$ aks-engine-azurestack update --help -Update an existing AKS Engine-created VMSS node pool in a Kubernetes cluster by updating its VMSS model - -Usage: - aks-engine-azurestack update [flags] - -Flags: - -m, --api-model string path to the generated apimodel.json file - --auth-method client_secret auth method (default:client_secret, `cli`, `client_certificate`, `device`) (default "cli") - --azure-env string the target Azure cloud (default "AzurePublicCloud") - --certificate-path string path to client certificate (used with --auth-method=client_certificate) - --client-id string client id (used with --auth-method=[client_secret|client_certificate]) - --client-secret string client secret (used with --auth-method=client_secret) - -h, --help help for update - --identity-system azure_ad identity system (default:azure_ad, `adfs`) (default "azure_ad") - --language string language to return error messages in (default "en-us") - -l, --location string location the cluster is deployed in - --node-pool string node pool to scale - --private-key-path string path to private key (used with --auth-method=client_certificate) - -g, --resource-group string the resource group where the cluster is deployed - -s, --subscription-id string azure subscription id (required) - -Global Flags: - --debug enable verbose debug logs -``` - -Detailed documentation on `aks-engine-azurestack update` can be found [here](../topics/update.md). - ### `aks-engine-azurestack addpool` The `aks-engine-azurestack addpool` command will add a new node pool to an existing AKS Engine-created cluster. Using a JSON file to define a the new node pool's configuration, and referencing the aks-engine-generated `apimodel.json`, you can add new nodes to your cluster. Use this command to add a specific number of new nodes using a discrete configuration compared to existing nodes participating in your cluster. @@ -262,7 +226,7 @@ Detailed documentation on `aks-engine-azurestack generate` can be found [here](. ### `aks-engine-azurestack rotate-certs` -The `aks-engine-azurestack rotate-certs` command is currently experimental and not recommended for use on production clusters. +Detailed documentation on `aks-engine-azurestack rotate-certs` can be found [here](../topics/rotate-certs.md). ### `aks-engine-azurestack get-logs` diff --git a/pkg/helpers/ssh/init.go b/pkg/helpers/ssh/init.go index d212af67f..1c76d6ff3 100644 --- a/pkg/helpers/ssh/init.go +++ b/pkg/helpers/ssh/init.go @@ -3,7 +3,49 @@ package ssh +import ( + "io" + "os" + "path" + + log "github.com/sirupsen/logrus" +) + var ( - khpath string - lineBreak string + khsource string + khpath string +) + +const ( + knownHostFileName = "known_hosts" ) + +// copyKnownHosts copies the SSH's known_hosts file to aks-engine's working directory. +// Errors are logged but not returned as we can still continue regardless. +func copyKnownHosts() { + src, err := os.Open(khsource) + if err != nil { + log.Warnf("failed to open file %s", khsource) + return + } + defer src.Close() + + dir := path.Dir(khpath) + if err = os.MkdirAll(dir, 0700); err != nil { + log.Warnf("failed to create %s directory", dir) + return + } + + dst, err := os.Create(khpath) + if err != nil { + log.Warnf("failed to open file %s", khpath) + return + } + defer dst.Close() + + _, err = io.Copy(dst, src) + if err != nil { + log.Warnf("failed to copy %s to %s", khsource, khpath) + return + } +} diff --git a/pkg/helpers/ssh/init_darwin.go b/pkg/helpers/ssh/init_darwin.go index 9e6e881cc..7c47a8d98 100644 --- a/pkg/helpers/ssh/init_darwin.go +++ b/pkg/helpers/ssh/init_darwin.go @@ -9,6 +9,7 @@ import ( ) func init() { - khpath = filepath.Join(os.Getenv("HOME"), ".ssh", "known_hosts") - lineBreak = "\n" + khsource = filepath.Join(os.Getenv("HOME"), ".ssh", knownHostFileName) + khpath = filepath.Join(os.Getenv("HOME"), ".aks-engine-azurestack", knownHostFileName) + copyKnownHosts() } diff --git a/pkg/helpers/ssh/init_linux.go b/pkg/helpers/ssh/init_linux.go index 9e6e881cc..7c47a8d98 100644 --- a/pkg/helpers/ssh/init_linux.go +++ b/pkg/helpers/ssh/init_linux.go @@ -9,6 +9,7 @@ import ( ) func init() { - khpath = filepath.Join(os.Getenv("HOME"), ".ssh", "known_hosts") - lineBreak = "\n" + khsource = filepath.Join(os.Getenv("HOME"), ".ssh", knownHostFileName) + khpath = filepath.Join(os.Getenv("HOME"), ".aks-engine-azurestack", knownHostFileName) + copyKnownHosts() } diff --git a/pkg/helpers/ssh/init_windows.go b/pkg/helpers/ssh/init_windows.go index a3cc89196..067723e9f 100644 --- a/pkg/helpers/ssh/init_windows.go +++ b/pkg/helpers/ssh/init_windows.go @@ -9,6 +9,7 @@ import ( ) func init() { - khpath = filepath.Join(os.Getenv("UserProfile"), ".ssh", "known_hosts") - lineBreak = "\r\n" + khsource = filepath.Join(os.Getenv("UserProfile"), ".ssh", knownHostFileName) + khpath = filepath.Join(os.Getenv("UserProfile"), ".aks-engine-azurestack", knownHostFileName) + copyKnownHosts() } diff --git a/pkg/helpers/ssh/ssh.go b/pkg/helpers/ssh/ssh.go index 1bbad5dfe..1053dec60 100644 --- a/pkg/helpers/ssh/ssh.go +++ b/pkg/helpers/ssh/ssh.go @@ -164,8 +164,8 @@ func clientConfigAuth(authConfig *AuthConfig) ([]ssh.AuthMethod, error) { return []ssh.AuthMethod{ssh.Password(authConfig.Password)}, nil } -// knownHostsHostKeyCallback returns a host key callback that uses file -// ${HOME}/.ssh/known_hosts to store known host keys +// knownHostsHostKeyCallback returns a host key callback that uses +// a known_hosts file to store known host keys func knownHostsHostKeyCallback() (ssh.HostKeyCallback, error) { err := ensuresKnownHosts() if err != nil { @@ -178,7 +178,7 @@ func knownHostsHostKeyCallback() (ssh.HostKeyCallback, error) { return khCallback, nil } -// ensuresKnownHosts creates file ${HOME}/.ssh/known_hosts if it does not exist +// ensuresKnownHosts creates the known_hosts file if it does not exist func ensuresKnownHosts() error { if err := os.MkdirAll(path.Dir(khpath), 0700); err != nil { return errors.Wrap(err, "creating .ssh directory") @@ -196,7 +196,7 @@ func hostKeyString(k ssh.PublicKey) string { return fmt.Sprintf("%s %s", k.Type(), base64.StdEncoding.EncodeToString(k.Marshal())) } -// addHostKey adds an entry to ${HOME}/.ssh/known_hosts +// addHostKey adds an entry to the known_hosts file func addHostKey(hostname string, pubKey ssh.PublicKey) error { f, err := os.OpenFile(khpath, os.O_APPEND|os.O_WRONLY, 0600) if err != nil { @@ -204,7 +204,7 @@ func addHostKey(hostname string, pubKey ssh.PublicKey) error { } defer f.Close() // append blank line - if _, err = f.WriteString(lineBreak); err != nil { + if _, err = f.WriteString(fmt.Sprintln()); err != nil { return errors.Wrap(err, "appending blank line to known_hosts file") } // append host key line