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

Commit

Permalink
feat: Set defaults for empty basic secrets (#347) (#1808)
Browse files Browse the repository at this point in the history
Signed-off-by: pratikjagrut <26519653+pratikjagrut@users.noreply.github.com>
  • Loading branch information
pratikjagrut committed Jul 7, 2023
1 parent 05d349b commit a2b288d
Show file tree
Hide file tree
Showing 5 changed files with 102 additions and 5 deletions.
23 changes: 23 additions & 0 deletions integration/secrets/secret_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ import (
"github.com/stretchr/testify/assert"
appsv1 "k8s.io/api/apps/v1"
corev1 "k8s.io/api/core/v1"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
)

const (
Expand Down Expand Up @@ -255,3 +256,25 @@ func TestMultiKeyDecryptionEndToEnd(t *testing.T) {

assert.Equal(t, plainTextData, string(secret.Data["key"]))
}

func TestCreateDefaultSecret(t *testing.T) {
c, ns := helper.ClientAndNamespace(t)
kc, err := c.GetClient()
assert.NoError(t, err)
secName := "test-secret"
secret := &apiv1.Secret{
Type: "basic",
ObjectMeta: metav1.ObjectMeta{
Name: secName,
Namespace: ns.Name,
},
}
err = kc.Create(context.Background(), secret)
assert.NoError(t, err)
gs := &apiv1.Secret{}
err = kc.Get(context.Background(), router.Key(ns.Name, secName), gs)
assert.NoError(t, err)
assert.NotEmpty(t, gs.Keys)
assert.Contains(t, gs.Keys, "username")
assert.Contains(t, gs.Keys, "password")
}
32 changes: 32 additions & 0 deletions pkg/secrets/generateSecret.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
package secrets

import (
"crypto/rand"
"math/big"
)

// GenerateRandomSecret generates a random secret with the specified length
// using a mix of uppercase letters, lowercase letters, numbers, and special characters.
func GenerateRandomSecret(length int) (string, error) {
const (
uppercase = "ABCDEFGHJKLMNPQRSTUVWXYZ"
lowercase = "abcdefghijkmnopqrstuvwxyz"
numbers = "23456789"
special = "!@#$%^&*_-=+"
)

// Create a pool of characters to choose from
pool := uppercase + lowercase + numbers + special

// Generate a random secret by randomly selecting characters from the pool
secret := make([]byte, length)
for i := 0; i < length; i++ {
index, err := rand.Int(rand.Reader, big.NewInt(int64(len(pool))))
if err != nil {
return "", err
}
secret[i] = pool[index.Int64()]
}

return string(secret), nil
}
5 changes: 2 additions & 3 deletions pkg/secrets/secret.go
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,6 @@ import (
"github.com/acorn-io/runtime/pkg/system"
"github.com/rancher/wrangler/pkg/data/convert"
"github.com/rancher/wrangler/pkg/merr"
"github.com/rancher/wrangler/pkg/randomtoken"
"golang.org/x/exp/maps"
corev1 "k8s.io/api/core/v1"
"k8s.io/apimachinery/pkg/api/equality"
Expand Down Expand Up @@ -252,15 +251,15 @@ func generateBasic(req router.Request, appInstance *v1.AppInstance, secretName s

for i, key := range []string{corev1.BasicAuthUsernameKey, corev1.BasicAuthPasswordKey} {
if len(secret.Data[key]) == 0 {
// TODO: Improve with more characters (special, upper/lowercase, etc)
v, err := randomtoken.Generate()
v, err := GenerateRandomSecret(54)
v = v[:(i+1)*8]
if err != nil {
return nil, err
}
secret.Data[key] = []byte(v)
}
}

return updateOrCreate(req, existing, secret)
}

Expand Down
6 changes: 4 additions & 2 deletions pkg/server/registry/apigroups/acorn/secrets/storage.go
Original file line number Diff line number Diff line change
Expand Up @@ -19,11 +19,13 @@ func NewStorage(c kclient.WithWatch, middlewares ...middleware.CompleteStrategy)
}, remote.NewRemote(&corev1.Secret{}, c))
remoteResource := publicname.NewStrategy(translated)
remoteResource = middleware.ForCompleteStrategy(remoteResource, middlewares...)

defaultSecret := &defaultSecretGenerateStrategy{
strategy: remoteResource,
}
validator := &Validator{}

return stores.NewBuilder(c.Scheme(), &apiv1.Secret{}).
WithCreate(remoteResource).
WithCreate(defaultSecret).
WithGet(remoteResource).
WithList(remoteResource).
WithUpdate(remoteResource).
Expand Down
41 changes: 41 additions & 0 deletions pkg/server/registry/apigroups/acorn/secrets/strategy.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
package secrets

import (
"context"

"github.com/acorn-io/mink/pkg/strategy"
"github.com/acorn-io/mink/pkg/types"
apiv1 "github.com/acorn-io/runtime/pkg/apis/api.acorn.io/v1"
sec "github.com/acorn-io/runtime/pkg/secrets"
)

type defaultSecretGenerateStrategy struct {
strategy strategy.CompleteStrategy
}

func (d *defaultSecretGenerateStrategy) Create(ctx context.Context, object types.Object) (types.Object, error) {
secret := object.(*apiv1.Secret)
// If the secret is of type 'basic' and data is empty,
// default username and password values are set.
if secret.Type == "basic" && secret.Data == nil {
username, err := sec.GenerateRandomSecret(8)
if err != nil {
return nil, err
}

password, err := sec.GenerateRandomSecret(16)
if err != nil {
return nil, err
}

secret.Data = map[string][]byte{}

secret.Data["username"] = []byte(username)
secret.Data["password"] = []byte(password)
}
return d.strategy.Create(ctx, secret)
}

func (d *defaultSecretGenerateStrategy) New() types.Object {
return &apiv1.Secret{}
}

0 comments on commit a2b288d

Please sign in to comment.