first controller implementation
This commit is contained in:
		| @@ -21,13 +21,19 @@ package controller | ||||
|  | ||||
| import ( | ||||
| 	"context" | ||||
| 	"encoding/base64" | ||||
| 	"os" | ||||
|  | ||||
| 	"k8s.io/apimachinery/pkg/api/errors" | ||||
| 	"k8s.io/apimachinery/pkg/runtime" | ||||
| 	ctrl "sigs.k8s.io/controller-runtime" | ||||
| 	"sigs.k8s.io/controller-runtime/pkg/client" | ||||
| 	"sigs.k8s.io/controller-runtime/pkg/log" | ||||
|  | ||||
| 	"github.com/bitwarden/sdk-go" | ||||
| 	lerentisuploadfilter24euv1 "github.com/lerentis/bitwarden-crd-operator/api/v1" | ||||
| 	corev1 "k8s.io/api/core/v1" | ||||
| 	metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" | ||||
| ) | ||||
|  | ||||
| // BitwardenSecretReconciler reconciles a BitwardenSecret object | ||||
| @@ -50,9 +56,97 @@ type BitwardenSecretReconciler struct { | ||||
| // For more details, check Reconcile and its Result here: | ||||
| // - https://pkg.go.dev/sigs.k8s.io/controller-runtime@v0.20.2/pkg/reconcile | ||||
| func (r *BitwardenSecretReconciler) Reconcile(ctx context.Context, req ctrl.Request) (ctrl.Result, error) { | ||||
| 	_ = log.FromContext(ctx) | ||||
| 	olog := log.FromContext(ctx) | ||||
|  | ||||
| 	// TODO(user): your logic here | ||||
| 	// Fetch the BitwardenSecret instance | ||||
| 	var bitwardenSecret lerentisuploadfilter24euv1.BitwardenSecret | ||||
| 	if err := r.Get(ctx, req.NamespacedName, &bitwardenSecret); err != nil { | ||||
| 		if errors.IsNotFound(err) { | ||||
| 			olog.Info("BitwardenSecret resource not found. Ignoring since object must be deleted.") | ||||
| 			return ctrl.Result{}, nil | ||||
| 		} | ||||
| 		olog.Error(err, "Failed to get BitwardenSecret.") | ||||
| 		return ctrl.Result{}, err | ||||
| 	} | ||||
|  | ||||
| 	// Fetch secrets from Bitwarden | ||||
| 	apiURL := os.Getenv("API_URL") | ||||
| 	identityURL := os.Getenv("IDENTITY_URL") | ||||
|  | ||||
| 	client, _ := sdk.NewBitwardenClient(&apiURL, &identityURL) | ||||
|  | ||||
| 	accessToken := os.Getenv("ACCESS_TOKEN") | ||||
|  | ||||
| 	stateFile := os.Getenv("STATE_FILE") | ||||
|  | ||||
| 	err := client.AccessTokenLogin(accessToken, &stateFile) | ||||
| 	if err != nil { | ||||
| 		olog.Error(err, "Failed to authenticate with Bitwarden.") | ||||
| 		return ctrl.Result{}, err | ||||
| 	} | ||||
|  | ||||
| 	secretData := make(map[string][]byte) | ||||
| 	for _, element := range bitwardenSecret.Spec.Content { | ||||
| 		resp, err := client.Secrets().Get(bitwardenSecret.Spec.ID) | ||||
| 		if err != nil { | ||||
| 			olog.Error(err, "Failed to fetch item from Bitwarden.") | ||||
| 			return ctrl.Result{}, err | ||||
| 		} | ||||
|  | ||||
| 		item := resp.Value | ||||
|  | ||||
| 		var secretValue string | ||||
| 		switch element.SecretScope { | ||||
| 		case "login": | ||||
| 			if element.SecretName == "username" { | ||||
| 				secretValue = item.Login.Username | ||||
| 			} else if element.SecretName == "password" { | ||||
| 				secretValue = item.Login.Password | ||||
| 			} | ||||
| 		case "fields": | ||||
| 			for _, field := range item.Fields { | ||||
| 				if field.Name == element.SecretName { | ||||
| 					secretValue = field.Value | ||||
| 					break | ||||
| 				} | ||||
| 			} | ||||
| 		case "attachment": | ||||
| 			for _, attachment := range item.Attachments { | ||||
| 				if attachment.FileName == element.SecretName { | ||||
| 					secretValue = attachment.File | ||||
| 					break | ||||
| 				} | ||||
| 			} | ||||
| 		} | ||||
|  | ||||
| 		if secretValue != "" { | ||||
| 			secretData[element.SecretRef] = []byte(base64.StdEncoding.EncodeToString([]byte(secretValue))) | ||||
| 		} | ||||
| 	} | ||||
|  | ||||
| 	// Create or update Kubernetes secret | ||||
| 	secret := &corev1.Secret{ | ||||
| 		ObjectMeta: metav1.ObjectMeta{ | ||||
| 			Name:        bitwardenSecret.Spec.Name, | ||||
| 			Namespace:   bitwardenSecret.Spec.Namespace, | ||||
| 			Labels:      bitwardenSecret.Spec.Labels, | ||||
| 			Annotations: bitwardenSecret.Spec.Annotations, | ||||
| 		}, | ||||
| 		Data: secretData, | ||||
| 		Type: corev1.SecretType(bitwardenSecret.Spec.SecretType), | ||||
| 	} | ||||
|  | ||||
| 	if err := r.Client.Create(ctx, secret); err != nil && !errors.IsAlreadyExists(err) { | ||||
| 		olog.Error(err, "Failed to create Secret.") | ||||
| 		return ctrl.Result{}, err | ||||
| 	} | ||||
|  | ||||
| 	if errors.IsAlreadyExists(err) { | ||||
| 		if err := r.Client.Update(ctx, secret); err != nil { | ||||
| 			olog.Error(err, "Failed to update Secret.") | ||||
| 			return ctrl.Result{}, err | ||||
| 		} | ||||
| 	} | ||||
|  | ||||
| 	return ctrl.Result{}, nil | ||||
| } | ||||
|   | ||||
		Reference in New Issue
	
	Block a user