Skip to content

Commit

Permalink
Adding namespace based reconcilation, fixing secret issue
Browse files Browse the repository at this point in the history
  • Loading branch information
oumkale committed Dec 10, 2023
1 parent 65067f6 commit 5c87fff
Show file tree
Hide file tree
Showing 72 changed files with 128 additions and 98 deletions.
Empty file modified Dockerfile
100755 → 100644
Empty file.
4 changes: 2 additions & 2 deletions Makefile
100755 → 100644
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
# VERSION defines the project version for the bundle.
# Update this value when you upgrade the version of your project.
# To re-generate a bundle for another specific version without changing the standard setup, you can:
# - use the VERSION as arg of the bundle target (e.g make bundle VERSION=0.0.3)
# - use environment variables to overwrite this value (e.g export VERSION=0.0.3)
# - use the VERSION as arg of the bundle target (e.g make bundle VERSION=1.0.0)
# - use environment variables to overwrite this value (e.g export VERSION=1.0.0)
VERSION ?= 0.0.1
PROJECT_DIR = $(CURDIR)
SCRIPTS_DIR = ${PROJECT_DIR}/scripts
Expand Down
Empty file modified PROJECT
100755 → 100644
Empty file.
Empty file modified README.md
100755 → 100644
Empty file.
Empty file modified api/v1alpha1/groupversion_info.go
100755 → 100644
Empty file.
1 change: 1 addition & 0 deletions api/v1alpha1/secretrotator_types.go
100755 → 100644
Original file line number Diff line number Diff line change
Expand Up @@ -92,6 +92,7 @@ type SecretRotatorStatus struct {
}

// ExternalSecretCreationPolicy defines rules on how to create the resulting Secret.

// ExternalSecretTemplate defines a blueprint for the created Secret resource.
// we can not use native corev1.Secret, it will have empty ObjectMeta values: https://github.com/kubernetes-sigs/controller-tools/issues/448

Expand Down
Empty file modified api/v1alpha1/zz_generated.deepcopy.go
100755 → 100644
Empty file.
Empty file modified charts/jfrog-registry-operator/.helmignore
100755 → 100644
Empty file.
Empty file modified charts/jfrog-registry-operator/CHANGELOG.md
100755 → 100644
Empty file.
Empty file modified charts/jfrog-registry-operator/Chart.lock
100755 → 100644
Empty file.
Empty file modified charts/jfrog-registry-operator/Chart.yaml
100755 → 100644
Empty file.
Empty file modified charts/jfrog-registry-operator/charts/jfrog-common-0.0.7.tgz
100755 → 100644
Empty file.
Empty file.
Empty file modified charts/jfrog-registry-operator/examples/secretrotator.yaml
100755 → 100644
Empty file.
2 changes: 1 addition & 1 deletion charts/jfrog-registry-operator/full-values.yaml
100755 → 100644
Original file line number Diff line number Diff line change
Expand Up @@ -357,7 +357,7 @@ persistence:
##
mountPath: /var/opt/jfrog/jfrog-registry-operator
## @param persistence.subPath The subdirectory of the volume to mount to
## Useful in main environments and one PV for multiple services
## Useful in dev environments and one PV for multiple services
##
subPath: ""
## @param persistence.size PVC Storage Request for metadata data volume
Expand Down
Empty file modified charts/jfrog-registry-operator/logo/jfrog-logo.png
100755 → 100644
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Empty file modified charts/jfrog-registry-operator/templates/NOTES.txt
100755 → 100644
Empty file.
Empty file modified charts/jfrog-registry-operator/templates/_helpers.tpl
100755 → 100644
Empty file.
Empty file modified charts/jfrog-registry-operator/templates/deployment.yaml
100755 → 100644
Empty file.
Empty file modified charts/jfrog-registry-operator/templates/role.yaml
100755 → 100644
Empty file.
Empty file modified charts/jfrog-registry-operator/templates/rolebinding.yaml
100755 → 100644
Empty file.
Empty file modified charts/jfrog-registry-operator/templates/serviceaccount.yaml
100755 → 100644
Empty file.
4 changes: 2 additions & 2 deletions charts/jfrog-registry-operator/values.yaml
100755 → 100644
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ global:
image:
registry: releases-docker.jfrog.io
repository: jfrog/jfrog-registry-operator
tag: 0.0.3
tag: 1.0.0

