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

Parameterize basic secret generation (#2192) #2242

Merged
merged 1 commit into from
Oct 15, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 3 additions & 3 deletions integration/secrets/testdata/generated/Acornfile
Original file line number Diff line number Diff line change
Expand Up @@ -7,9 +7,9 @@ jobs: {
cmd: ["sh", "-c", "echo -n $PASS > /run/secrets/output"]
}
cronpass: {
pass
schedule: "* * * * * "
}
pass
schedule: "* * * * * "
}
}

secrets: {
Expand Down
10 changes: 10 additions & 0 deletions pkg/appdefinition/app.acorn
Original file line number Diff line number Diff line change
Expand Up @@ -336,6 +336,16 @@
SecretBasicAuth: {
SecretBase
type: string == "basic"
params: {
// The character set used in the generated string
passwordCharacters: string || default "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789!#$%^&*_-=+"
// The length of the token to be generated
passwordLength: (int >= 0 && int <= 256) || default 16
// The character set used in the generated string
usernameCharacters: string || default "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789!#$%^&*_-=+"
// The length of the token to be generated
usernameLength: (int >= 0 && int <= 256) || default 8
}
data?: {
username?: string
password?: string
Expand Down
6 changes: 6 additions & 0 deletions pkg/appdefinition/appdefinition_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -1454,6 +1454,12 @@ secrets: {
}, appSpec.Secrets["explicit"])
assert.Equal(t, v1.Secret{
Type: "basic",
Params: v1.NewGenericMap(map[string]any{
"passwordCharacters": "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789!#$%^&*_-=+",
"passwordLength": int64(16),
"usernameCharacters": "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789!#$%^&*_-=+",
"usernameLength": int64(8),
}),
Data: map[string]string{
"username": "bardata",
"password": "barpass",
Expand Down
8 changes: 5 additions & 3 deletions pkg/controller/secrets/secret_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ import (
"github.com/acorn-io/runtime/pkg/labels"
"github.com/acorn-io/runtime/pkg/scheme"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
corev1 "k8s.io/api/core/v1"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
)
Expand Down Expand Up @@ -86,7 +87,8 @@ func TestBasic_Gen(t *testing.T) {
},
AppSpec: v1.AppSpec{
Secrets: map[string]v1.Secret{
"pass": {Type: "basic",
"pass": {
Type: "basic",
Data: map[string]string{
// cue will populate empty string if not sent
"username": "",
Expand All @@ -108,8 +110,8 @@ func TestBasic_Gen(t *testing.T) {
t.Fatal(err)
}

assert.Len(t, resp.Client.Created, 2)
assert.Len(t, resp.Collected, 2)
require.Len(t, resp.Client.Created, 2)
thedadams marked this conversation as resolved.
Show resolved Hide resolved
require.Len(t, resp.Collected, 2)

secret := resp.Client.Created[0].(*corev1.Secret)
assert.Equal(t, "pass", secret.Labels[labels.AcornSecretName])
Expand Down
36 changes: 36 additions & 0 deletions pkg/secrets/generate.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
package secrets

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

const (
defaultLength = 54
defaultCharacterSet = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789!#$%^&*_-=+"
)

// GenerateRandomSecret generates a random secret with the specified length and character set.
// If the length is less than 1, a default value of 54 will be used.
// If the character set is empty, a default value of "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789!#$%^&*_-=+"
// will be used.
func GenerateRandomSecret(length int, characterSet string) (string, error) {
if length < 1 {
length = defaultLength
}
if characterSet == "" {
characterSet = defaultCharacterSet
}

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

return string(secret), nil
}
32 changes: 0 additions & 32 deletions pkg/secrets/generateSecret.go

This file was deleted.

37 changes: 31 additions & 6 deletions pkg/secrets/secret.go
Original file line number Diff line number Diff line change
Expand Up @@ -249,15 +249,40 @@ func generateBasic(req router.Request, appInstance *v1.AppInstance, secretName s
Type: v1.SecretTypeBasic,
}

for i, key := range []string{corev1.BasicAuthUsernameKey, corev1.BasicAuthPasswordKey} {
if len(secret.Data[key]) == 0 {
v, err := GenerateRandomSecret(54)
v = v[:(i+1)*8]
if err != nil {
for _, keys := range []struct {
dataKey, lengthKey, charactersKey string
}{
{
dataKey: corev1.BasicAuthUsernameKey,
lengthKey: "usernameLength",
charactersKey: "usernameCharacters",
},
{
dataKey: corev1.BasicAuthPasswordKey,
lengthKey: "passwordLength",
charactersKey: "passwordCharacters",
},
} {
if len(secret.Data[keys.dataKey]) > 0 {
// Explicitly set by user, don't generate
continue
}

var length int64
if lengthParam, ok := secretRef.Params.GetData()[keys.lengthKey]; ok {
g-linville marked this conversation as resolved.
Show resolved Hide resolved
var err error
if length, err = convert.ToNumber(lengthParam); err != nil {
return nil, err
}
secret.Data[key] = []byte(v)
}
characters := convert.ToString(secretRef.Params.GetData()[keys.charactersKey])

v, err := GenerateRandomSecret(int(length), characters)
if err != nil {
return nil, err
}

secret.Data[keys.dataKey] = []byte(v)
}

return updateOrCreate(req, existing, secret)
Expand Down
4 changes: 2 additions & 2 deletions pkg/server/registry/apigroups/acorn/secrets/strategy.go
Original file line number Diff line number Diff line change
Expand Up @@ -18,12 +18,12 @@ func (d *defaultSecretGenerateStrategy) Create(ctx context.Context, object types
// 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)
username, err := sec.GenerateRandomSecret(8, "")
if err != nil {
return nil, err
}

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