Skip to content

Commit

Permalink
Merge pull request #927 from cpanato/GH-909
Browse files Browse the repository at this point in the history
🌱 AzureMachinePool/AzureManagedControlPlane: generate ssh key when is not set
  • Loading branch information
k8s-ci-robot authored Sep 28, 2020
2 parents 20517fd + f3e7a35 commit 0c45468
Show file tree
Hide file tree
Showing 20 changed files with 695 additions and 43 deletions.
15 changes: 5 additions & 10 deletions api/v1alpha3/azuremachine_default.go
Original file line number Diff line number Diff line change
Expand Up @@ -17,27 +17,22 @@ limitations under the License.
package v1alpha3

import (
"crypto/rand"
"crypto/rsa"
"encoding/base64"

"github.com/pkg/errors"
"golang.org/x/crypto/ssh"

utilSSH "sigs.k8s.io/cluster-api-provider-azure/util/ssh"
)

// SetDefaultSSHPublicKey sets the default SSHPublicKey for an AzureMachine
func (m *AzureMachine) SetDefaultSSHPublicKey() error {
sshKeyData := m.Spec.SSHPublicKey
if sshKeyData == "" {
privateKey, perr := rsa.GenerateKey(rand.Reader, 2048)
if perr != nil {
return errors.Wrap(perr, "Failed to generate private key")
_, publicRsaKey, err := utilSSH.GenerateSSHKey()
if err != nil {
return err
}

publicRsaKey, perr := ssh.NewPublicKey(&privateKey.PublicKey)
if perr != nil {
return errors.Wrap(perr, "Failed to generate public key")
}
m.Spec.SSHPublicKey = base64.StdEncoding.EncodeToString(ssh.MarshalAuthorizedKey(publicRsaKey))
}

Expand Down
4 changes: 2 additions & 2 deletions docs/book/src/topics/ephemeral-os.md
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ disk SKU limits. Instead they will always be capable of saturating the
VM level limits. This can significantly improve performance on the OS
disk. Ephemeral storage used for the OS will not persist between
maintenance events and VM redeployments. This is ideal for stateless
base OS disks, where any stateful data is kept elsewhere.
base OS disks, where any stateful data is kept elsewhere.

There are a few kinds of local storage devices available on Azure VMs.
Each VM size will have a different combination. For example, some sizes
Expand Down Expand Up @@ -56,6 +56,6 @@ spec:
managedDisk:
storageAccountType: Standard_LRS
osType: Linux
sshPublicKey: ${AZURE_SSH_PUBLIC_KEY_B64}
sshPublicKey: ${AZURE_SSH_PUBLIC_KEY_B64:=""}
vmSize: ${AZURE_NODE_MACHINE_TYPE}
````
4 changes: 2 additions & 2 deletions docs/book/src/topics/managedcluster.md
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,7 @@ export AZURE_LOCATION="southcentralus"
export AZURE_RESOURCE_GROUP="${CLUSTER_NAME}"
# set AZURE_SUBSCRIPTION_ID to the GUID of your subscription
# this example uses an sdk authentication file and parses the subscriptionId with jq
# this file may be created using
# this file may be created using
#
# `az ad sp create-for-rbac --sdk-auth [roles] > sp.json`
#
Expand Down Expand Up @@ -92,7 +92,7 @@ spec:
name: agentpool0
location: southcentralus
resourceGroup: foo-bar
sshPublicKey: ${AZURE_SSH_PUBLIC_KEY_B64}
sshPublicKey: ${AZURE_SSH_PUBLIC_KEY_B64:=""}
subscriptionID: fae7cc14-bfba-4471-9435-f945b42a16dd # fake uuid
version: v1.17.4
networkPolicy: azure # or calico
Expand Down
40 changes: 40 additions & 0 deletions exp/api/v1alpha3/azuremachinepool_default.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
/*
Copyright 2020 The Kubernetes Authors.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/

package v1alpha3

import (
"encoding/base64"

"golang.org/x/crypto/ssh"

utilSSH "sigs.k8s.io/cluster-api-provider-azure/util/ssh"
)

// SetDefaultSSHPublicKey sets the default SSHPublicKey for an AzureMachinePool
func (amp *AzureMachinePool) SetDefaultSSHPublicKey() error {
sshKeyData := amp.Spec.Template.SSHPublicKey
if sshKeyData == "" {
_, publicRsaKey, err := utilSSH.GenerateSSHKey()
if err != nil {
return err
}

amp.Spec.Template.SSHPublicKey = base64.StdEncoding.EncodeToString(ssh.MarshalAuthorizedKey(publicRsaKey))
}

return nil
}
57 changes: 57 additions & 0 deletions exp/api/v1alpha3/azuremachinepool_default_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,57 @@
/*
Copyright 2020 The Kubernetes Authors.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/

package v1alpha3

import (
"testing"

. "github.com/onsi/gomega"
)

func TestAzureMachinePool_SetDefaultSSHPublicKey(t *testing.T) {
g := NewWithT(t)

type test struct {
amp *AzureMachinePool
}

existingPublicKey := "testpublickey"
publicKeyExistTest := test{amp: createMachinePoolWithSSHPublicKey(t, existingPublicKey)}
publicKeyNotExistTest := test{amp: createMachinePoolWithSSHPublicKey(t, "")}

err := publicKeyExistTest.amp.SetDefaultSSHPublicKey()
g.Expect(err).To(BeNil())
g.Expect(publicKeyExistTest.amp.Spec.Template.SSHPublicKey).To(Equal(existingPublicKey))

err = publicKeyNotExistTest.amp.SetDefaultSSHPublicKey()
g.Expect(err).To(BeNil())
g.Expect(publicKeyNotExistTest.amp.Spec.Template.SSHPublicKey).NotTo(BeEmpty())
}

func createMachinePoolWithSSHPublicKey(t *testing.T, sshPublicKey string) *AzureMachinePool {
return hardcodedAzureMachinePoolWithSSHKey(sshPublicKey)
}

func hardcodedAzureMachinePoolWithSSHKey(sshPublicKey string) *AzureMachinePool {
return &AzureMachinePool{
Spec: AzureMachinePoolSpec{
Template: AzureMachineTemplate{
SSHPublicKey: sshPublicKey,
},
},
}
}
21 changes: 21 additions & 0 deletions exp/api/v1alpha3/azuremachinepool_webhook.go
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,11 @@ var _ webhook.Defaulter = &AzureMachinePool{}
// Default implements webhook.Defaulter so a webhook will be registered for the type
func (amp *AzureMachinePool) Default() {
azuremachinepoollog.Info("default", "name", amp.Name)

err := amp.SetDefaultSSHPublicKey()
if err != nil {
azuremachinepoollog.Error(err, "SetDefaultSshPublicKey failed")
}
}

// +kubebuilder:webhook:verbs=create;update,path=/validate-exp-cluster-x-k8s-io-x-k8s-io-v1alpha3-azuremachinepool,mutating=false,failurePolicy=fail,matchPolicy=Equivalent,groups=exp.cluster.x-k8s.io.x-k8s.io,resources=azuremachinepools,versions=v1alpha3,name=vazuremachinepool.kb.io,sideEffects=None
Expand Down Expand Up @@ -74,6 +79,7 @@ func (amp *AzureMachinePool) Validate() error {
validators := []func() error{
amp.ValidateImage,
amp.ValidateTerminateNotificationTimeout,
amp.ValidateSSHKey,
}

var errs []error
Expand All @@ -100,6 +106,7 @@ func (amp *AzureMachinePool) ValidateImage() error {
return agg
}
}

return nil
}

Expand All @@ -118,3 +125,17 @@ func (amp *AzureMachinePool) ValidateTerminateNotificationTimeout() error {

return nil
}

// ValidateSSHKey validates an SSHKey
func (amp *AzureMachinePool) ValidateSSHKey() error {
if amp.Spec.Template.SSHPublicKey != "" {
sshKey := amp.Spec.Template.SSHPublicKey
if errs := infrav1.ValidateSSHKey(sshKey, field.NewPath("sshKey")); len(errs) > 0 {
agg := kerrors.NewAggregate(errs.ToAggregate().Errors())
azuremachinepoollog.Info("Invalid sshKey: %s", agg.Error())
return agg
}
}

return nil
}
Loading

0 comments on commit 0c45468

Please sign in to comment.