diff --git a/.nancy-ignore b/.nancy-ignore index 9bf4f52d..2f11f309 100644 --- a/.nancy-ignore +++ b/.nancy-ignore @@ -1,2 +1,3 @@ #pkg:golang/k8s.io/apiserver@v0.25.0 CVE-2020-8561 until=2024-01-08 # k8s.io/apiserver@v0.25.0 +CVE-2023-47108 until=2024-01-08 # go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc@v0.42.0 diff --git a/helm/teleport-operator/templates/configmap.yaml b/helm/teleport-operator/templates/configmap.yaml index 250f9217..0543bb6b 100644 --- a/helm/teleport-operator/templates/configmap.yaml +++ b/helm/teleport-operator/templates/configmap.yaml @@ -1,27 +1,15 @@ apiVersion: v1 kind: ConfigMap metadata: - name: tbot-config - namespace: {{ include "resource.default.namespace" . }} + name: {{ include "resource.default.name" . }} + namespace: {{ include "resource.default.namespace" . }} labels: - {{- include "labels.common" . | nindent 4 }} + {{- include "labels.common" . | nindent 4 }} +type: Opaque data: - tbot.yaml: | - version: v2 - onboarding: - join_method: kubernetes - # ensure token is set to the name of the join token you created earlier - token: {{ .Values.teleport.managementClusterName }} - storage: - # a memory destination is used for the bots own state since the kubernetes - # join method does not require persistence. - type: memory - # ensure this is configured to the address of your Teleport Proxy or - # Auth Server. Prefer the address of the Teleport Proxy. - auth_server: {{ .Values.teleport.proxyAddr }} - # outputs will be filled in during the completion of an access guide. - outputs: - - type: identity - destination: - type: kubernetes_secret - name: identity-output + appCatalog: {{ .Values.teleport.appCatalog | quote }} + appName: {{ .Values.teleport.appName | quote }} + appVersion: {{ .Values.teleport.appVersion | quote }} + managementClusterName: {{ .Values.teleport.managementClusterName | quote }} + proxyAddr: {{ .Values.teleport.proxyAddr | quote }} + teleportVersion: {{ .Values.teleport.teleportVersion | quote }} diff --git a/helm/teleport-operator/templates/secret.yaml b/helm/teleport-operator/templates/secret.yaml deleted file mode 100644 index 2281a297..00000000 --- a/helm/teleport-operator/templates/secret.yaml +++ /dev/null @@ -1,16 +0,0 @@ -apiVersion: v1 -kind: Secret -metadata: - name: {{ include "resource.default.name" . }} - namespace: {{ include "resource.default.namespace" . }} - labels: - {{- include "labels.common" . | nindent 4 }} -type: Opaque -data: - appCatalog: {{ .Values.teleport.appCatalog | b64enc | quote }} - appName: {{ .Values.teleport.appName | b64enc | quote }} - appVersion: {{ .Values.teleport.appVersion | b64enc | quote }} - identityFile: {{ .Values.teleport.identityFile | quote }} - managementClusterName: {{ .Values.teleport.managementClusterName | b64enc | quote }} - proxyAddr: {{ .Values.teleport.proxyAddr | b64enc | quote }} - teleportVersion: {{ .Values.teleport.teleportVersion | b64enc | quote }} diff --git a/helm/teleport-operator/templates/tbot-configmap.yaml b/helm/teleport-operator/templates/tbot-configmap.yaml new file mode 100644 index 00000000..bd7bc2ba --- /dev/null +++ b/helm/teleport-operator/templates/tbot-configmap.yaml @@ -0,0 +1,27 @@ +apiVersion: v1 +kind: ConfigMap +metadata: + name: tbot-config + namespace: {{ include "resource.default.namespace" . }} + labels: + {{- include "labels.common" . | nindent 4 }} +data: + tbot.yaml: | + version: v2 + onboarding: + join_method: kubernetes + # ensure token is set to the name of the join token you created earlier + token: {{ .Values.teleport.managementClusterName }}-bot + storage: + # a memory destination is used for the bots own state since the kubernetes + # join method does not require persistence. + type: memory + # ensure this is configured to the address of your Teleport Proxy or + # Auth Server. Prefer the address of the Teleport Proxy. + auth_server: {{ .Values.teleport.proxyAddr }} + # outputs will be filled in during the completion of an access guide. + outputs: + - type: identity + destination: + type: kubernetes_secret + name: identity-output diff --git a/internal/controller/cluster_controller.go b/internal/controller/cluster_controller.go index e58c46b4..dea34550 100644 --- a/internal/controller/cluster_controller.go +++ b/internal/controller/cluster_controller.go @@ -18,8 +18,6 @@ package controller import ( "context" - "crypto/sha512" - "encoding/hex" "time" "github.com/giantswarm/microerror" @@ -29,6 +27,7 @@ import ( capi "sigs.k8s.io/cluster-api/api/v1beta1" ctrl "sigs.k8s.io/controller-runtime" + "github.com/giantswarm/teleport-operator/internal/pkg/config" "github.com/giantswarm/teleport-operator/internal/pkg/key" "github.com/giantswarm/teleport-operator/internal/pkg/teleport" @@ -36,6 +35,8 @@ import ( "sigs.k8s.io/controller-runtime/pkg/controller/controllerutil" ) +const identityExpirationPeriod = 20 * time.Minute + // ClusterReconciler reconciles a Cluster object type ClusterReconciler struct { Client client.Client @@ -71,35 +72,32 @@ func (r *ClusterReconciler) Reconcile(ctx context.Context, req ctrl.Request) (ct } log.Info("Reconciling cluster", "cluster", cluster) - now := time.Now() - diff := now.Sub(r.Teleport.SecretConfig.LastRead) - seconds := diff.Seconds() - minutes := seconds / 60 - hasher := sha512.New() - hasher.Write([]byte(r.Teleport.SecretConfig.IdentityFile)) - sum := hasher.Sum(nil) - hashString := hex.EncodeToString(sum) - - log.Info("Teleport identity", "last-read-minutes-ago", minutes, "hash", hashString) + if r.Teleport.Identity != nil { + log.Info("Teleport identity", "last-read-minutes-ago", r.Teleport.Identity.Age(), "hash", r.Teleport.Identity.Hash()) + } - if time.Since(r.Teleport.SecretConfig.LastRead) > 20*time.Minute { + if r.Teleport.Identity == nil || time.Since(r.Teleport.Identity.LastRead) > identityExpirationPeriod { log.Info("Retrieving new identity", "secretName", key.TeleportBotSecretName) - newSecretConfig, err := teleport.GetConfigFromSecret(ctx, r.Client, r.Namespace) + newIdentityConfig, err := config.GetIdentityConfigFromSecret(ctx, r.Client, r.Namespace) if err != nil { return ctrl.Result{}, microerror.Mask(err) } - r.Teleport.SecretConfig = newSecretConfig - if r.Teleport.TeleportClient, err = teleport.NewClient(ctx, newSecretConfig.ProxyAddr, newSecretConfig.IdentityFile); err != nil { + if r.Teleport.TeleportClient, err = teleport.NewClient(ctx, r.Teleport.Config.ProxyAddr, newIdentityConfig.IdentityFile); err != nil { return ctrl.Result{}, microerror.Mask(err) } - log.Info("Re-connected to teleport cluster with new identity", "proxyAddr", newSecretConfig.ProxyAddr) + if r.Teleport.Identity == nil { + log.Info("Connected to teleport cluster", "proxyAddr", r.Teleport.Config.ProxyAddr) + } else { + log.Info("Re-connected to teleport cluster with new identity", "proxyAddr", r.Teleport.Config.ProxyAddr) + } + r.Teleport.Identity = newIdentityConfig } registerName := cluster.Name - if cluster.Name != r.Teleport.SecretConfig.ManagementClusterName { - registerName = key.GetRegisterName(r.Teleport.SecretConfig.ManagementClusterName, cluster.Name) + if cluster.Name != r.Teleport.Config.ManagementClusterName { + registerName = key.GetRegisterName(r.Teleport.Config.ManagementClusterName, cluster.Name) } // Check if the cluster instance is marked to be deleted, which is indicated by the deletion timestamp being set. diff --git a/internal/controller/cluster_controller_test.go b/internal/controller/cluster_controller_test.go index 0a954f1b..82eb5f5f 100644 --- a/internal/controller/cluster_controller_test.go +++ b/internal/controller/cluster_controller_test.go @@ -2,6 +2,7 @@ package controller import ( "context" + "errors" "testing" "time" @@ -15,6 +16,7 @@ import ( ctrl "sigs.k8s.io/controller-runtime" "sigs.k8s.io/controller-runtime/pkg/client" + "github.com/giantswarm/teleport-operator/internal/pkg/config" "github.com/giantswarm/teleport-operator/internal/pkg/key" "github.com/giantswarm/teleport-operator/internal/pkg/teleport" "github.com/giantswarm/teleport-operator/internal/pkg/test" @@ -26,19 +28,24 @@ func Test_ClusterController(t *testing.T) { namespace string token string tokens []teleportTypes.ProvisionToken - secretConfig *teleport.SecretConfig + config *config.Config + identity *config.IdentityConfig + identitySecret *corev1.Secret cluster *capi.Cluster secret *corev1.Secret configMap *corev1.ConfigMap + newTeleportClient func(ctx context.Context, proxyAddr, identityFile string) (teleport.Client, error) expectedCluster *capi.Cluster expectedSecret *corev1.Secret expectedConfigMap *corev1.ConfigMap + expectedError error }{ { name: "case 0: Register cluster and create Secret, ConfigMap and App resources in case they do not exist", namespace: test.NamespaceName, token: test.TokenName, - secretConfig: newSecretConfig(), + config: newConfig(), + identity: newIdentity(test.LastReadValue), cluster: test.NewCluster(test.ClusterName, test.NamespaceName, []string{key.TeleportOperatorFinalizer}, time.Time{}), expectedCluster: test.NewCluster(test.ClusterName, test.NamespaceName, []string{key.TeleportOperatorFinalizer}, time.Time{}), expectedSecret: test.NewSecret(test.ClusterName, test.NamespaceName, test.TokenName), @@ -48,7 +55,8 @@ func Test_ClusterController(t *testing.T) { name: "case 1: Register cluster and update Secret, ConfigMap and App resources in case they exist", namespace: test.NamespaceName, token: test.TokenName, - secretConfig: newSecretConfig(), + config: newConfig(), + identity: newIdentity(test.LastReadValue), cluster: test.NewCluster(test.ClusterName, test.NamespaceName, []string{key.TeleportOperatorFinalizer}, time.Time{}), secret: test.NewSecret(test.ClusterName, test.NamespaceName, test.TokenName), configMap: test.NewConfigMap(test.ClusterName, test.AppName, test.NamespaceName, test.TokenName), @@ -60,7 +68,8 @@ func Test_ClusterController(t *testing.T) { name: "case 2: Update Secret and ConfigMap resources in case join token changes", namespace: test.NamespaceName, token: test.NewTokenName, - secretConfig: newSecretConfig(), + config: newConfig(), + identity: newIdentity(test.LastReadValue), cluster: test.NewCluster(test.ClusterName, test.NamespaceName, []string{key.TeleportOperatorFinalizer}, time.Time{}), secret: test.NewSecret(test.ClusterName, test.NamespaceName, test.TokenName), configMap: test.NewConfigMap(test.ClusterName, test.AppName, test.NamespaceName, test.TokenName), @@ -69,13 +78,45 @@ func Test_ClusterController(t *testing.T) { expectedConfigMap: test.NewConfigMap(test.ClusterName, test.AppName, test.NamespaceName, test.NewTokenName), }, { - name: "case 3: Deregister cluster and delete resources in case the cluster is deleted", - namespace: test.NamespaceName, - token: test.TokenName, - secretConfig: newSecretConfig(), - cluster: test.NewCluster(test.ClusterName, test.NamespaceName, []string{key.TeleportOperatorFinalizer}, time.Now()), - secret: test.NewSecret(test.ClusterName, test.NamespaceName, test.TokenName), - configMap: test.NewConfigMap(test.ClusterName, test.AppName, test.NamespaceName, test.TokenName), + name: "case 3: Deregister cluster and delete resources in case the cluster is deleted", + namespace: test.NamespaceName, + token: test.TokenName, + config: newConfig(), + identity: newIdentity(test.LastReadValue), + cluster: test.NewCluster(test.ClusterName, test.NamespaceName, []string{key.TeleportOperatorFinalizer}, time.Now()), + secret: test.NewSecret(test.ClusterName, test.NamespaceName, test.TokenName), + configMap: test.NewConfigMap(test.ClusterName, test.AppName, test.NamespaceName, test.TokenName), + }, + { + name: "case 4: Reconnect to Teleport when credentials are rotated", + namespace: test.NamespaceName, + token: test.NewTokenName, + config: newConfig(), + identity: newIdentity(time.Now().Add(-identityExpirationPeriod - time.Second)), + cluster: test.NewCluster(test.ClusterName, test.NamespaceName, []string{key.TeleportOperatorFinalizer}, time.Time{}), + secret: test.NewSecret(test.ClusterName, test.NamespaceName, test.TokenName), + identitySecret: test.NewIdentitySecret(test.NamespaceName, test.IdentityFileValue), + configMap: test.NewConfigMap(test.ClusterName, test.AppName, test.NamespaceName, test.TokenName), + newTeleportClient: func(ctx context.Context, proxyAddr, identityFile string) (teleport.Client, error) { + return test.NewTeleportClient(test.FakeTeleportClientConfig{Tokens: nil}), nil + }, + expectedCluster: test.NewCluster(test.ClusterName, test.NamespaceName, []string{key.TeleportOperatorFinalizer}, time.Time{}), + expectedSecret: test.NewSecret(test.ClusterName, test.NamespaceName, test.NewTokenName), + expectedConfigMap: test.NewConfigMap(test.ClusterName, test.AppName, test.NamespaceName, test.NewTokenName), + }, + { + name: "case 5: Return an error in case reconnection to Teleport fails after the credentials are rotated", + namespace: test.NamespaceName, + token: test.TokenName, + config: newConfig(), + identity: newIdentity(time.Now().Add(-identityExpirationPeriod - time.Second)), + cluster: test.NewCluster(test.ClusterName, test.NamespaceName, []string{key.TeleportOperatorFinalizer}, time.Time{}), + secret: test.NewSecret(test.ClusterName, test.NamespaceName, test.TokenName), + configMap: test.NewConfigMap(test.ClusterName, test.AppName, test.NamespaceName, test.TokenName), + newTeleportClient: func(ctx context.Context, proxyAddr, identityFile string) (teleport.Client, error) { + return nil, errors.New("simulated error") + }, + expectedError: errors.New("secrets \"identity-output\" not found"), }, } @@ -91,6 +132,17 @@ func Test_ClusterController(t *testing.T) { if tc.configMap != nil { runtimeObjects = append(runtimeObjects, tc.configMap) } + if tc.identitySecret != nil { + runtimeObjects = append(runtimeObjects, tc.identitySecret) + } + + newTeleportClient := teleport.NewClient + if tc.newTeleportClient != nil { + teleport.NewClient = tc.newTeleportClient + } + defer func() { + teleport.NewClient = newTeleportClient + }() ctrlClient, err := test.NewFakeK8sClient(runtimeObjects) if err != nil { @@ -105,11 +157,12 @@ func Test_ClusterController(t *testing.T) { Log: log, Scheme: scheme.Scheme, Namespace: tc.namespace, - Teleport: teleport.New(tc.namespace, tc.secretConfig, test.NewMockTokenGenerator(tc.token)), + Teleport: teleport.New(tc.namespace, tc.config, test.NewMockTokenGenerator(tc.token)), } controller.Teleport.TeleportClient = test.NewTeleportClient(test.FakeTeleportClientConfig{ Tokens: tc.tokens, }) + controller.Teleport.Identity = tc.identity req := ctrl.Request{ NamespacedName: types.NamespacedName{ @@ -120,7 +173,14 @@ func Test_ClusterController(t *testing.T) { _, err = controller.Reconcile(ctx, req) if err != nil { + if tc.expectedError != nil && err.Error() != tc.expectedError.Error() { + t.Fatalf("unexpected error: expected %v, actual %v", tc.expectedError, err) + } else if tc.expectedError != nil { + return + } t.Fatalf("unexpected error %v", err) + } else if tc.expectedError != nil { + t.Fatalf("did not receive an expected error %v", tc.expectedError) } clusterList := &capi.ClusterList{} @@ -142,12 +202,17 @@ func Test_ClusterController(t *testing.T) { if err != nil { t.Fatalf("unexpected error %v", err) } + expectedSecretListLength := 1 + if tc.identitySecret != nil { + expectedSecretListLength = 2 + } if tc.expectedSecret != nil { - if len(secretList.Items) == 0 { + if len(secretList.Items) < expectedSecretListLength { t.Fatalf("unexpected result: secret list is empty\n%v", secretList) } - test.CheckSecret(t, tc.expectedSecret, &secretList.Items[0]) - } else if len(secretList.Items) > 0 { + actualSecret := findSecretInList(secretList, tc.expectedSecret.Name) + test.CheckSecret(t, tc.expectedSecret, actualSecret) + } else if len(secretList.Items) > expectedSecretListLength-1 { t.Fatalf("unexpected result: secret list is not empty\n%v", secretList) } @@ -158,11 +223,11 @@ func Test_ClusterController(t *testing.T) { } if tc.expectedConfigMap != nil { if len(configMapList.Items) == 0 { - t.Fatalf("unexpected result: secret list is empty\n%v", secretList) + t.Fatalf("unexpected result: config map list is empty\n%v", configMapList) } test.CheckConfigMap(t, tc.expectedConfigMap, &configMapList.Items[0]) } else if len(configMapList.Items) > 0 { - t.Fatalf("unexpected result: config map list is not empty\n%v", secretList) + t.Fatalf("unexpected result: config map list is not empty\n%v", configMapList) } appList := &appv1alpha1.AppList{} @@ -174,15 +239,29 @@ func Test_ClusterController(t *testing.T) { } } -func newSecretConfig() *teleport.SecretConfig { - return &teleport.SecretConfig{ +func newConfig() *config.Config { + return &config.Config{ AppCatalog: test.AppCatalog, AppName: test.AppName, AppVersion: test.AppVersion, - IdentityFile: test.IdentityFileValue, - LastRead: test.LastReadValue, ManagementClusterName: test.ManagementClusterName, ProxyAddr: test.ProxyAddr, TeleportVersion: test.TeleportVersion, } } + +func newIdentity(lastRead time.Time) *config.IdentityConfig { + return &config.IdentityConfig{ + IdentityFile: test.IdentityFileValue, + LastRead: lastRead, + } +} + +func findSecretInList(secretList *corev1.SecretList, name string) *corev1.Secret { + for _, secret := range secretList.Items { + if secret.Name == name { + return &secret + } + } + return nil +} diff --git a/internal/pkg/config/config.go b/internal/pkg/config/config.go new file mode 100644 index 00000000..4c05c6c3 --- /dev/null +++ b/internal/pkg/config/config.go @@ -0,0 +1,81 @@ +package config + +import ( + "context" + "fmt" + + "github.com/giantswarm/microerror" + corev1 "k8s.io/api/core/v1" + "k8s.io/apimachinery/pkg/types" + "sigs.k8s.io/controller-runtime/pkg/client" + + "github.com/giantswarm/teleport-operator/internal/pkg/key" +) + +type Config struct { + ProxyAddr string + TeleportVersion string + ManagementClusterName string + AppName string + AppVersion string + AppCatalog string +} + +func GetConfigFromConfigMap(ctx context.Context, ctrlClient client.Client, namespace string) (*Config, error) { + configMap := &corev1.ConfigMap{} + if err := ctrlClient.Get(ctx, types.NamespacedName{ + Name: key.TeleportOperatorConfigName, + Namespace: namespace, + }, configMap); err != nil { + return nil, microerror.Mask(err) + } + + proxyAddr, err := getConfigMapString(configMap, key.ProxyAddr) + if err != nil { + return nil, microerror.Mask(err) + } + + managementClusterName, err := getConfigMapString(configMap, key.ManagementClusterName) + if err != nil { + return nil, microerror.Mask(err) + } + + teleportVersion, err := getConfigMapString(configMap, key.TeleportVersion) + if err != nil { + return nil, microerror.Mask(err) + } + + appName, err := getConfigMapString(configMap, key.AppName) + if err != nil { + return nil, microerror.Mask(err) + } + + appVersion, err := getConfigMapString(configMap, key.AppVersion) + if err != nil { + return nil, microerror.Mask(err) + } + + appCatalog, err := getConfigMapString(configMap, key.AppCatalog) + if err != nil { + return nil, microerror.Mask(err) + } + + return &Config{ + ProxyAddr: proxyAddr, + TeleportVersion: teleportVersion, + ManagementClusterName: managementClusterName, + AppName: appName, + AppVersion: appVersion, + AppCatalog: appCatalog, + }, nil +} + +func getConfigMapString(configMap *corev1.ConfigMap, key string) (string, error) { + if s, ok := configMap.Data[key]; ok { + return s, nil + } + if b, ok := configMap.BinaryData[key]; ok { + return string(b), nil + } + return "", fmt.Errorf("malformed Config Map: required key %q not found", key) +} diff --git a/internal/pkg/config/config_test.go b/internal/pkg/config/config_test.go new file mode 100644 index 00000000..e54933a9 --- /dev/null +++ b/internal/pkg/config/config_test.go @@ -0,0 +1,109 @@ +package config + +import ( + "context" + "testing" + + corev1 "k8s.io/api/core/v1" + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + "k8s.io/apimachinery/pkg/runtime" + + "github.com/giantswarm/teleport-operator/internal/pkg/key" + "github.com/giantswarm/teleport-operator/internal/pkg/test" +) + +func Test_GetConfigFromSecret(t *testing.T) { + testCases := []struct { + name string + namespace string + configMap *corev1.ConfigMap + testSecret bool + testConfigMap bool + expectedConfig *Config + expectError bool + }{ + { + name: "case 0: Return config in case a valid config map exists", + namespace: test.NamespaceName, + configMap: &corev1.ConfigMap{ + ObjectMeta: metav1.ObjectMeta{ + Name: key.TeleportOperatorConfigName, + Namespace: test.NamespaceName, + }, + Data: map[string]string{ + key.AppCatalog: test.AppCatalog, + key.AppName: test.AppName, + key.AppVersion: test.AppVersion, + key.ManagementClusterName: test.ManagementClusterName, + key.ProxyAddr: test.ProxyAddr, + key.TeleportVersion: test.TeleportVersion, + }, + }, + testConfigMap: true, + expectedConfig: &Config{ + AppCatalog: test.AppCatalog, + AppName: test.AppName, + AppVersion: test.AppVersion, + ManagementClusterName: test.ManagementClusterName, + ProxyAddr: test.ProxyAddr, + TeleportVersion: test.TeleportVersion, + }, + }, + { + name: "case 1: Fail in case the config map does not exist", + namespace: test.NamespaceName, + testConfigMap: true, + expectError: true, + }, + { + name: "case 2: Fail in case the config map exists but does not contain all keys", + namespace: test.NamespaceName, + configMap: &corev1.ConfigMap{ + ObjectMeta: metav1.ObjectMeta{ + Name: key.TeleportOperatorConfigName, + Namespace: test.NamespaceName, + }, + Data: map[string]string{}, + }, + testConfigMap: true, + expectError: true, + }, + } + + for _, tc := range testCases { + t.Run(tc.name, func(t *testing.T) { + var runtimeObjects []runtime.Object + if tc.configMap != nil { + runtimeObjects = append(runtimeObjects, tc.configMap) + } + + ctrlClient, err := test.NewFakeK8sClient(runtimeObjects) + if err != nil { + t.Fatalf("unexpected error %v", err) + } + + ctx := context.TODO() + + var actualConfig *Config + actualConfig, err = GetConfigFromConfigMap(ctx, ctrlClient, tc.namespace) + test.CheckError(t, tc.expectError, err) + + if err == nil { + checkConfigs(t, tc.expectedConfig, actualConfig) + } + }) + } +} + +func checkConfigs(t *testing.T, expected *Config, actual *Config) { + configsMatch := expected.AppVersion == actual.AppVersion && + expected.AppName == actual.AppName && + expected.AppCatalog == actual.AppCatalog && + expected.ManagementClusterName == actual.ManagementClusterName && + expected.ProxyAddr == actual.ProxyAddr && + expected.TeleportVersion == actual.TeleportVersion + + if !configsMatch { + t.Fatalf("configs do not match: expected\n%v,\nactual\n%v", expected, actual) + } +} diff --git a/internal/pkg/config/identity.go b/internal/pkg/config/identity.go new file mode 100644 index 00000000..2dfe7963 --- /dev/null +++ b/internal/pkg/config/identity.go @@ -0,0 +1,62 @@ +package config + +import ( + "context" + "crypto/sha512" + "encoding/hex" + "fmt" + "time" + + "github.com/giantswarm/microerror" + corev1 "k8s.io/api/core/v1" + "k8s.io/apimachinery/pkg/types" + "sigs.k8s.io/controller-runtime/pkg/client" + + "github.com/giantswarm/teleport-operator/internal/pkg/key" +) + +type IdentityConfig struct { + IdentityFile string + LastRead time.Time +} + +func (c *IdentityConfig) Age() time.Duration { + now := time.Now() + diff := now.Sub(c.LastRead) + return diff +} + +func (c *IdentityConfig) Hash() string { + hasher := sha512.New() + hasher.Write([]byte(c.IdentityFile)) + sum := hasher.Sum(nil) + return hex.EncodeToString(sum) +} + +func GetIdentityConfigFromSecret(ctx context.Context, ctrlClient client.Client, namespace string) (*IdentityConfig, error) { + secret := &corev1.Secret{} + if err := ctrlClient.Get(ctx, types.NamespacedName{ + Name: key.TeleportBotSecretName, + Namespace: namespace, + }, secret); err != nil { + return nil, microerror.Mask(err) + } + + identityFile, err := getSecretString(secret, key.Identity) + if err != nil { + return nil, microerror.Mask(err) + } + + return &IdentityConfig{ + IdentityFile: identityFile, + LastRead: time.Now(), + }, nil +} + +func getSecretString(secret *corev1.Secret, key string) (string, error) { + b, ok := secret.Data[key] + if !ok { + return "", fmt.Errorf("malformed Secret: required key %q not found", key) + } + return string(b), nil +} diff --git a/internal/pkg/config/identity_test.go b/internal/pkg/config/identity_test.go new file mode 100644 index 00000000..51b29871 --- /dev/null +++ b/internal/pkg/config/identity_test.go @@ -0,0 +1,79 @@ +package config + +import ( + "context" + "testing" + + corev1 "k8s.io/api/core/v1" + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + "k8s.io/apimachinery/pkg/runtime" + + "github.com/giantswarm/teleport-operator/internal/pkg/key" + "github.com/giantswarm/teleport-operator/internal/pkg/test" +) + +func Test_GetIdentityConfigFromSecret(t *testing.T) { + testCases := []struct { + name string + namespace string + secret *corev1.Secret + expectedConfig *IdentityConfig + expectError bool + }{ + { + name: "case 0: Return identity config in case a valid secret exists", + namespace: test.NamespaceName, + secret: &corev1.Secret{ + ObjectMeta: metav1.ObjectMeta{ + Name: "identity-output", + Namespace: test.NamespaceName, + }, + Data: map[string][]byte{ + "identity": []byte(test.IdentityFileValue), + }, + }, + expectedConfig: &IdentityConfig{ + IdentityFile: test.IdentityFileValue, + }, + }, + { + name: "case 1: Fail in case the identity config secret does not exist", + namespace: test.NamespaceName, + expectError: true, + }, + { + name: "case 2: Fail in case the identity config secret exists but does not contain all keys", + namespace: test.NamespaceName, + secret: &corev1.Secret{ + ObjectMeta: metav1.ObjectMeta{ + Name: key.TeleportBotSecretName, + Namespace: test.NamespaceName, + }, + Data: map[string][]byte{}, + }, + expectError: true, + }, + } + + for _, tc := range testCases { + t.Run(tc.name, func(t *testing.T) { + var runtimeObjects []runtime.Object + if tc.secret != nil { + runtimeObjects = append(runtimeObjects, tc.secret) + } + + ctrlClient, err := test.NewFakeK8sClient(runtimeObjects) + if err != nil { + t.Fatalf("unexpected error %v", err) + } + + ctx := context.TODO() + actualConfig, err := GetIdentityConfigFromSecret(ctx, ctrlClient, tc.namespace) + test.CheckError(t, tc.expectError, err) + + if err == nil && tc.expectedConfig.IdentityFile != actualConfig.IdentityFile { + t.Fatalf("configs do not match: expected\n%v,\nactual\n%v", tc.expectedConfig, actualConfig) + } + }) + } +} diff --git a/internal/pkg/key/key.go b/internal/pkg/key/key.go index f233058d..bfdd83b7 100644 --- a/internal/pkg/key/key.go +++ b/internal/pkg/key/key.go @@ -11,7 +11,7 @@ const ( TeleportKubeAppDefaultNamespace = "giantswarm" TeleportKubeAppNamespace = "kube-system" TeleportOperatorLabelValue = "teleport-operator" - TeleportOperatorSecretName = "teleport-operator" + TeleportOperatorConfigName = "teleport-operator" TeleportBotSecretName = "identity-output" TeleportKubeTokenValidity = 1 * time.Hour TeleportNodeTokenValidity = 24 * time.Hour diff --git a/internal/pkg/teleport/client.go b/internal/pkg/teleport/client.go index b9d8b71d..790fcb4d 100644 --- a/internal/pkg/teleport/client.go +++ b/internal/pkg/teleport/client.go @@ -19,7 +19,7 @@ type Client interface { DeleteToken(ctx context.Context, name string) error } -func NewClient(ctx context.Context, proxyAddr, identityFile string) (Client, error) { +var NewClient = func(ctx context.Context, proxyAddr, identityFile string) (Client, error) { teleportClient, err := tc.New(ctx, tc.Config{ Addrs: []string{ proxyAddr, diff --git a/internal/pkg/teleport/configmap.go b/internal/pkg/teleport/configmap.go index 33d13f80..79551c58 100644 --- a/internal/pkg/teleport/configmap.go +++ b/internal/pkg/teleport/configmap.go @@ -18,7 +18,7 @@ import ( func (t *Teleport) GetConfigMap(ctx context.Context, log logr.Logger, ctrlClient client.Client, clusterName string, clusterNamespace string) (*corev1.ConfigMap, error) { var ( - configMapName = key.GetConfigmapName(clusterName, t.SecretConfig.AppName) + configMapName = key.GetConfigmapName(clusterName, t.Config.AppName) configMap = &corev1.ConfigMap{} ) @@ -52,7 +52,7 @@ func (t *Teleport) GetTokenFromConfigMap(ctx context.Context, configMap *corev1. } func (t *Teleport) CreateConfigMap(ctx context.Context, log logr.Logger, ctrlClient client.Client, clusterName string, clusterNamespace string, registerName string, token string) error { - configMapName := key.GetConfigmapName(clusterName, t.SecretConfig.AppName) + configMapName := key.GetConfigmapName(clusterName, t.Config.AppName) configMapData := map[string]string{ "values": t.getConfigMapData(registerName, token), @@ -112,7 +112,7 @@ func (t *Teleport) UpdateConfigMap(ctx context.Context, log logr.Logger, ctrlCli } func (t *Teleport) DeleteConfigMap(ctx context.Context, log logr.Logger, ctrlClient client.Client, clusterName string, clusterNamespace string) error { - configMapName := key.GetConfigmapName(clusterName, t.SecretConfig.AppName) + configMapName := key.GetConfigmapName(clusterName, t.Config.AppName) cm := corev1.ConfigMap{ ObjectMeta: metav1.ObjectMeta{ Name: configMapName, @@ -134,9 +134,9 @@ func (t *Teleport) DeleteConfigMap(ctx context.Context, log logr.Logger, ctrlCli func (t *Teleport) getConfigMapData(registerName string, token string) string { var ( authToken = token - proxyAddr = t.SecretConfig.ProxyAddr + proxyAddr = t.Config.ProxyAddr kubeClusterName = registerName - teleportVersionOverride = t.SecretConfig.TeleportVersion + teleportVersionOverride = t.Config.TeleportVersion ) return key.GetConfigmapDataFromTemplate(authToken, proxyAddr, kubeClusterName, teleportVersionOverride) diff --git a/internal/pkg/teleport/configmap_test.go b/internal/pkg/teleport/configmap_test.go index 7a0d5fe9..97162c9e 100644 --- a/internal/pkg/teleport/configmap_test.go +++ b/internal/pkg/teleport/configmap_test.go @@ -11,6 +11,7 @@ import ( ctrl "sigs.k8s.io/controller-runtime" "sigs.k8s.io/controller-runtime/pkg/client" + "github.com/giantswarm/teleport-operator/internal/pkg/config" "github.com/giantswarm/teleport-operator/internal/pkg/key" "github.com/giantswarm/teleport-operator/internal/pkg/test" "github.com/giantswarm/teleport-operator/internal/pkg/token" @@ -30,7 +31,7 @@ func Test_ConfigMapCRUD(t *testing.T) { configMapToDelete *corev1.ConfigMap expectError bool expectEmpty bool - secretConfig *SecretConfig + config *config.Config }{ { name: "case 0: Create a configmap if it does not exist", @@ -38,7 +39,7 @@ func Test_ConfigMapCRUD(t *testing.T) { clusterName: test.ClusterName, registerName: key.GetRegisterName(test.ManagementClusterName, test.ClusterName), configMapToCreate: test.NewConfigMap(test.ClusterName, test.AppName, test.NamespaceName, test.TokenName), - secretConfig: &SecretConfig{ + config: &config.Config{ AppName: test.AppName, ProxyAddr: test.ProxyAddr, TeleportVersion: test.TeleportVersion, @@ -52,7 +53,7 @@ func Test_ConfigMapCRUD(t *testing.T) { configMap: test.NewConfigMap(test.ClusterName, test.AppName, test.NamespaceName, test.TokenName), configMapToCreate: test.NewConfigMap(test.ClusterName, test.AppName, test.NamespaceName, test.TokenName), expectError: false, - secretConfig: &SecretConfig{ + config: &config.Config{ AppName: test.AppName, ProxyAddr: test.ProxyAddr, TeleportVersion: test.TeleportVersion, @@ -65,7 +66,7 @@ func Test_ConfigMapCRUD(t *testing.T) { registerName: key.GetRegisterName(test.ManagementClusterName, test.ClusterName), configMap: test.NewConfigMap(test.ClusterName, test.AppName, test.NamespaceName, test.TokenName), configMapToRead: test.NewConfigMap(test.ClusterName, test.AppName, test.NamespaceName, test.TokenName), - secretConfig: &SecretConfig{ + config: &config.Config{ AppName: test.AppName, ProxyAddr: test.ProxyAddr, TeleportVersion: test.TeleportVersion, @@ -78,7 +79,7 @@ func Test_ConfigMapCRUD(t *testing.T) { registerName: key.GetRegisterName(test.ManagementClusterName, test.ClusterName), configMapToRead: test.NewConfigMap(test.ClusterName, test.AppName, test.NamespaceName, test.TokenName), expectEmpty: true, - secretConfig: &SecretConfig{ + config: &config.Config{ AppName: test.AppName, ProxyAddr: test.ProxyAddr, TeleportVersion: test.TeleportVersion, @@ -92,7 +93,7 @@ func Test_ConfigMapCRUD(t *testing.T) { token: test.TokenName, configMap: test.NewConfigMap(test.ClusterName, test.AppName, test.NamespaceName, test.TokenName), configMapToRead: test.NewConfigMap(test.ClusterName, test.AppName, test.NamespaceName, test.TokenName), - secretConfig: &SecretConfig{ + config: &config.Config{ AppName: test.AppName, ProxyAddr: test.ProxyAddr, TeleportVersion: test.TeleportVersion, @@ -112,7 +113,7 @@ func Test_ConfigMapCRUD(t *testing.T) { }, configMapToRead: test.NewConfigMap(test.ClusterName, test.AppName, test.NamespaceName, test.TokenName), expectError: true, - secretConfig: &SecretConfig{ + config: &config.Config{ AppName: test.AppName, ProxyAddr: test.ProxyAddr, TeleportVersion: test.TeleportVersion, @@ -126,7 +127,7 @@ func Test_ConfigMapCRUD(t *testing.T) { token: test.NewTokenName, configMap: test.NewConfigMap(test.ClusterName, test.AppName, test.NamespaceName, test.TokenName), configMapToUpdate: test.NewConfigMap(test.ClusterName, test.AppName, test.NamespaceName, test.NewTokenName), - secretConfig: &SecretConfig{ + config: &config.Config{ AppName: test.AppName, ProxyAddr: test.ProxyAddr, TeleportVersion: test.TeleportVersion, @@ -140,7 +141,7 @@ func Test_ConfigMapCRUD(t *testing.T) { configMap: test.NewConfigMap(test.ClusterName, test.AppName, test.NamespaceName, test.TokenName), configMapToDelete: test.NewConfigMap(test.ClusterName, test.AppName, test.NamespaceName, test.TokenName), expectError: false, - secretConfig: &SecretConfig{ + config: &config.Config{ AppName: test.AppName, ProxyAddr: test.ProxyAddr, TeleportVersion: test.TeleportVersion, @@ -153,7 +154,7 @@ func Test_ConfigMapCRUD(t *testing.T) { registerName: key.GetRegisterName(test.ManagementClusterName, test.ClusterName), configMapToDelete: test.NewConfigMap(test.ClusterName, test.AppName, test.NamespaceName, test.TokenName), expectError: false, - secretConfig: &SecretConfig{ + config: &config.Config{ AppName: test.AppName, ProxyAddr: test.ProxyAddr, TeleportVersion: test.TeleportVersion, @@ -175,7 +176,7 @@ func Test_ConfigMapCRUD(t *testing.T) { t.Fatalf("unexpected error %v", err) } - teleport := New(tc.name, tc.secretConfig, token.NewGenerator()) + teleport := New(tc.name, tc.config, token.NewGenerator()) ctx := context.TODO() log := ctrl.Log.WithName("test") diff --git a/internal/pkg/teleport/secret.go b/internal/pkg/teleport/secret.go index baf09362..fe5d9094 100644 --- a/internal/pkg/teleport/secret.go +++ b/internal/pkg/teleport/secret.go @@ -3,7 +3,6 @@ package teleport import ( "context" "fmt" - "time" "github.com/giantswarm/microerror" "github.com/go-logr/logr" @@ -16,82 +15,6 @@ import ( "github.com/giantswarm/teleport-operator/internal/pkg/key" ) -type SecretConfig struct { - ProxyAddr string - LastRead time.Time - IdentityFile string - TeleportVersion string - ManagementClusterName string - AppName string - AppVersion string - AppCatalog string -} - -func GetConfigFromSecret(ctx context.Context, ctrlClient client.Client, namespace string) (*SecretConfig, error) { - secret := &corev1.Secret{} - tbotSecret := &corev1.Secret{} - - if err := ctrlClient.Get(ctx, types.NamespacedName{ - Name: key.TeleportOperatorSecretName, - Namespace: namespace, - }, secret); err != nil { - return nil, microerror.Mask(err) - } - - if err := ctrlClient.Get(ctx, types.NamespacedName{ - Name: key.TeleportBotSecretName, - Namespace: namespace, - }, tbotSecret); err != nil { - return nil, microerror.Mask(err) - } - - proxyAddr, err := getSecretString(secret, key.ProxyAddr) - if err != nil { - return nil, microerror.Mask(err) - } - - identityFile, err := getSecretString(tbotSecret, key.Identity) - if err != nil { - return nil, microerror.Mask(err) - } - - managementClusterName, err := getSecretString(secret, key.ManagementClusterName) - if err != nil { - return nil, microerror.Mask(err) - } - - teleportVersion, err := getSecretString(secret, key.TeleportVersion) - if err != nil { - return nil, microerror.Mask(err) - } - - appName, err := getSecretString(secret, key.AppName) - if err != nil { - return nil, microerror.Mask(err) - } - - appVersion, err := getSecretString(secret, key.AppVersion) - if err != nil { - return nil, microerror.Mask(err) - } - - appCatalog, err := getSecretString(secret, key.AppCatalog) - if err != nil { - return nil, microerror.Mask(err) - } - - return &SecretConfig{ - IdentityFile: identityFile, - LastRead: time.Now(), - ProxyAddr: proxyAddr, - ManagementClusterName: managementClusterName, - TeleportVersion: teleportVersion, - AppName: appName, - AppVersion: appVersion, - AppCatalog: appCatalog, - }, nil -} - func (t *Teleport) GetSecret(ctx context.Context, log logr.Logger, ctrlClient client.Client, clusterName string, clusterNamespace string) (*corev1.Secret, error) { var ( secretName = key.GetSecretName(clusterName) //#nosec G101 @@ -176,11 +99,3 @@ func (t *Teleport) DeleteSecret(ctx context.Context, log logr.Logger, ctrlClient log.Info("Deleted secret", "secretName", secretName) return nil } - -func getSecretString(secret *corev1.Secret, key string) (string, error) { - b, ok := secret.Data[key] - if !ok { - return "", fmt.Errorf("malformed Secret: required key %q not found", key) - } - return string(b), nil -} diff --git a/internal/pkg/teleport/secret_test.go b/internal/pkg/teleport/secret_test.go index cb8ded69..1f9e0bf8 100644 --- a/internal/pkg/teleport/secret_test.go +++ b/internal/pkg/teleport/secret_test.go @@ -11,112 +11,12 @@ import ( ctrl "sigs.k8s.io/controller-runtime" "sigs.k8s.io/controller-runtime/pkg/client" + "github.com/giantswarm/teleport-operator/internal/pkg/config" "github.com/giantswarm/teleport-operator/internal/pkg/key" "github.com/giantswarm/teleport-operator/internal/pkg/test" "github.com/giantswarm/teleport-operator/internal/pkg/token" ) -func Test_GetConfigFromSecret(t *testing.T) { - testCases := []struct { - name string - namespace string - secret *corev1.Secret - tbotSecret *corev1.Secret - expectedConfig *SecretConfig - expectError bool - }{ - { - name: "case 0: Return config in case a valid secret exists", - namespace: test.NamespaceName, - secret: &corev1.Secret{ - ObjectMeta: metav1.ObjectMeta{ - Name: key.TeleportOperatorSecretName, - Namespace: test.NamespaceName, - }, - Data: map[string][]byte{ - key.AppCatalog: []byte(test.AppCatalog), - key.AppName: []byte(test.AppName), - key.AppVersion: []byte(test.AppVersion), - key.IdentityFile: []byte(test.IdentityFileValue), - key.ManagementClusterName: []byte(test.ManagementClusterName), - key.ProxyAddr: []byte(test.ProxyAddr), - key.TeleportVersion: []byte(test.TeleportVersion), - }, - }, - tbotSecret: &corev1.Secret{ - ObjectMeta: metav1.ObjectMeta{ - Name: "identity-output", - Namespace: test.NamespaceName, - }, - Data: map[string][]byte{ - "identity": []byte(test.IdentityFileValue), - }, - }, - expectedConfig: &SecretConfig{ - AppCatalog: test.AppCatalog, - AppName: test.AppName, - AppVersion: test.AppVersion, - ManagementClusterName: test.ManagementClusterName, - IdentityFile: test.IdentityFileValue, - ProxyAddr: test.ProxyAddr, - TeleportVersion: test.TeleportVersion, - }, - }, - { - name: "case 1: Fail in case the config secret does not exist", - namespace: test.NamespaceName, - expectError: true, - }, - { - name: "case 2: Fail in case the config secret exists but does not contain all keys", - namespace: test.NamespaceName, - secret: &corev1.Secret{ - ObjectMeta: metav1.ObjectMeta{ - Name: key.TeleportOperatorSecretName, - Namespace: test.NamespaceName, - }, - Data: map[string][]byte{}, - }, - expectError: true, - }, - } - - for _, tc := range testCases { - t.Run(tc.name, func(t *testing.T) { - var runtimeObjects []runtime.Object - if tc.secret != nil { - runtimeObjects = append(runtimeObjects, tc.secret) - } - if tc.tbotSecret != nil { - runtimeObjects = append(runtimeObjects, tc.tbotSecret) - } - - ctrlClient, err := test.NewFakeK8sClient(runtimeObjects) - if err != nil { - t.Fatalf("unexpected error %v", err) - } - - ctx := context.TODO() - actualConfig, err := GetConfigFromSecret(ctx, ctrlClient, tc.namespace) - test.CheckError(t, tc.expectError, err) - - if err == nil { - configsMatch := tc.expectedConfig.AppVersion == actualConfig.AppVersion && - tc.expectedConfig.AppName == actualConfig.AppName && - tc.expectedConfig.AppCatalog == actualConfig.AppCatalog && - tc.expectedConfig.IdentityFile == actualConfig.IdentityFile && - tc.expectedConfig.ManagementClusterName == actualConfig.ManagementClusterName && - tc.expectedConfig.ProxyAddr == actualConfig.ProxyAddr && - tc.expectedConfig.TeleportVersion == actualConfig.TeleportVersion - - if !configsMatch { - t.Fatalf("configs do not match: expected\n%v,\nactual\n%v", tc.expectedConfig, actualConfig) - } - } - }) - } -} - func Test_SecretCRUD(t *testing.T) { testCases := []struct { name string @@ -228,7 +128,7 @@ func Test_SecretCRUD(t *testing.T) { t.Fatalf("unexpected error %v", err) } - teleport := New(tc.name, &SecretConfig{}, token.NewGenerator()) + teleport := New(tc.name, &config.Config{}, token.NewGenerator()) ctx := context.TODO() log := ctrl.Log.WithName("test") diff --git a/internal/pkg/teleport/teleport.go b/internal/pkg/teleport/teleport.go index 7a3a6a6a..af771af8 100644 --- a/internal/pkg/teleport/teleport.go +++ b/internal/pkg/teleport/teleport.go @@ -1,19 +1,21 @@ package teleport import ( + "github.com/giantswarm/teleport-operator/internal/pkg/config" "github.com/giantswarm/teleport-operator/internal/pkg/token" ) type Teleport struct { - SecretConfig *SecretConfig + Config *config.Config + Identity *config.IdentityConfig TeleportClient Client Namespace string TokenGenerator token.Generator } -func New(namespace string, secretConfig *SecretConfig, tokenGenerator token.Generator) *Teleport { +func New(namespace string, cfg *config.Config, tokenGenerator token.Generator) *Teleport { return &Teleport{ - SecretConfig: secretConfig, + Config: cfg, Namespace: namespace, TokenGenerator: tokenGenerator, } diff --git a/internal/pkg/teleport/token_test.go b/internal/pkg/teleport/token_test.go index 17713624..14260f49 100644 --- a/internal/pkg/teleport/token_test.go +++ b/internal/pkg/teleport/token_test.go @@ -7,6 +7,7 @@ import ( "github.com/gravitational/teleport/api/types" ctrl "sigs.k8s.io/controller-runtime" + "github.com/giantswarm/teleport-operator/internal/pkg/config" "github.com/giantswarm/teleport-operator/internal/pkg/key" "github.com/giantswarm/teleport-operator/internal/pkg/test" "github.com/giantswarm/teleport-operator/internal/pkg/token" @@ -47,7 +48,7 @@ func Test_GenerateToken(t *testing.T) { for _, tc := range testCases { t.Run(tc.name, func(t *testing.T) { - teleport := New(test.NamespaceName, &SecretConfig{}, test.NewMockTokenGenerator(test.TokenName)) + teleport := New(test.NamespaceName, &config.Config{}, test.NewMockTokenGenerator(test.TokenName)) teleport.TeleportClient = test.NewTeleportClient(test.FakeTeleportClientConfig{ FailsList: tc.failsList, FailsDelete: tc.failsDelete, @@ -118,7 +119,7 @@ func Test_IsTokenValid(t *testing.T) { for _, tc := range testCases { t.Run(tc.name, func(t *testing.T) { - teleport := New(test.NamespaceName, &SecretConfig{}, token.NewGenerator()) + teleport := New(test.NamespaceName, &config.Config{}, token.NewGenerator()) teleport.TeleportClient = test.NewTeleportClient(test.FakeTeleportClientConfig{ Tokens: tc.tokens, FailsList: tc.failsList, @@ -182,7 +183,7 @@ func Test_DeleteToken(t *testing.T) { ctx := context.TODO() log := ctrl.Log.WithName("test") - teleport := New(test.NamespaceName, &SecretConfig{}, token.NewGenerator()) + teleport := New(test.NamespaceName, &config.Config{}, token.NewGenerator()) teleport.TeleportClient = test.NewTeleportClient(test.FakeTeleportClientConfig{ FailsDelete: tc.failsDelete, Tokens: tc.tokens, diff --git a/internal/pkg/test/resources.go b/internal/pkg/test/resources.go index 0bda4f7e..cbdc593b 100644 --- a/internal/pkg/test/resources.go +++ b/internal/pkg/test/resources.go @@ -70,6 +70,16 @@ func NewSecret(clusterName, namespaceName, tokenName string) *corev1.Secret { } } +func NewIdentitySecret(namespaceName, identityFile string) *corev1.Secret { + return &corev1.Secret{ + ObjectMeta: metav1.ObjectMeta{ + Name: key.TeleportBotSecretName, + Namespace: namespaceName, + }, + Data: map[string][]byte{key.Identity: []byte(identityFile)}, + } +} + func NewConfigMap(clusterName, appName, namespaceName, tokenName string) *corev1.ConfigMap { registerName := key.GetRegisterName(ManagementClusterName, clusterName) return &corev1.ConfigMap{ diff --git a/main.go b/main.go index 159b05be..39a23b3f 100644 --- a/main.go +++ b/main.go @@ -39,6 +39,7 @@ import ( capi "sigs.k8s.io/cluster-api/api/v1beta1" "github.com/giantswarm/teleport-operator/internal/controller" + "github.com/giantswarm/teleport-operator/internal/pkg/config" "github.com/giantswarm/teleport-operator/internal/pkg/teleport" "github.com/giantswarm/teleport-operator/internal/pkg/token" //+kubebuilder:scaffold:imports @@ -110,19 +111,13 @@ func main() { } ctx := context.Background() - secretConfig, err := teleport.GetConfigFromSecret(ctx, ctrlClient, namespace) + config, err := config.GetConfigFromConfigMap(ctx, ctrlClient, namespace) if err != nil { setupLog.Error(err, "unable to get secret config") os.Exit(1) } - tele := teleport.New(namespace, secretConfig, token.NewGenerator()) - if tele.TeleportClient, err = teleport.NewClient(ctx, secretConfig.ProxyAddr, secretConfig.IdentityFile); err != nil { - setupLog.Error(err, "unable to create teleport client") - os.Exit(1) - } - setupLog.Info("Connected to teleport cluster", "proxyAddr", tele.SecretConfig.ProxyAddr) - + tele := teleport.New(namespace, config, token.NewGenerator()) if err = (&controller.ClusterReconciler{ Client: mgr.GetClient(), Log: ctrl.Log.WithName("controllers").WithName("Cluster"),