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

Commit

Permalink
Parameterize basic secret generation
Browse files Browse the repository at this point in the history
Enable users to specify character set and length for username
and password fields of generated basic auth secrets.

Signed-off-by: Nick Hale <[email protected]>
  • Loading branch information
njhale committed Oct 13, 2023
1 parent 5ec8609 commit 34969cc
Show file tree
Hide file tree
Showing 6 changed files with 72 additions and 25 deletions.
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
32 changes: 18 additions & 14 deletions pkg/secrets/generateSecret.go
Original file line number Diff line number Diff line change
Expand Up @@ -5,27 +5,31 @@ import (
"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 = "!#$%^&*_-=+"
)
const (
defaultLength = 54
defaultCharacterSet = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789!#$%^&*_-=+"
)

// Create a pool of characters to choose from
pool := uppercase + lowercase + numbers + special
// 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 pool
// 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(pool))))
index, err := rand.Int(rand.Reader, big.NewInt(int64(len(characterSet))))
if err != nil {
return "", err
}
secret[i] = pool[index.Int64()]
secret[i] = characterSet[index.Int64()]
}

return string(secret), nil
Expand Down
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(secretRef.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 34969cc

Please sign in to comment.