Skip to content
This repository was archived by the owner on Mar 16, 2024. It is now read-only.

Commit a2b288d

Browse files
authored
feat: Set defaults for empty basic secrets (#347) (#1808)
Signed-off-by: pratikjagrut <[email protected]>
1 parent 05d349b commit a2b288d

File tree

5 files changed

+102
-5
lines changed

5 files changed

+102
-5
lines changed

integration/secrets/secret_test.go

+23
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@ import (
1616
"github.com/stretchr/testify/assert"
1717
appsv1 "k8s.io/api/apps/v1"
1818
corev1 "k8s.io/api/core/v1"
19+
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
1920
)
2021

2122
const (
@@ -255,3 +256,25 @@ func TestMultiKeyDecryptionEndToEnd(t *testing.T) {
255256

256257
assert.Equal(t, plainTextData, string(secret.Data["key"]))
257258
}
259+
260+
func TestCreateDefaultSecret(t *testing.T) {
261+
c, ns := helper.ClientAndNamespace(t)
262+
kc, err := c.GetClient()
263+
assert.NoError(t, err)
264+
secName := "test-secret"
265+
secret := &apiv1.Secret{
266+
Type: "basic",
267+
ObjectMeta: metav1.ObjectMeta{
268+
Name: secName,
269+
Namespace: ns.Name,
270+
},
271+
}
272+
err = kc.Create(context.Background(), secret)
273+
assert.NoError(t, err)
274+
gs := &apiv1.Secret{}
275+
err = kc.Get(context.Background(), router.Key(ns.Name, secName), gs)
276+
assert.NoError(t, err)
277+
assert.NotEmpty(t, gs.Keys)
278+
assert.Contains(t, gs.Keys, "username")
279+
assert.Contains(t, gs.Keys, "password")
280+
}

pkg/secrets/generateSecret.go

+32
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,32 @@
1+
package secrets
2+
3+
import (
4+
"crypto/rand"
5+
"math/big"
6+
)
7+
8+
// GenerateRandomSecret generates a random secret with the specified length
9+
// using a mix of uppercase letters, lowercase letters, numbers, and special characters.
10+
func GenerateRandomSecret(length int) (string, error) {
11+
const (
12+
uppercase = "ABCDEFGHJKLMNPQRSTUVWXYZ"
13+
lowercase = "abcdefghijkmnopqrstuvwxyz"
14+
numbers = "23456789"
15+
special = "!@#$%^&*_-=+"
16+
)
17+
18+
// Create a pool of characters to choose from
19+
pool := uppercase + lowercase + numbers + special
20+
21+
// Generate a random secret by randomly selecting characters from the pool
22+
secret := make([]byte, length)
23+
for i := 0; i < length; i++ {
24+
index, err := rand.Int(rand.Reader, big.NewInt(int64(len(pool))))
25+
if err != nil {
26+
return "", err
27+
}
28+
secret[i] = pool[index.Int64()]
29+
}
30+
31+
return string(secret), nil
32+
}

pkg/secrets/secret.go

+2-3
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,6 @@ import (
2222
"github.com/acorn-io/runtime/pkg/system"
2323
"github.com/rancher/wrangler/pkg/data/convert"
2424
"github.com/rancher/wrangler/pkg/merr"
25-
"github.com/rancher/wrangler/pkg/randomtoken"
2625
"golang.org/x/exp/maps"
2726
corev1 "k8s.io/api/core/v1"
2827
"k8s.io/apimachinery/pkg/api/equality"
@@ -252,15 +251,15 @@ func generateBasic(req router.Request, appInstance *v1.AppInstance, secretName s
252251

253252
for i, key := range []string{corev1.BasicAuthUsernameKey, corev1.BasicAuthPasswordKey} {
254253
if len(secret.Data[key]) == 0 {
255-
// TODO: Improve with more characters (special, upper/lowercase, etc)
256-
v, err := randomtoken.Generate()
254+
v, err := GenerateRandomSecret(54)
257255
v = v[:(i+1)*8]
258256
if err != nil {
259257
return nil, err
260258
}
261259
secret.Data[key] = []byte(v)
262260
}
263261
}
262+
264263
return updateOrCreate(req, existing, secret)
265264
}
266265

pkg/server/registry/apigroups/acorn/secrets/storage.go

+4-2
Original file line numberDiff line numberDiff line change
@@ -19,11 +19,13 @@ func NewStorage(c kclient.WithWatch, middlewares ...middleware.CompleteStrategy)
1919
}, remote.NewRemote(&corev1.Secret{}, c))
2020
remoteResource := publicname.NewStrategy(translated)
2121
remoteResource = middleware.ForCompleteStrategy(remoteResource, middlewares...)
22-
22+
defaultSecret := &defaultSecretGenerateStrategy{
23+
strategy: remoteResource,
24+
}
2325
validator := &Validator{}
2426

2527
return stores.NewBuilder(c.Scheme(), &apiv1.Secret{}).
26-
WithCreate(remoteResource).
28+
WithCreate(defaultSecret).
2729
WithGet(remoteResource).
2830
WithList(remoteResource).
2931
WithUpdate(remoteResource).
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,41 @@
1+
package secrets
2+
3+
import (
4+
"context"
5+
6+
"github.com/acorn-io/mink/pkg/strategy"
7+
"github.com/acorn-io/mink/pkg/types"
8+
apiv1 "github.com/acorn-io/runtime/pkg/apis/api.acorn.io/v1"
9+
sec "github.com/acorn-io/runtime/pkg/secrets"
10+
)
11+
12+
type defaultSecretGenerateStrategy struct {
13+
strategy strategy.CompleteStrategy
14+
}
15+
16+
func (d *defaultSecretGenerateStrategy) Create(ctx context.Context, object types.Object) (types.Object, error) {
17+
secret := object.(*apiv1.Secret)
18+
// If the secret is of type 'basic' and data is empty,
19+
// default username and password values are set.
20+
if secret.Type == "basic" && secret.Data == nil {
21+
username, err := sec.GenerateRandomSecret(8)
22+
if err != nil {
23+
return nil, err
24+
}
25+
26+
password, err := sec.GenerateRandomSecret(16)
27+
if err != nil {
28+
return nil, err
29+
}
30+
31+
secret.Data = map[string][]byte{}
32+
33+
secret.Data["username"] = []byte(username)
34+
secret.Data["password"] = []byte(password)
35+
}
36+
return d.strategy.Create(ctx, secret)
37+
}
38+
39+
func (d *defaultSecretGenerateStrategy) New() types.Object {
40+
return &apiv1.Secret{}
41+
}

0 commit comments

Comments
 (0)