Skip to content

Commit 30c1d2d

Browse files
authored
Fix register a key using secret creationTimestamp instead of certificate validity timestamp (#1681)
<!-- Before you open the request please review the following guidelines and tips to help it be more easily integrated: - Describe the scope of your change - i.e. what the change does. - Describe any known limitations with your change. - Please run any tests or examples that can exercise your modified code. Thank you for contributing! We will try to test and integrate the change as soon as we can, but be aware we have many GitHub repositories to manage and can't immediately respond to every request. There is no need to bump or check in on a pull request (it will clutter the discussion of the request). Also don't be worried if the request is closed or not integrated sometimes the priorities of Bitnami might not match the priorities of the pull request. Don't fret, the open source community thrives on forks and GitHub makes it easy to keep your changes in a forked repo. --> **Description of the change** Register a key and order it based on its secret creation timestamp instead of its cert starting validity (NotBefore attribute) <!-- Describe the scope of your change - i.e. what the change does. --> **Benefits** <!-- What benefits will be realized by the code change? --> In case we are bringing our own certificate, if the certificate is created before sealed secret installation but applied after the installation, still the latest certificate used will be the certificate installed by sealed secret during its initialization instead of the latest secret certificate created. **Possible drawbacks** <!-- Describe any known limitations with your change --> **Applicable issues** <!-- Enter any applicable Issues here (You can reference an issue using #) --> - fixes # #1639 **Additional information** <!-- If there's anything else that's important and relevant to your pull request, mention that information here.--> --------- Signed-off-by: Jérôme GARCIA <[email protected]> Signed-off-by: Sybernatus <[email protected]> Signed-off-by: Jérôme GARCIA <[email protected]>
1 parent d87ba07 commit 30c1d2d

File tree

5 files changed

+45
-14
lines changed

5 files changed

+45
-14
lines changed

README.md

+12
Original file line numberDiff line numberDiff line change
@@ -620,6 +620,18 @@ It doesn't help that this feature has been historically called "key rotation", w
620620
Sealed secrets are not automatically rotated and old keys are not deleted
621621
when new keys are generated. Old `SealedSecret` resources can be still decrypted (that's because old sealing keys are not deleted).
622622

623+
### Key registry init priority order
624+
625+
When the controller starts, it will initialize the key registry. The most recent key is used to seal secrets. By default, this certificate is chosen based on the NotBefore attribute of the certificate. If you want to change the priority order of the keys in the registry, you can use the `--key-order-priority` flag.
626+
627+
The `--key-order-priority` flag accepts the following values:
628+
- `CertNotBefore`: (default) The key registry will be ordered based on the NotBefore attribute of the key certificate.
629+
- `SecretCreationTimestamp`: The key registry will be ordered based on the creation timestamp of the secret.
630+
631+
This flag influences the public key used to encrypt secrets and the certificate retrieved by `kubeseal --fetch-cert`.
632+
633+
634+
623635
### User secret rotation
624636

625637
The *sealing key* renewal and SealedSecret rotation are **not a substitute** for rotating your actual secrets.

cmd/controller/main.go

+4-2
Original file line numberDiff line numberDiff line change
@@ -20,8 +20,9 @@ import (
2020
)
2121

2222
const (
23-
flagEnvPrefix = "SEALED_SECRETS"
24-
defaultKeyRenewPeriod = 30 * 24 * time.Hour
23+
flagEnvPrefix = "SEALED_SECRETS"
24+
defaultKeyRenewPeriod = 30 * 24 * time.Hour
25+
defaultKeyOrderPriority = "CertNotBefore"
2526
)
2627

2728
var (
@@ -36,6 +37,7 @@ func bindControllerFlags(f *controller.Flags, fs *flag.FlagSet) {
3637
fs.StringVar(&f.MyCN, "my-cn", "", "Common name to be used as issuer/subject DN in generated certificate.")
3738

3839
fs.DurationVar(&f.KeyRenewPeriod, "key-renew-period", defaultKeyRenewPeriod, "New key generation period (automatic rotation deactivated if 0)")
40+
fs.StringVar(&f.KeyOrderPriority, "key-order-priority", defaultKeyOrderPriority, "Ordering of keys based on NotBefore certificate attribute or secret creation timestamp.")
3941
fs.BoolVar(&f.AcceptV1Data, "accept-deprecated-v1-data", true, "Accept deprecated V1 data field.")
4042
fs.StringVar(&f.KeyCutoffTime, "key-cutoff-time", "", "Create a new key if latest one is older than this cutoff time. RFC1123 format with numeric timezone expected.")
4143
fs.BoolVar(&f.NamespaceAll, "all-namespaces", true, "Scan all namespaces or only the current namespace (default=true).")

pkg/controller/controller_test.go

+1-1
Original file line numberDiff line numberDiff line change
@@ -219,7 +219,7 @@ func testKeyRegister(t *testing.T, ctx context.Context, clientset kubernetes.Int
219219
keyLabel := SealedSecretsKeyLabel
220220
prefix := "test-keys"
221221
testKeySize := 4096
222-
keyRegistry, err := initKeyRegistry(ctx, clientset, rand.Reader, ns, prefix, keyLabel, testKeySize)
222+
keyRegistry, err := initKeyRegistry(ctx, clientset, rand.Reader, ns, prefix, keyLabel, testKeySize, "CertNotBefore")
223223
if err != nil {
224224
t.Fatalf("failed to provision key registry: %v", err)
225225
}

pkg/controller/main.go

+20-3
Original file line numberDiff line numberDiff line change
@@ -40,6 +40,7 @@ type Flags struct {
4040
ValidFor time.Duration
4141
MyCN string
4242
KeyRenewPeriod time.Duration
43+
KeyOrderPriority string
4344
AcceptV1Data bool
4445
KeyCutoffTime string
4546
NamespaceAll bool
@@ -62,7 +63,7 @@ func initKeyPrefix(keyPrefix string) (string, error) {
6263
return validateKeyPrefix(keyPrefix)
6364
}
6465

65-
func initKeyRegistry(ctx context.Context, client kubernetes.Interface, r io.Reader, namespace, prefix, label string, keysize int) (*KeyRegistry, error) {
66+
func initKeyRegistry(ctx context.Context, client kubernetes.Interface, r io.Reader, namespace, prefix, label string, keysize int, keyOrderPriority string) (*KeyRegistry, error) {
6667
slog.Info("Searching for existing private keys")
6768
secretList, err := client.CoreV1().Secrets(namespace).List(ctx, metav1.ListOptions{
6869
LabelSelector: keySelector.String(),
@@ -88,14 +89,30 @@ func initKeyRegistry(ctx context.Context, client kubernetes.Interface, r io.Read
8889
if err != nil {
8990
slog.Error("Error reading key", "secret", secret.Name, "error", err)
9091
}
91-
if err := keyRegistry.registerNewKey(secret.Name, key, certs[0], certs[0].NotBefore); err != nil {
92+
93+
// Select ordering time based on the keyOrderPriority flag
94+
orderingTime := getKeyOrderPriority(keyOrderPriority, certs[0], secret)
95+
96+
if err := keyRegistry.registerNewKey(secret.Name, key, certs[0], orderingTime); err != nil {
9297
return nil, err
9398
}
9499
slog.Info("registered private key", "secretname", secret.Name)
95100
}
96101
return keyRegistry, nil
97102
}
98103

104+
func getKeyOrderPriority(keyOrderPriority string, cert *x509.Certificate, secret v1.Secret) time.Time {
105+
switch keyOrderPriority {
106+
case "CertNotBefore":
107+
return cert.NotBefore
108+
case "SecretCreationTimestamp":
109+
return secret.GetCreationTimestamp().Time
110+
default:
111+
slog.Error("Invalid keyOrderPriority. Use CertNotBefore or SecretCreationTimestamp", "keyOrderPriority", keyOrderPriority)
112+
}
113+
return cert.NotBefore
114+
}
115+
99116
func myNamespace() string {
100117
if ns := os.Getenv("POD_NAMESPACE"); ns != "" {
101118
return ns
@@ -169,7 +186,7 @@ func Main(f *Flags, version string) error {
169186
return err
170187
}
171188

172-
keyRegistry, err := initKeyRegistry(ctx, clientset, rand.Reader, myNs, prefix, SealedSecretsKeyLabel, f.KeySize)
189+
keyRegistry, err := initKeyRegistry(ctx, clientset, rand.Reader, myNs, prefix, SealedSecretsKeyLabel, f.KeySize, f.KeyOrderPriority)
173190
if err != nil {
174191
return err
175192
}

pkg/controller/main_test.go

+8-8
Original file line numberDiff line numberDiff line change
@@ -49,7 +49,7 @@ func TestInitKeyRegistry(t *testing.T) {
4949
client := fake.NewSimpleClientset()
5050
client.PrependReactor("create", "secrets", generateNameReactor)
5151

52-
registry, err := initKeyRegistry(ctx, client, rand, "namespace", "prefix", "label", 1024)
52+
registry, err := initKeyRegistry(ctx, client, rand, "namespace", "prefix", "label", 1024, "CertNotBefore")
5353
if err != nil {
5454
t.Fatalf("initKeyRegistry() returned err: %v", err)
5555
}
@@ -69,7 +69,7 @@ func TestInitKeyRegistry(t *testing.T) {
6969

7070
// Due to limitations of the fake client, we cannot test whether initKeyRegistry is able
7171
// to pick up existing keys
72-
_, err = initKeyRegistry(ctx, client, rand, "namespace", "prefix", "label", 1024)
72+
_, err = initKeyRegistry(ctx, client, rand, "namespace", "prefix", "label", 1024, "CertNotBefore")
7373
if err != nil {
7474
t.Fatalf("initKeyRegistry() returned err: %v", err)
7575
}
@@ -84,7 +84,7 @@ func TestInitKeyRotation(t *testing.T) {
8484
client := fake.NewSimpleClientset()
8585
client.PrependReactor("create", "secrets", generateNameReactor)
8686

87-
registry, err := initKeyRegistry(ctx, client, rand, "namespace", "prefix", "label", 1024)
87+
registry, err := initKeyRegistry(ctx, client, rand, "namespace", "prefix", "label", 1024, "CertNotBefore")
8888
if err != nil {
8989
t.Fatalf("initKeyRegistry() returned err: %v", err)
9090
}
@@ -125,7 +125,7 @@ func TestInitKeyRotationTick(t *testing.T) {
125125
client := fake.NewSimpleClientset()
126126
client.PrependReactor("create", "secrets", generateNameReactor)
127127

128-
registry, err := initKeyRegistry(ctx, client, rand, "namespace", "prefix", "label", 1024)
128+
registry, err := initKeyRegistry(ctx, client, rand, "namespace", "prefix", "label", 1024, "CertNotBefore")
129129
if err != nil {
130130
t.Fatalf("initKeyRegistry() returned err: %v", err)
131131
}
@@ -180,7 +180,7 @@ func TestReuseKey(t *testing.T) {
180180

181181
client.ClearActions()
182182

183-
registry, err := initKeyRegistry(ctx, client, rand, "namespace", "prefix", SealedSecretsKeyLabel, 1024)
183+
registry, err := initKeyRegistry(ctx, client, rand, "namespace", "prefix", SealedSecretsKeyLabel, 1024, "CertNotBefore")
184184
if err != nil {
185185
t.Fatalf("initKeyRegistry() returned err: %v", err)
186186
}
@@ -227,7 +227,7 @@ func TestRenewStaleKey(t *testing.T) {
227227
t.Errorf("writeKey() failed with: %v", err)
228228
}
229229

230-
registry, err := initKeyRegistry(ctx, client, rand, "namespace", "prefix", SealedSecretsKeyLabel, 1024)
230+
registry, err := initKeyRegistry(ctx, client, rand, "namespace", "prefix", SealedSecretsKeyLabel, 1024, "CertNotBefore")
231231
if err != nil {
232232
t.Fatalf("initKeyRegistry() returned err: %v", err)
233233
}
@@ -284,7 +284,7 @@ func TestKeyCutoff(t *testing.T) {
284284
t.Errorf("writeKey() failed with: %v", err)
285285
}
286286

287-
registry, err := initKeyRegistry(ctx, client, rand, "namespace", "prefix", SealedSecretsKeyLabel, 1024)
287+
registry, err := initKeyRegistry(ctx, client, rand, "namespace", "prefix", SealedSecretsKeyLabel, 1024, "CertNotBefore")
288288
if err != nil {
289289
t.Fatalf("initKeyRegistry() returned err: %v", err)
290290
}
@@ -351,7 +351,7 @@ func TestLegacySecret(t *testing.T) {
351351

352352
client.ClearActions()
353353

354-
registry, err := initKeyRegistry(ctx, client, rand, "namespace", "prefix", SealedSecretsKeyLabel, 1024)
354+
registry, err := initKeyRegistry(ctx, client, rand, "namespace", "prefix", SealedSecretsKeyLabel, 1024, "CertNotBefore")
355355
if err != nil {
356356
t.Fatalf("initKeyRegistry() returned err: %v", err)
357357
}

0 commit comments

Comments
 (0)