From c1ae01308bba2c83946b140c3fe5d740ad671a8f Mon Sep 17 00:00:00 2001 From: Abhinav Dahiya Date: Mon, 25 Mar 2019 15:55:46 -0700 Subject: [PATCH] machines: add the authorized keys for a pool using a machine config `cluster-config-v1` is being deprecated in favor of global configs [1] and Machine Config Operator needs to drop using the `SSHKey` in install-config [2] to setup the `SSHAuthorizedKeys` for `core` user. This pushes a machineconfig with the `SSHAuthorizedKeys` sourced from [2] for each machinepool, so that Machine Config Operator can drop generating the machineconfig using the `cluster-config-v1` config map in the cluster. [1]: https://github.com/openshift/installer/issues/680 [2]: https://godoc.org/github.com/openshift/installer/pkg/types#InstallConfig --- .../machines/machineconfig/authorizedkeys.go | 37 ++++++ pkg/asset/machines/master.go | 3 + pkg/asset/machines/master_test.go | 111 +++++++++++++++++ pkg/asset/machines/worker.go | 3 + pkg/asset/machines/worker_test.go | 113 ++++++++++++++++++ 5 files changed, 267 insertions(+) create mode 100644 pkg/asset/machines/machineconfig/authorizedkeys.go create mode 100644 pkg/asset/machines/master_test.go create mode 100644 pkg/asset/machines/worker_test.go diff --git a/pkg/asset/machines/machineconfig/authorizedkeys.go b/pkg/asset/machines/machineconfig/authorizedkeys.go new file mode 100644 index 00000000000..973641839cb --- /dev/null +++ b/pkg/asset/machines/machineconfig/authorizedkeys.go @@ -0,0 +1,37 @@ +package machineconfig + +import ( + "fmt" + + ignv2_2types "github.com/coreos/ignition/config/v2_2/types" + mcfgv1 "github.com/openshift/machine-config-operator/pkg/apis/machineconfiguration.openshift.io/v1" + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" +) + +// ForAuthorizedKeys creates the MachineConfig to set the authorized key for `core` user. +func ForAuthorizedKeys(key string, role string) *mcfgv1.MachineConfig { + return &mcfgv1.MachineConfig{ + TypeMeta: metav1.TypeMeta{ + APIVersion: mcfgv1.SchemeGroupVersion.String(), + Kind: "MachineConfig", + }, + ObjectMeta: metav1.ObjectMeta{ + Name: fmt.Sprintf("99-%s-ssh", role), + Labels: map[string]string{ + "machineconfiguration.openshift.io/role": role, + }, + }, + Spec: mcfgv1.MachineConfigSpec{ + Config: ignv2_2types.Config{ + Ignition: ignv2_2types.Ignition{ + Version: ignv2_2types.MaxVersion.String(), + }, + Passwd: ignv2_2types.Passwd{ + Users: []ignv2_2types.PasswdUser{{ + Name: "core", SSHAuthorizedKeys: []ignv2_2types.SSHAuthorizedKey{ignv2_2types.SSHAuthorizedKey(key)}, + }}, + }, + }, + }, + } +} diff --git a/pkg/asset/machines/master.go b/pkg/asset/machines/master.go index 0cf2dda554a..f3f35644f42 100644 --- a/pkg/asset/machines/master.go +++ b/pkg/asset/machines/master.go @@ -150,6 +150,9 @@ func (m *Master) Generate(dependencies asset.Parents) error { } machineConfigs := []*mcfgv1.MachineConfig{} + if ic.SSHKey != "" { + machineConfigs = append(machineConfigs, machineconfig.ForAuthorizedKeys(ic.SSHKey, "master")) + } m.MachineConfigFiles, err = machineconfig.Manifests(machineConfigs, "master", directory) if err != nil { return errors.Wrap(err, "failed to create MachineConfig manifests for master machines") diff --git a/pkg/asset/machines/master_test.go b/pkg/asset/machines/master_test.go new file mode 100644 index 00000000000..99232f98fb2 --- /dev/null +++ b/pkg/asset/machines/master_test.go @@ -0,0 +1,111 @@ +package machines + +import ( + "testing" + + "github.com/stretchr/testify/assert" + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + "k8s.io/utils/pointer" + + "github.com/openshift/installer/pkg/asset" + "github.com/openshift/installer/pkg/asset/ignition/machine" + "github.com/openshift/installer/pkg/asset/installconfig" + "github.com/openshift/installer/pkg/asset/rhcos" + "github.com/openshift/installer/pkg/types" + awstypes "github.com/openshift/installer/pkg/types/aws" +) + +func TestMasterGenerateMachineConfigs(t *testing.T) { + cases := []struct { + name string + key string + expectedMachineConfig string + }{ + { + name: "no key", + }, + { + name: "key present", + key: "ssh-rsa: dummy-key", + expectedMachineConfig: `--- +apiVersion: machineconfiguration.openshift.io/v1 +kind: MachineConfig +metadata: + creationTimestamp: null + labels: + machineconfiguration.openshift.io/role: master + name: 99-master-ssh +spec: + config: + ignition: + config: {} + security: + tls: {} + timeouts: {} + version: 2.2.0 + networkd: {} + passwd: + users: + - name: core + sshAuthorizedKeys: + - 'ssh-rsa: dummy-key' + storage: {} + systemd: {} + osImageURL: "" +`, + }, + } + for _, tc := range cases { + t.Run(tc.name, func(t *testing.T) { + parents := asset.Parents{} + parents.Add( + &installconfig.ClusterID{ + UUID: "test-uuid", + InfraID: "test-infra-id", + }, + &installconfig.InstallConfig{ + Config: &types.InstallConfig{ + ObjectMeta: metav1.ObjectMeta{ + Name: "test-cluster", + }, + SSHKey: tc.key, + BaseDomain: "test-domain", + Platform: types.Platform{ + AWS: &awstypes.Platform{ + Region: "us-east-1", + }, + }, + ControlPlane: &types.MachinePool{ + Replicas: pointer.Int64Ptr(1), + Platform: types.MachinePoolPlatform{ + AWS: &awstypes.MachinePool{ + Zones: []string{"us-east-1a"}, + }, + }, + }, + }, + }, + (*rhcos.Image)(pointer.StringPtr("test-image")), + &machine.Master{ + File: &asset.File{ + Filename: "master-ignition", + Data: []byte("test-ignition"), + }, + }, + ) + master := &Master{} + if err := master.Generate(parents); err != nil { + t.Fatalf("failed to generate master machines: %v", err) + } + if tc.expectedMachineConfig != "" { + if assert.Equal(t, 1, len(master.MachineConfigFiles), "expected one machine config file") { + file := master.MachineConfigFiles[0] + assert.Equal(t, "openshift/99_openshift-machineconfig_master.yaml", file.Filename, "unexpected machine config filename") + assert.Equal(t, tc.expectedMachineConfig, string(file.Data), "unexepcted machine config contents") + } + } else { + assert.Equal(t, 0, len(master.MachineConfigFiles), "expected no machine config files") + } + }) + } +} diff --git a/pkg/asset/machines/worker.go b/pkg/asset/machines/worker.go index 1266624baf8..2e83fb17bd6 100644 --- a/pkg/asset/machines/worker.go +++ b/pkg/asset/machines/worker.go @@ -159,6 +159,9 @@ func (w *Worker) Generate(dependencies asset.Parents) error { default: return fmt.Errorf("invalid Platform") } + if ic.SSHKey != "" { + machineConfigs = append(machineConfigs, machineconfig.ForAuthorizedKeys(ic.SSHKey, "worker")) + } } w.MachineConfigFiles, err = machineconfig.Manifests(machineConfigs, "worker", directory) diff --git a/pkg/asset/machines/worker_test.go b/pkg/asset/machines/worker_test.go new file mode 100644 index 00000000000..17e03f30e09 --- /dev/null +++ b/pkg/asset/machines/worker_test.go @@ -0,0 +1,113 @@ +package machines + +import ( + "testing" + + "github.com/stretchr/testify/assert" + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + "k8s.io/utils/pointer" + + "github.com/openshift/installer/pkg/asset" + "github.com/openshift/installer/pkg/asset/ignition/machine" + "github.com/openshift/installer/pkg/asset/installconfig" + "github.com/openshift/installer/pkg/asset/rhcos" + "github.com/openshift/installer/pkg/types" + awstypes "github.com/openshift/installer/pkg/types/aws" +) + +func TestWorkerGenerate(t *testing.T) { + cases := []struct { + name string + key string + expectedMachineConfig string + }{ + { + name: "no key", + }, + { + name: "key present", + key: "ssh-rsa: dummy-key", + expectedMachineConfig: `--- +apiVersion: machineconfiguration.openshift.io/v1 +kind: MachineConfig +metadata: + creationTimestamp: null + labels: + machineconfiguration.openshift.io/role: worker + name: 99-worker-ssh +spec: + config: + ignition: + config: {} + security: + tls: {} + timeouts: {} + version: 2.2.0 + networkd: {} + passwd: + users: + - name: core + sshAuthorizedKeys: + - 'ssh-rsa: dummy-key' + storage: {} + systemd: {} + osImageURL: "" +`, + }, + } + for _, tc := range cases { + t.Run(tc.name, func(t *testing.T) { + parents := asset.Parents{} + parents.Add( + &installconfig.ClusterID{ + UUID: "test-uuid", + InfraID: "test-infra-id", + }, + &installconfig.InstallConfig{ + Config: &types.InstallConfig{ + ObjectMeta: metav1.ObjectMeta{ + Name: "test-cluster", + }, + SSHKey: tc.key, + BaseDomain: "test-domain", + Platform: types.Platform{ + AWS: &awstypes.Platform{ + Region: "us-east-1", + }, + }, + Compute: []types.MachinePool{ + { + Replicas: pointer.Int64Ptr(1), + Platform: types.MachinePoolPlatform{ + AWS: &awstypes.MachinePool{ + Zones: []string{"us-east-1a"}, + }, + }, + }, + }, + }, + }, + (*rhcos.Image)(pointer.StringPtr("test-image")), + &machine.Worker{ + File: &asset.File{ + Filename: "worker-ignition", + Data: []byte("test-ignition"), + }, + }, + ) + worker := &Worker{} + if err := worker.Generate(parents); err != nil { + t.Fatalf("failed to generate worker machines: %v", err) + } + if tc.expectedMachineConfig != "" { + if assert.Equal(t, 1, len(worker.MachineConfigFiles), "expected one machine config file") { + file := worker.MachineConfigFiles[0] + assert.Equal(t, "openshift/99_openshift-machineconfig_worker.yaml", file.Filename, "unexpected machine config filename") + assert.Equal(t, tc.expectedMachineConfig, string(file.Data), "unexepcted machine config contents") + } + } else { + assert.Equal(t, 0, len(worker.MachineConfigFiles), "expected no machine config files") + } + }) + } +}