@@ -6,31 +6,55 @@ import (
6
6
"log"
7
7
"time"
8
8
9
- "k8s.io/apimachinery/pkg/runtime"
10
-
11
- apiv1 "k8s.io/api/core/v1"
9
+ corev1 "k8s.io/api/core/v1"
10
+ apiequality "k8s.io/apimachinery/pkg/api/equality"
12
11
"k8s.io/apimachinery/pkg/api/errors"
13
12
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
13
+ "k8s.io/apimachinery/pkg/runtime"
14
14
runtimeserializer "k8s.io/apimachinery/pkg/runtime/serializer"
15
15
utilruntime "k8s.io/apimachinery/pkg/util/runtime"
16
16
"k8s.io/apimachinery/pkg/util/wait"
17
17
"k8s.io/client-go/kubernetes"
18
18
"k8s.io/client-go/kubernetes/scheme"
19
- "k8s.io/client-go/kubernetes/typed/core/v1"
19
+ v1 "k8s.io/client-go/kubernetes/typed/core/v1"
20
20
"k8s.io/client-go/tools/cache"
21
+ "k8s.io/client-go/tools/record"
21
22
"k8s.io/client-go/util/workqueue"
22
23
23
24
ssv1alpha1 "github.com/bitnami-labs/sealed-secrets/pkg/apis/sealed-secrets/v1alpha1"
25
+ ssclientset "github.com/bitnami-labs/sealed-secrets/pkg/client/clientset/versioned"
26
+ ssscheme "github.com/bitnami-labs/sealed-secrets/pkg/client/clientset/versioned/scheme"
27
+ ssv1alpha1client "github.com/bitnami-labs/sealed-secrets/pkg/client/clientset/versioned/typed/sealed-secrets/v1alpha1"
24
28
ssinformer "github.com/bitnami-labs/sealed-secrets/pkg/client/informers/externalversions"
25
29
)
26
30
27
- const maxRetries = 5
31
+ const (
32
+ maxRetries = 5
33
+
34
+ // SuccessUnsealed is used as part of the Event 'reason' when
35
+ // a SealedSecret is unsealed successfully.
36
+ SuccessUnsealed = "Unsealed"
37
+
38
+ // ErrUpdateFailed is used as part of the Event 'reason' when
39
+ // a SealedSecret fails to update the target Secret for a
40
+ // non-cryptography reason. Typically this is due to API I/O
41
+ // or RBAC issues.
42
+ ErrUpdateFailed = "ErrUpdateFailed"
43
+
44
+ // ErrUnsealFailed is used as part of the Event 'reason' when a
45
+ // SealedSecret fails the unsealing process. Typically this
46
+ // is because it is encrypted with the wrong key or has been
47
+ // renamed from its original namespace/name.
48
+ ErrUnsealFailed = "ErrUnsealFailed"
49
+ )
28
50
29
51
// Controller implements the main sealed-secrets-controller loop.
30
52
type Controller struct {
31
53
queue workqueue.RateLimitingInterface
32
54
informer cache.SharedIndexInformer
33
55
sclient v1.SecretsGetter
56
+ ssclient ssv1alpha1client.SealedSecretsGetter
57
+ recorder record.EventRecorder
34
58
keyRegistry * KeyRegistry
35
59
}
36
60
@@ -62,9 +86,15 @@ func unseal(sclient v1.SecretsGetter, codecs runtimeserializer.CodecFactory, key
62
86
}
63
87
64
88
// NewController returns the main sealed-secrets controller loop.
65
- func NewController (clientset kubernetes.Interface , ssinformer ssinformer.SharedInformerFactory , keyRegistry * KeyRegistry ) * Controller {
89
+ func NewController (clientset kubernetes.Interface , ssclientset ssclientset. Interface , ssinformer ssinformer.SharedInformerFactory , keyRegistry * KeyRegistry ) * Controller {
66
90
queue := workqueue .NewRateLimitingQueue (workqueue .DefaultControllerRateLimiter ())
67
91
92
+ ssscheme .AddToScheme (scheme .Scheme )
93
+ eventBroadcaster := record .NewBroadcaster ()
94
+ eventBroadcaster .StartLogging (log .Printf )
95
+ eventBroadcaster .StartRecordingToSink (& v1.EventSinkImpl {Interface : clientset .CoreV1 ().Events ("" )})
96
+ recorder := eventBroadcaster .NewRecorder (scheme .Scheme , corev1.EventSource {Component : "sealed-secrets" })
97
+
68
98
informer := ssinformer .Bitnami ().V1alpha1 ().
69
99
SealedSecrets ().
70
100
Informer ()
@@ -93,7 +123,9 @@ func NewController(clientset kubernetes.Interface, ssinformer ssinformer.SharedI
93
123
return & Controller {
94
124
informer : informer ,
95
125
queue : queue ,
96
- sclient : clientset .Core (),
126
+ sclient : clientset .CoreV1 (),
127
+ ssclient : ssclientset .BitnamiV1alpha1 (),
128
+ recorder : recorder ,
97
129
keyRegistry : keyRegistry ,
98
130
}
99
131
}
@@ -185,31 +217,66 @@ func (c *Controller) unseal(key string) error {
185
217
ssecret := obj .(* ssv1alpha1.SealedSecret )
186
218
log .Printf ("Updating %s" , key )
187
219
188
- secret , err := c .attemptUnseal (ssecret )
220
+ newSecret , err := c .attemptUnseal (ssecret )
189
221
if err != nil {
222
+ c .recorder .Eventf (ssecret , corev1 .EventTypeWarning , ErrUnsealFailed , "Failed to unseal: %v" , err )
190
223
return err
191
224
}
192
225
193
- _ , err = c .sclient .Secrets (ssecret .GetObjectMeta ().GetNamespace ()).Create (secret )
194
- if err == nil {
195
- // Secret successfully created
196
- return nil
226
+ secret , err := c .sclient .Secrets (ssecret .GetObjectMeta ().GetNamespace ()).Get (newSecret .GetObjectMeta ().GetName (), metav1.GetOptions {})
227
+ if errors .IsNotFound (err ) {
228
+ secret , err = c .sclient .Secrets (ssecret .GetObjectMeta ().GetNamespace ()).Create (newSecret )
197
229
}
198
- if ! errors . IsAlreadyExists ( err ) {
199
- // Error wasn't already exists so is real error
230
+ if err != nil {
231
+ c . recorder . Event ( ssecret , corev1 . EventTypeWarning , ErrUpdateFailed , err . Error ())
200
232
return err
201
233
}
202
234
203
- // Secret already exists so update it in place with new data/owner reference
204
- updatedSecret , err := c .updateSecret (secret )
235
+ if ! metav1 .IsControlledBy (secret , ssecret ) {
236
+ msg := fmt .Sprintf ("Resource %q already exists and is not managed by SealedSecret" , secret .Name )
237
+ c .recorder .Event (ssecret , corev1 .EventTypeWarning , ErrUpdateFailed , msg )
238
+ return fmt .Errorf ("failed update: %s" , msg )
239
+ }
240
+
241
+ origSecret := secret
242
+ secret = secret .DeepCopy ()
243
+
244
+ secret .Data = newSecret .Data
245
+ secret .Type = newSecret .Type
246
+ secret .ObjectMeta .Annotations = newSecret .ObjectMeta .Annotations
247
+ secret .ObjectMeta .Labels = newSecret .ObjectMeta .Labels
248
+
249
+ if ! apiequality .Semantic .DeepEqual (origSecret , secret ) {
250
+ secret , err = c .sclient .Secrets (ssecret .GetObjectMeta ().GetNamespace ()).Update (secret )
251
+ if err != nil {
252
+ c .recorder .Event (ssecret , corev1 .EventTypeWarning , ErrUpdateFailed , err .Error ())
253
+ return err
254
+ }
255
+ }
256
+
257
+ err = c .updateSealedSecretStatus (ssecret , secret )
205
258
if err != nil {
206
- return fmt .Errorf ("failed to update existing secret: %s" , err )
259
+ // Non-fatal. Log and continue.
260
+ log .Printf ("Error updating SealedSecret %s status: %v" , key , err )
207
261
}
208
- _ , err = c .sclient .Secrets (ssecret .GetObjectMeta ().GetNamespace ()).Update (updatedSecret )
262
+
263
+ c .recorder .Event (ssecret , corev1 .EventTypeNormal , SuccessUnsealed , "SealedSecret unsealed successfully" )
264
+ return nil
265
+ }
266
+
267
+ func (c * Controller ) updateSealedSecretStatus (ssecret * ssv1alpha1.SealedSecret , secret * corev1.Secret ) error {
268
+ ssecret = ssecret .DeepCopy ()
269
+
270
+ ssecret .Status .ObservedGeneration = secret .ObjectMeta .Generation
271
+
272
+ // TODO: Use UpdateStatus when k8s CustomResourceSubresources
273
+ // feature is widespread.
274
+ var err error
275
+ ssecret , err = c .ssclient .SealedSecrets (ssecret .GetObjectMeta ().GetNamespace ()).Update (ssecret )
209
276
return err
210
277
}
211
278
212
- func (c * Controller ) updateSecret (newSecret * apiv1 .Secret ) (* apiv1 .Secret , error ) {
279
+ func (c * Controller ) updateSecret (newSecret * corev1 .Secret ) (* corev1 .Secret , error ) {
213
280
existingSecret , err := c .sclient .Secrets (newSecret .GetObjectMeta ().GetNamespace ()).Get (newSecret .GetObjectMeta ().GetName (), metav1.GetOptions {})
214
281
if err != nil {
215
282
return nil , fmt .Errorf ("failed to read existing secret: %s" , err )
@@ -222,7 +289,7 @@ func (c *Controller) updateSecret(newSecret *apiv1.Secret) (*apiv1.Secret, error
222
289
return existingSecret , nil
223
290
}
224
291
225
- func (c * Controller ) updateOwnerReferences (existing , new * apiv1 .Secret ) {
292
+ func (c * Controller ) updateOwnerReferences (existing , new * corev1 .Secret ) {
226
293
ownerRefs := existing .GetOwnerReferences ()
227
294
228
295
for _ , newRef := range new .GetOwnerReferences () {
@@ -288,11 +355,11 @@ func (c *Controller) Rotate(content []byte) ([]byte, error) {
288
355
}
289
356
}
290
357
291
- func (c * Controller ) attemptUnseal (ss * ssv1alpha1.SealedSecret ) (* apiv1 .Secret , error ) {
358
+ func (c * Controller ) attemptUnseal (ss * ssv1alpha1.SealedSecret ) (* corev1 .Secret , error ) {
292
359
return attemptUnseal (ss , c .keyRegistry )
293
360
}
294
361
295
- func attemptUnseal (ss * ssv1alpha1.SealedSecret , keyRegistry * KeyRegistry ) (* apiv1 .Secret , error ) {
362
+ func attemptUnseal (ss * ssv1alpha1.SealedSecret , keyRegistry * KeyRegistry ) (* corev1 .Secret , error ) {
296
363
for _ , privKey := range keyRegistry .privateKeys {
297
364
if secret , err := ss .Unseal (scheme .Codecs , privKey ); err == nil {
298
365
return secret , nil
0 commit comments