From 720bc912b9c0164f97ed87c57cbc60dbb3dfc561 Mon Sep 17 00:00:00 2001 From: kkb0318 Date: Wed, 10 Apr 2024 23:08:23 +0900 Subject: [PATCH] apply keypair secret --- go.mod | 3 +- go.sum | 2 - internal/controller/irsasetup_controller.go | 31 +++++++++++--- internal/handler/handler.go | 25 +++++++++++ internal/handler/kubernetes.go | 33 +++++++++++++++ internal/kubernetes/apply.go | 20 +++------ internal/kubernetes/client.go | 11 +++++ internal/kubernetes/delete.go | 16 ++----- internal/manifests/handler.go | 12 ------ internal/manifests/keys_secret.go | 47 ++++++++++++++++++++- internal/manifests/manifests.go | 8 ---- 11 files changed, 149 insertions(+), 59 deletions(-) create mode 100644 internal/handler/handler.go create mode 100644 internal/handler/kubernetes.go create mode 100644 internal/kubernetes/client.go delete mode 100644 internal/manifests/handler.go delete mode 100644 internal/manifests/manifests.go diff --git a/go.mod b/go.mod index ef06720..68f47bb 100644 --- a/go.mod +++ b/go.mod @@ -13,7 +13,7 @@ require ( github.com/onsi/ginkgo/v2 v2.17.1 github.com/onsi/gomega v1.30.0 github.com/stretchr/testify v1.9.0 - go.uber.org/mock v0.4.0 + k8s.io/api v0.29.3 k8s.io/apimachinery v0.29.3 k8s.io/client-go v0.29.3 sigs.k8s.io/controller-runtime v0.17.2 @@ -86,7 +86,6 @@ require ( gopkg.in/inf.v0 v0.9.1 // indirect gopkg.in/yaml.v2 v2.4.0 // indirect gopkg.in/yaml.v3 v3.0.1 // indirect - k8s.io/api v0.29.3 // indirect k8s.io/apiextensions-apiserver v0.29.3 // indirect k8s.io/component-base v0.29.3 // indirect k8s.io/klog/v2 v2.120.1 // indirect diff --git a/go.sum b/go.sum index 9942af0..fc3cbfd 100644 --- a/go.sum +++ b/go.sum @@ -137,8 +137,6 @@ github.com/yuin/goldmark v1.2.1/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9dec github.com/yuin/goldmark v1.4.13/go.mod h1:6yULJ656Px+3vBD8DxQVa3kxgyrAnzto9xy5taEt/CY= go.uber.org/goleak v1.3.0 h1:2K3zAYmnTNqV73imy9J1T3WC+gmCePx2hEGkimedGto= go.uber.org/goleak v1.3.0/go.mod h1:CoHD4mav9JJNrW/WLlf7HGZPjdw8EucARQHekz1X6bE= -go.uber.org/mock v0.4.0 h1:VcM4ZOtdbR4f6VXfiOpwpVJDL6lCReaZ6mw31wqh7KU= -go.uber.org/mock v0.4.0/go.mod h1:a6FSlNadKUHUa9IP5Vyt1zh4fC7uAwxMutEAscFbkZc= go.uber.org/multierr v1.11.0 h1:blXXJkSxSSfBVBlC76pxqeO+LN3aDfLQo+309xJstO0= go.uber.org/multierr v1.11.0/go.mod h1:20+QtiLqy0Nd6FdQB9TLXag12DsQkrbs3htMFfDN80Y= go.uber.org/zap v1.27.0 h1:aJMhYGrd5QSmlpLMr2MftRKl7t8J8PTZPA732ud/XR8= diff --git a/internal/controller/irsasetup_controller.go b/internal/controller/irsasetup_controller.go index ff9652f..44df1d6 100644 --- a/internal/controller/irsasetup_controller.go +++ b/internal/controller/irsasetup_controller.go @@ -27,6 +27,9 @@ import ( irsav1alpha1 "github.com/kkb0318/irsa-manager/api/v1alpha1" awsclient "github.com/kkb0318/irsa-manager/internal/client" + "github.com/kkb0318/irsa-manager/internal/handler" + "github.com/kkb0318/irsa-manager/internal/kubernetes" + "github.com/kkb0318/irsa-manager/internal/manifests" "github.com/kkb0318/irsa-manager/internal/selfhosted" "github.com/kkb0318/irsa-manager/internal/selfhosted/oidc" ) @@ -53,12 +56,16 @@ type IRSASetupReconciler struct { // // For more details, check Reconcile and its Result here: // - https://pkg.go.dev/sigs.k8s.io/controller-runtime@v0.16.3/pkg/reconcile -func (r *IRSASetupReconciler) Reconcile(ctx context.Context, req ctrl.Request) (result ctrl.Result, retErr error) { +func (r *IRSASetupReconciler) Reconcile(ctx context.Context, req ctrl.Request) (ctrl.Result, error) { log := ctrllog.FromContext(ctx) obj := &irsav1alpha1.IRSASetup{} if err := r.Get(ctx, req.NamespacedName, obj); err != nil { return ctrl.Result{}, client.IgnoreNotFound(err) } + kubeClient, err := kubernetes.NewKubernetesClient(r.Client, kubernetes.Owner{Field: "irsa-manager"}) + if err != nil { + return ctrl.Result{}, err + } if !controllerutil.ContainsFinalizer(obj, irsamanagerFinalizer) { controllerutil.AddFinalizer(obj, irsamanagerFinalizer) @@ -70,11 +77,11 @@ func (r *IRSASetupReconciler) Reconcile(ctx context.Context, req ctrl.Request) ( } if !obj.DeletionTimestamp.IsZero() { - retErr = r.reconcileDelete(ctx, obj) - return + err = r.reconcileDelete(ctx, obj) + return ctrl.Result{}, err } - if err := r.reconcile(ctx, obj); err != nil { + if err := r.reconcile(ctx, obj, kubeClient); err != nil { return ctrl.Result{}, err } @@ -82,8 +89,8 @@ func (r *IRSASetupReconciler) Reconcile(ctx context.Context, req ctrl.Request) ( return ctrl.Result{}, nil } -func (r *IRSASetupReconciler) reconcile(ctx context.Context, obj *irsav1alpha1.IRSASetup) error { - err := reconcileSelfhosted(ctx, obj, r.AwsClient) +func (r *IRSASetupReconciler) reconcile(ctx context.Context, obj *irsav1alpha1.IRSASetup, kubeClient *kubernetes.KubernetesClient) error { + err := reconcileSelfhosted(ctx, obj, r.AwsClient, kubeClient) return err } @@ -91,7 +98,7 @@ func (r *IRSASetupReconciler) reconcileDelete(ctx context.Context, obj *irsav1al return nil } -func reconcileSelfhosted(ctx context.Context, obj *irsav1alpha1.IRSASetup, awsClient awsclient.AwsClient) error { +func reconcileSelfhosted(ctx context.Context, obj *irsav1alpha1.IRSASetup, awsClient awsclient.AwsClient, kubeClient *kubernetes.KubernetesClient) error { keyPair, err := selfhosted.CreateKeyPair() if err != nil { return err @@ -104,10 +111,20 @@ func reconcileSelfhosted(ctx context.Context, obj *irsav1alpha1.IRSASetup, awsCl if err != nil { return err } + secret, err := manifests.NewSecretBuilder().WithSSHKey(*keyPair).Build("name", "default") + if err != nil { + return err + } + kubeHandler := handler.NewKubernetesHandler(kubeClient) + kubeHandler.Append(secret) err = selfhosted.Execute(ctx, factory) if err != nil { return err } + err = kubeHandler.ApplyAll(ctx) + if err != nil { + return err + } return nil } diff --git a/internal/handler/handler.go b/internal/handler/handler.go new file mode 100644 index 0000000..639dfc3 --- /dev/null +++ b/internal/handler/handler.go @@ -0,0 +1,25 @@ +package handler + +import ( + "context" + + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + "k8s.io/apimachinery/pkg/apis/meta/v1/unstructured" + "sigs.k8s.io/controller-runtime/pkg/client" +) + +type KubernetesClient interface { + Apply(ctx context.Context, obj client.Object) error + Delete(ctx context.Context, obj *unstructured.Unstructured, opts DeleteOptions) error +} + +// DeleteOptions contains options for delete requests. +type DeleteOptions struct { + // DeletionPropagation decides how the garbage collector will handle the propagation. + DeletionPropagation metav1.DeletionPropagation + + // Inclusions determines which in-cluster objects are subject to deletion + // based on the labels. + // A nil Inclusions map means all objects are subject to deletion + Inclusions map[string]string +} diff --git a/internal/handler/kubernetes.go b/internal/handler/kubernetes.go new file mode 100644 index 0000000..e8fa60e --- /dev/null +++ b/internal/handler/kubernetes.go @@ -0,0 +1,33 @@ +package handler + +import ( + "context" + + "sigs.k8s.io/controller-runtime/pkg/client" +) + +type KubernetesHandler struct { + client KubernetesClient + objs []client.Object +} + +func NewKubernetesHandler(k KubernetesClient) *KubernetesHandler { + return &KubernetesHandler{ + client: k, + objs: []client.Object{}, + } +} + +func (k *KubernetesHandler) Append(obj client.Object) { + k.objs = append(k.objs, obj) +} + +func (k *KubernetesHandler) ApplyAll(ctx context.Context) error { + for _, obj := range k.objs { + err := k.client.Apply(ctx, obj) + if err != nil { + return err + } + } + return nil +} diff --git a/internal/kubernetes/apply.go b/internal/kubernetes/apply.go index a4f0763..3ea57bf 100644 --- a/internal/kubernetes/apply.go +++ b/internal/kubernetes/apply.go @@ -10,22 +10,14 @@ import ( "sigs.k8s.io/controller-runtime/pkg/client/apiutil" ) -type Handler struct { - cleanup bool - client client.Client - owner Owner -} - -// NewHelper returns an initialized Helper. -func NewHandler(c client.Client, owner Owner, cleanup bool) (*Handler, error) { - return &Handler{ - cleanup: cleanup, - client: c, - owner: owner, +func NewKubernetesClient(c client.Client, owner Owner) (*KubernetesClient, error) { + return &KubernetesClient{ + client: c, + owner: owner, }, nil } -func (h Handler) Apply(ctx context.Context, obj client.Object) error { +func (h KubernetesClient) Apply(ctx context.Context, obj client.Object) error { opts := []client.PatchOption{ client.ForceOwnership, client.FieldOwner(h.owner.Field), @@ -50,7 +42,7 @@ func (h Handler) Apply(ctx context.Context, obj client.Object) error { return nil } -func (h Handler) PatchStatus(ctx context.Context, obj client.Object) error { +func (h KubernetesClient) PatchStatus(ctx context.Context, obj client.Object) error { opts := &client.SubResourcePatchOptions{ PatchOptions: client.PatchOptions{ FieldManager: h.owner.Field, diff --git a/internal/kubernetes/client.go b/internal/kubernetes/client.go new file mode 100644 index 0000000..c7579dc --- /dev/null +++ b/internal/kubernetes/client.go @@ -0,0 +1,11 @@ +package kubernetes + +import ( + "sigs.k8s.io/controller-runtime/pkg/client" +) + +type KubernetesClient struct { + client client.Client + owner Owner + cleanup bool +} diff --git a/internal/kubernetes/delete.go b/internal/kubernetes/delete.go index 142ded7..aaf3bd8 100644 --- a/internal/kubernetes/delete.go +++ b/internal/kubernetes/delete.go @@ -6,6 +6,7 @@ import ( metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + "github.com/kkb0318/irsa-manager/internal/handler" "k8s.io/apimachinery/pkg/api/errors" "k8s.io/apimachinery/pkg/apis/meta/v1/unstructured" "k8s.io/apimachinery/pkg/labels" @@ -13,18 +14,7 @@ import ( "sigs.k8s.io/controller-runtime/pkg/client" ) -// DeleteOptions contains options for delete requests. -type DeleteOptions struct { - // DeletionPropagation decides how the garbage collector will handle the propagation. - DeletionPropagation metav1.DeletionPropagation - - // Inclusions determines which in-cluster objects are subject to deletion - // based on the labels. - // A nil Inclusions map means all objects are subject to deletion - Inclusions map[string]string -} - -func (h *Handler) DeleteAll(ctx context.Context, resources []*unstructured.Unstructured, opts DeleteOptions) error { +func (h *KubernetesClient) DeleteAll(ctx context.Context, resources []*unstructured.Unstructured, opts handler.DeleteOptions) error { if !h.cleanup { return nil } @@ -38,7 +28,7 @@ func (h *Handler) DeleteAll(ctx context.Context, resources []*unstructured.Unstr } // Delete deletes the given object (not found errors are ignored). -func (h *Handler) Delete(ctx context.Context, object *unstructured.Unstructured, opts DeleteOptions) error { +func (h *KubernetesClient) Delete(ctx context.Context, object *unstructured.Unstructured, opts handler.DeleteOptions) error { if !h.cleanup { return nil } diff --git a/internal/manifests/handler.go b/internal/manifests/handler.go deleted file mode 100644 index 85b78e0..0000000 --- a/internal/manifests/handler.go +++ /dev/null @@ -1,12 +0,0 @@ -package manifests - -import ( - "context" - - "k8s.io/apimachinery/pkg/apis/meta/v1/unstructured" -) - -type Handler interface { - Apply(ctx context.Context, obj *unstructured.Unstructured) error - Delete(ctx context.Context, obj *unstructured.Unstructured) error -} diff --git a/internal/manifests/keys_secret.go b/internal/manifests/keys_secret.go index 5b41351..9b74bb9 100644 --- a/internal/manifests/keys_secret.go +++ b/internal/manifests/keys_secret.go @@ -1,3 +1,48 @@ package manifests -// TODO: get keys from oidc, and create secret struct +import ( + "fmt" + + "github.com/kkb0318/irsa-manager/internal/selfhosted" + corev1 "k8s.io/api/core/v1" + v1 "k8s.io/apimachinery/pkg/apis/meta/v1" +) + +type SecretBuilder struct { + data map[string][]byte + secretType corev1.SecretType +} + +func NewSecretBuilder() *SecretBuilder { + return &SecretBuilder{ + secretType: corev1.SecretTypeOpaque, + } +} + +func (b *SecretBuilder) WithSSHKey(keyPair selfhosted.KeyPair) *SecretBuilder { + b.data = map[string][]byte{ + "ssh-publickey": keyPair.PublicKey(), + corev1.SSHAuthPrivateKey: keyPair.PrivateKey(), + } + b.secretType = corev1.SecretTypeSSHAuth + return b +} + +func (b *SecretBuilder) Build(name, ns string) (*corev1.Secret, error) { + if b.data == nil { + return nil, fmt.Errorf("Secret.Data is empty") + } + secret := &corev1.Secret{ + ObjectMeta: v1.ObjectMeta{ + Name: name, + Namespace: ns, + }, + TypeMeta: v1.TypeMeta{ + APIVersion: corev1.SchemeGroupVersion.String(), + Kind: "Secret", + }, + Type: b.secretType, + Data: b.data, + } + return secret, nil +} diff --git a/internal/manifests/manifests.go b/internal/manifests/manifests.go deleted file mode 100644 index 0f6041b..0000000 --- a/internal/manifests/manifests.go +++ /dev/null @@ -1,8 +0,0 @@ -package manifests - -import "context" - -type Manifest interface { - Apply(ctx context.Context, handler Handler) error - Delete(ctx context.Context, handler Handler) error -}