pullPolicy: IfNotPresent
# pullSecrets:
Expand Down Expand Up @@ -189,7 +189,7 @@ persistence:
##
mountPath: /var/opt/jfrog/jfrog-registry-operator
## @param persistence.subPath The subdirectory of the volume to mount to
## Useful in main environments and one PV for multiple services
## Useful in dev environments and one PV for multiple services
##
subPath: ""
## @param persistence.size PVC Storage Request for metadata data volume
Expand Down
Empty file modified config/crd/bases/apps.jfrog.com_secretrotators.yaml
100755 → 100644
Empty file.
Empty file modified config/deploy/operator.yaml
100755 → 100644
Empty file.
Binary file removed config/images/frogbot-badge.png
Binary file not shown.
Binary file removed config/images/frogbot-intro.png
Binary file not shown.
Empty file modified config/monitoring/README.md
100755 → 100644
Empty file.
Empty file modified config/monitoring/graph.png
100755 → 100644
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Empty file modified config/monitoring/operator-service.yaml
100755 → 100644
Empty file.
Empty file modified config/monitoring/prometheus/01-prometheus-rbac.yaml
100755 → 100644
Empty file.
Empty file modified config/monitoring/prometheus/02-prometheus-configMap.yaml
100755 → 100644
Empty file.
Empty file modified config/monitoring/prometheus/prometheus-alert-rules.yaml
100755 → 100644
Empty file.
Empty file modified config/monitoring/prometheus/prometheus-deployment.yaml
100755 → 100644
Empty file.
Empty file modified config/monitoring/prometheus/prometheus-service.yaml
100755 → 100644
Empty file.
62 changes: 0 additions & 62 deletions config/rbac/role.yaml

This file was deleted.

4 changes: 2 additions & 2 deletions config/samples/jfrog_v1alpha1_secretrotator.yaml
100755 → 100644
Original file line number Diff line number Diff line change
Expand Up @@ -7,11 +7,11 @@ metadata:

app.kubernetes.io/created-by: artifactory-secrets-rotator
name: secretrotator-sample
namespace: oumk
namespace: jfrog-operator
spec:
namespaceSelector:
matchLabels:
kubernetes.io/metadata.name: oumk
kubernetes.io/metadata.name: jfrog-operator
secretName: token-secret
artifactoryUrl: ""
refreshTime: 30m
Expand Down
3 changes: 1 addition & 2 deletions config/samples/jfrog_v1alpha1_secretrotator2.yaml
100755 → 100644
Original file line number Diff line number Diff line change
Expand Up @@ -4,14 +4,13 @@ metadata:
labels:
app.kubernetes.io/name: secretrotators.apps.jfrog.com
app.kubernetes.io/instance: secretrotator-sample

