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

Commit

Permalink
Merge pull request #2242 from njhale/parameterize-basic-secret-gen
Browse files Browse the repository at this point in the history
Parameterize basic secret generation (#2192)
  • Loading branch information
njhale authored Oct 15, 2023
2 parents 28f2b00 + aa650df commit bdd8d40
Show file tree
Hide file tree
Showing 8 changed files with 93 additions and 46 deletions.
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)
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 {
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

0 comments on commit bdd8d40

Please sign in to comment.