mirror of
https://github.com/external-secrets/external-secrets.git
synced 2024-12-14 11:57:59 +00:00
Merge pull request #329 from FGA-GCES/feat/immutable-secrets
Add immutable secrets
This commit is contained in:
commit
c00afc9ff7
4 changed files with 70 additions and 2 deletions
|
@ -103,6 +103,10 @@ type ExternalSecretTarget struct {
|
|||
// Template defines a blueprint for the created Secret resource.
|
||||
// +optional
|
||||
Template *ExternalSecretTemplate `json:"template,omitempty"`
|
||||
|
||||
// Immutable defines if the final secret will be immutable
|
||||
// +optional
|
||||
Immutable bool `json:"immutable,omitempty"`
|
||||
}
|
||||
|
||||
// ExternalSecretData defines the connection between the Kubernetes Secret key (spec.data.<key>) and the Provider data.
|
||||
|
|
|
@ -132,6 +132,9 @@ spec:
|
|||
description: CreationPolicy defines rules on how to create the
|
||||
resulting Secret Defaults to 'Owner'
|
||||
type: string
|
||||
immutable:
|
||||
description: Immutable defines if the final secret will be immutable
|
||||
type: boolean
|
||||
name:
|
||||
description: Name defines the name of the Secret resource to be
|
||||
managed This field is immutable Defaults to the .metadata.name
|
||||
|
|
|
@ -180,13 +180,21 @@ func (r *Reconciler) Reconcile(ctx context.Context, req ctrl.Request) (ctrl.Resu
|
|||
log.V(1).Info("skipping refresh", "rv", getResourceVersion(externalSecret))
|
||||
return ctrl.Result{RequeueAfter: refreshInt}, nil
|
||||
}
|
||||
if !shouldReconcile(externalSecret) {
|
||||
log.V(1).Info("stopping reconciling", "rv", getResourceVersion(externalSecret))
|
||||
return ctrl.Result{
|
||||
RequeueAfter: 0,
|
||||
Requeue: false,
|
||||
}, nil
|
||||
}
|
||||
|
||||
secret := &v1.Secret{
|
||||
ObjectMeta: metav1.ObjectMeta{
|
||||
Name: secretName,
|
||||
Namespace: externalSecret.Namespace,
|
||||
},
|
||||
Data: make(map[string][]byte),
|
||||
Immutable: &externalSecret.Spec.Target.Immutable,
|
||||
Data: make(map[string][]byte),
|
||||
}
|
||||
|
||||
mutationFunc := func() error {
|
||||
|
@ -314,6 +322,22 @@ func shouldRefresh(es esv1alpha1.ExternalSecret) bool {
|
|||
return !es.Status.RefreshTime.Add(es.Spec.RefreshInterval.Duration).After(time.Now())
|
||||
}
|
||||
|
||||
func shouldReconcile(es esv1alpha1.ExternalSecret) bool {
|
||||
if es.Spec.Target.Immutable && hasSyncedCondition(es) {
|
||||
return false
|
||||
}
|
||||
return true
|
||||
}
|
||||
|
||||
func hasSyncedCondition(es esv1alpha1.ExternalSecret) bool {
|
||||
for _, condition := range es.Status.Conditions {
|
||||
if condition.Reason == "SecretSynced" {
|
||||
return true
|
||||
}
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
// isSecretValid checks if the secret exists, and it's data is consistent with the calculated hash.
|
||||
func isSecretValid(existingSecret v1.Secret) bool {
|
||||
// if target secret doesn't exist, or annotations as not set, we need to refresh
|
||||
|
|
|
@ -307,7 +307,7 @@ var _ = Describe("ExternalSecret controller", func() {
|
|||
Expect(hasFieldOwnership(
|
||||
secret.ObjectMeta,
|
||||
"external-secrets",
|
||||
fmt.Sprintf("{\"f:data\":{\"f:targetProperty\":{}},\"f:metadata\":{\"f:annotations\":{\"f:%s\":{}}}}", esv1alpha1.AnnotationDataHash)),
|
||||
fmt.Sprintf("{\"f:data\":{\"f:targetProperty\":{}},\"f:immutable\":{},\"f:metadata\":{\"f:annotations\":{\"f:%s\":{}}}}", esv1alpha1.AnnotationDataHash)),
|
||||
).To(BeTrue())
|
||||
Expect(hasFieldOwnership(secret.ObjectMeta, "fake.manager", "{\"f:data\":{\".\":{},\"f:pre-existing-key\":{}},\"f:type\":{}}")).To(BeTrue())
|
||||
}
|
||||
|
@ -1138,6 +1138,43 @@ var _ = Describe("ExternalSecret refresh logic", func() {
|
|||
})
|
||||
})
|
||||
|
||||
var _ = Describe("Controller Reconcile logic", func() {
|
||||
Context("controller reconcile", func() {
|
||||
It("should reconcile when resource is not synced", func() {
|
||||
Expect(shouldReconcile(esv1alpha1.ExternalSecret{
|
||||
Status: esv1alpha1.ExternalSecretStatus{
|
||||
SyncedResourceVersion: "some resource version",
|
||||
Conditions: []esv1alpha1.ExternalSecretStatusCondition{{Reason: "NotASecretSynced"}},
|
||||
},
|
||||
})).To(BeTrue())
|
||||
})
|
||||
|
||||
It("should reconcile when secret isn't immutable", func() {
|
||||
Expect(shouldReconcile(esv1alpha1.ExternalSecret{
|
||||
Spec: esv1alpha1.ExternalSecretSpec{
|
||||
Target: esv1alpha1.ExternalSecretTarget{
|
||||
Immutable: false,
|
||||
},
|
||||
},
|
||||
})).To(BeTrue())
|
||||
})
|
||||
|
||||
It("should not reconcile if secret is immutable and has synced condition", func() {
|
||||
Expect(shouldReconcile(esv1alpha1.ExternalSecret{
|
||||
Spec: esv1alpha1.ExternalSecretSpec{
|
||||
Target: esv1alpha1.ExternalSecretTarget{
|
||||
Immutable: true,
|
||||
},
|
||||
},
|
||||
Status: esv1alpha1.ExternalSecretStatus{
|
||||
SyncedResourceVersion: "some resource version",
|
||||
Conditions: []esv1alpha1.ExternalSecretStatusCondition{{Reason: "SecretSynced"}},
|
||||
},
|
||||
})).To(BeFalse())
|
||||
})
|
||||
})
|
||||
})
|
||||
|
||||
// CreateNamespace creates a new namespace in the cluster.
|
||||
func CreateNamespace(baseName string, c client.Client) (string, error) {
|
||||
genName := fmt.Sprintf("ctrl-test-%v", baseName)
|
||||
|
|
Loading…
Reference in a new issue