app.kubernetes.io/created-by: artifactory-secrets-rotator
name: secretrotator-sample2
namespace: jfrog-operator
spec:
namespaceSelector:
matchLabels:
registry: rt2
kubernetes.io/metadata.name: jfrog-operator
secretName: token-secret
artifactoryUrl: http://10.100.23.21
refreshTime: 10m
Expand Down
Empty file modified config/samples/secret_example/echo_pod_example.yaml
100755 → 100644
Empty file.
Empty file modified config/samples/secret_example/secret_namespace.yaml
100755 → 100644
Empty file.
Empty file modified config/samples/secret_example/secret_namespace2.yaml
100755 → 100644
Empty file.
Empty file modified config/samples/secret_example/secret_namespace_not_labeled.yaml
100755 → 100644
Empty file.
Empty file modified config/samples/secret_example/secret_namespace_other_label.yaml
100755 → 100644
Empty file.
65 changes: 43 additions & 22 deletions controllers/secretrotator_controller.go
100755 → 100644
Original file line number Diff line number Diff line change
Expand Up @@ -19,11 +19,13 @@ package controllers
import (
jfrogv1alpha1 "artifactory-secrets-rotator/api/v1alpha1"
"artifactory-secrets-rotator/internal/operations"
"errors"
"reflect"

corev1 "k8s.io/api/core/v1"
"sigs.k8s.io/controller-runtime/pkg/controller"
"sigs.k8s.io/controller-runtime/pkg/event"
"sigs.k8s.io/controller-runtime/pkg/log"
"sigs.k8s.io/controller-runtime/pkg/predicate"

"context"
"fmt"
Expand Down Expand Up @@ -86,16 +88,19 @@ func (r *SecretRotatorReconciler) Reconcile(ctx context.Context, req ctrl.Reques

// InitializeResource initializes the secret rotator object and validates specs
if err := r.InitializeResource(ctx, &tokenDetails, secretRotator, req); err != nil {
r.Recorder.Eventf(secretRotator, "Warning", "Failed in initializing resource", "%s", err)
return r.handleError(err)
}

// ManagingSecrets is validating the desired state versus the actual state of secrets and creating or updating secrets.
if err := r.ManagingSecrets(ctx, &tokenDetails, secretRotator, req); err != nil {
r.Recorder.Eventf(secretRotator, "Warning", "Failed in managing secret", "%s", err)
return r.handleError(err)
}

// UpdateStatus, update the custom resource status
if err := r.UpdateStatus(ctx, &tokenDetails, secretRotator); err != nil {
r.Recorder.Eventf(secretRotator, "Warning", "Failed in updating status", "%s", err)
return r.handleError(err)
}

Expand All @@ -105,36 +110,52 @@ func (r *SecretRotatorReconciler) Reconcile(ctx context.Context, req ctrl.Reques
} else {
r.RequeueInterval = secretRotator.Spec.RefreshInterval.Duration
}

r.Log.Info("Reconcile completed, see you in", "next iteration", r.RequeueInterval)
return ctrl.Result{RequeueAfter: r.RequeueInterval}, nil
}

// handleError converts an error into reconcile result
func (r *SecretRotatorReconciler) handleError(err error) (ctrl.Result, error) {
var status *operations.ReconcileError
if !errors.As(err, &status) {
r.Log.Error(err, "Reconcile terminated")
return ctrl.Result{}, err
}
if status.Cause == nil {
r.Log.Error(status, status.Message)
} else {
r.Log.Error(status.Cause, status.Message)
}
if status.RetryIn == 0*time.Minute {
r.Log.Info("Reconcile stopped")
return ctrl.Result{}, nil
}
r.Log.Info("Reconcile stopped, will retry in", "next iteration", status.RetryIn)
return ctrl.Result{RequeueAfter: status.RetryIn}, nil
}

// SetupWithManager sets up the controller with the Manager.
func (r *SecretRotatorReconciler) SetupWithManager(mgr ctrl.Manager) error {
return ctrl.NewControllerManagedBy(mgr).
For(&jfrogv1alpha1.SecretRotator{}).
WithEventFilter(WatchNsChanges(r)).
WithOptions(controller.Options{MaxConcurrentReconciles: 1}).
Owns(&corev1.Namespace{}).
Complete(r)
}

// WatchNsChanges uses predicates for Event Filtering (namespace creation changes)
func WatchNsChanges(r *SecretRotatorReconciler) predicate.Predicate {
return predicate.Funcs{
CreateFunc: func(e event.CreateEvent) bool {
if _, ok := e.Object.(*corev1.Namespace); ok {
secretRotators := operations.ListSecretRotatorObjects(r.Client)
for i := range secretRotators.Items {
if operations.IsExist(e.Object.GetLabels(), secretRotators.Items[i].Spec.NamespaceSelector.MatchLabels) {
r.Log.Info("Created new namespace with matching labels to secret rotator object, ", "Namespace name :", e.Object.GetName(), "Secret rotator name :", secretRotators.Items[i].Name)
if flag := operations.HandlingNamespaceEvents(r.Client, r.Log, &secretRotators.Items[i]); !flag {
return false
}
}
}
}
return true
},
UpdateFunc: func(e event.UpdateEvent) bool {
if _, ok := e.ObjectOld.(*corev1.Namespace); ok {
if !reflect.DeepEqual(e.ObjectOld.GetLabels(), e.ObjectNew.GetLabels()) {
secretRotators := operations.ListSecretRotatorObjects(r.Client)
for i := range secretRotators.Items {
if operations.IsExist(e.ObjectNew.GetLabels(), secretRotators.Items[i].Spec.NamespaceSelector.MatchLabels) || operations.IsExist(e.ObjectOld.GetLabels(), secretRotators.Items[i].Spec.NamespaceSelector.MatchLabels) {
r.Log.Info("Namespace lebels has been changes, ", "Namespace name :", e.ObjectNew.GetName(), "Secret rotator name :", secretRotators.Items[i].Name)
if flag := operations.HandlingNamespaceEvents(r.Client, r.Log, &secretRotators.Items[i]); !flag {
return false
}
}
}
}
}
return true
},
}
}
23 changes: 23 additions & 0 deletions controllers/secretrotator_operations.go
100755 → 100644
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ import (
"artifactory-secrets-rotator/internal/handler"
operations "artifactory-secrets-rotator/internal/operations"
resource "artifactory-secrets-rotator/internal/resource"
"errors"
"fmt"
"sort"
"time"
Expand Down Expand Up @@ -110,6 +111,8 @@ func (r *SecretRotatorReconciler) UpdateStatus(ctx context.Context, tokenDetails
if err := r.Status().Update(ctx, secretRotator); err != nil {
return &operations.ReconcileError{Message: "Failed to update SecretRotator status", Cause: err, RetryIn: 1 * time.Minute}
}
r.Recorder.Eventf(secretRotator, "Normal", "Secret rotated successfully", "")

return nil
}

Expand Down Expand Up @@ -217,3 +220,23 @@ func (r *SecretRotatorReconciler) DeferPatch(ctx context.Context, secretRotator
func (r *SecretRotatorReconciler) DoFinalizerOperationsForSecretRotator(secretRotator *jfrogv1alpha1.SecretRotator) {
r.Recorder.Event(secretRotator, "Warning", "Deleting", fmt.Sprintf("Custom Resource %s is being deleted from the namespace %s", secretRotator.Name, secretRotator.Namespace))
}

// handleError converts an error into reconcile result
func (r *SecretRotatorReconciler) handleError(err error) (ctrl.Result, error) {
var status *operations.ReconcileError
if !errors.As(err, &status) {
r.Log.Error(err, "Reconcile terminated")
return ctrl.Result{}, err
}
if status.Cause == nil {
r.Log.Error(status, status.Message)
} else {
r.Log.Error(status.Cause, status.Message)
}
if status.RetryIn == 0*time.Minute {
r.Log.Info("Reconcile stopped")
return ctrl.Result{}, nil
}
r.Log.Info("Reconcile stopped, will retry in", "next iteration", status.RetryIn)
return ctrl.Result{RequeueAfter: status.RetryIn}, nil
}
Empty file modified controllers/suite_test.go
100755 → 100644
Empty file.
Empty file modified go.mod
100755 → 100644
Empty file.
Empty file modified go.sum
100755 → 100644
Empty file.
Empty file modified hack/boilerplate.go.txt
100755 → 100644
Empty file.
Empty file modified internal/handler/aws.go
100755 → 100644
Empty file.
11 changes: 6 additions & 5 deletions internal/handler/token.go
100755 → 100644
Original file line number Diff line number Diff line change
Expand Up @@ -8,12 +8,13 @@ import (
"encoding/json"
"errors"
"fmt"
"github.com/aws/aws-sdk-go-v2/aws"
"io"
"net/http"
"os"
"time"

"github.com/aws/aws-sdk-go-v2/aws"

"k8s.io/client-go/tools/record"

"sigs.k8s.io/controller-runtime/pkg/log"
Expand All @@ -32,7 +33,7 @@ func HandlingToken(ctx context.Context, tokenDetails *operations.TokenDetails, s
awsTokenFile := os.Getenv("AWS_WEB_IDENTITY_TOKEN_FILE")
//getting AWS_ROLE_ARN from env
if awsRoleName == "" {
recorder.Event(secretRotator, "Warning", "Misconfiguration", "missing aws Role Name")
recorder.Eventf(secretRotator, "Warning", "Misconfiguration", "missing aws Role Name")
return &operations.ReconcileError{Message: "AWS_ROLE_ARN is empty", RetryIn: 1 * time.Minute}
}
//getting AWS_WEB_IDENTITY_TOKEN_FILE from env
Expand All @@ -43,7 +44,7 @@ func HandlingToken(ctx context.Context, tokenDetails *operations.TokenDetails, s
//getting signed request headers for AWS STS GetCallerIdentity call
request, err := GetSignedRequest(ctx, awsRoleName, awsTokenFile)
if err != nil {
recorder.Event(secretRotator, "Warning", "TokenGenerationFailure",
recorder.Eventf(secretRotator, "Warning", "TokenGenerationFailure",
fmt.Sprintf("Error getting signed AWS credentials, error was %s", err.Error()))
return err
}
Expand All @@ -61,15 +62,15 @@ func HandlingToken(ctx context.Context, tokenDetails *operations.TokenDetails, s
err = errors.New("the token TTL taken from Role max session value, is shorter then reconciliation duration set through operator refreshTime, which is a misconfiguration causing token expire events")
logger.Error(err, "CRITICAL MIS CONFIGURATION")
//reflect this mis misconfiguration through the operator events
recorder.Event(secretRotator, "Warning", "TokenGenerationFailure",
recorder.Eventf(secretRotator, "Warning", "TokenGenerationFailure",
fmt.Sprintf("The token TTL taken from Role max session value (%d), is shorter then reconciliation duration set through operator refreshTime (%s), which is a misconfiguration causing token expire events",
*maxTTL,
secretRotator.Spec.RefreshInterval))
}
logger.Info("Generating artifactory token")
tokenDetails.Username, tokenDetails.Token, err = createArtifactoryToken(ctx, request, tokenDetails.ArtifactoryUrl, maxTTL)
if err != nil {
recorder.Event(secretRotator, "Warning", "Misconfiguration",
recorder.Eventf(secretRotator, "Warning", "Misconfiguration",
fmt.Sprintf("could not get artifactory Token, notice we might ran into expired tokens if this persists, error was %s", err.Error()))
return err
}
Expand Down
47 changes: 47 additions & 0 deletions internal/operations/operations.go
100755 → 100644
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,10 @@ package operations
import (
jfrogv1alpha1 "artifactory-secrets-rotator/api/v1alpha1"
"context"
"math/rand"
"time"

"github.com/go-logr/logr"
"sigs.k8s.io/controller-runtime/pkg/log"

metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
Expand Down Expand Up @@ -48,3 +52,46 @@ func ValidateObjectSpec(ctx context.Context, tokenDetails *TokenDetails, secretR
logger.Info("Artifactory host", "host", tokenDetails.ArtifactoryUrl)
return nil
}

// IsExist checks the labels from namespaces and secret rotator objects
func IsExist(namespaceLabels, objectLabels map[string]string) bool {

for val, _ := range objectLabels {
if namespaceLabels[val] != objectLabels[val] {
return false
}
}
return true
}

// GetRandomString generates random string with size 10
func GetRandomString() string {
const charset = "abcdefghijklmnopqrstuvwxyz"
var seededRand *rand.Rand = rand.New(rand.NewSource(time.Now().UnixNano()))
b := make([]byte, 10)
for i := range b {
b[i] = charset[seededRand.Intn(len(charset))]
}
return string(b)
}

// ListSecretRotatorObjects return list of secret rotator objects
func ListSecretRotatorObjects(cli client.Client) *jfrogv1alpha1.SecretRotatorList {
secretRotators := &jfrogv1alpha1.SecretRotatorList{}
err := cli.List(context.Background(), secretRotators, &client.ListOptions{})
if err != nil {
return &jfrogv1alpha1.SecretRotatorList{}
}
return secretRotators
}

func HandlingNamespaceEvents(cli client.Client, log logr.Logger, object *jfrogv1alpha1.SecretRotator) bool {
if object.Annotations == nil {
object.Annotations = make(map[string]string)
}
object.Annotations["uid"] = GetRandomString()
if err := cli.Update(context.Background(), object, &client.UpdateOptions{}); err != nil {
return false
}
return true
}
Empty file modified internal/operations/types.go
100755 → 100644
Empty file.
Empty file modified internal/resource/namespace.go
100755 → 100644
Empty file.
Empty file modified internal/resource/secret.go
100755 → 100644
Empty file.
Empty file modified internal/sign/signer.go
100755 → 100644
Empty file.
Empty file modified internal/sign/v4a/crypto/compare.go
100755 → 100644
Empty file.
Empty file modified internal/sign/v4a/crypto/compare_test.go
100755 → 100644
Empty file.
Empty file modified internal/sign/v4a/crypto/ecc.go
100755 → 100644
Empty file.
Empty file modified internal/sign/v4a/crypto/ecc_test.go
100755 → 100644
Empty file.
Empty file modified internal/sign/v4a/error.go
100755 → 100644
Empty file.
Empty file modified internal/sign/v4a/v4/const.go
100755 → 100644
Empty file.
Empty file modified internal/sign/v4a/v4/header_rules.go
100755 → 100644
Empty file.
Empty file modified internal/sign/v4a/v4/headers.go
100755 → 100644
Empty file.
Empty file modified internal/sign/v4a/v4/hmac.go
100755 → 100644
Empty file.
Empty file modified internal/sign/v4a/v4/host.go
100755 → 100644
Empty file.
Empty file modified internal/sign/v4a/v4/time.go
100755 → 100644
Empty file.
Empty file modified internal/sign/v4a/v4/util.go
100755 → 100644
Empty file.
Empty file modified internal/sign/v4a/v4/util_test.go
100755 → 100644
Empty file.
Empty file modified internal/sign/v4a/v4a.go
100755 → 100644
Empty file.
Empty file modified main.go
100755 → 100644
Empty file.
Empty file modified pom.xml
100755 → 100644
Empty file.

0 comments on commit 5c87fff

Please sign in to comment.