add charset to secret generation
All checks were successful
continuous-integration/drone/pr Build is passing
All checks were successful
continuous-integration/drone/pr Build is passing
This commit is contained in:
@ -33,6 +33,10 @@ type Secret struct {
|
|||||||
// variable. For Example:
|
// variable. For Example:
|
||||||
// SECRET_FOO=v1 # length=12
|
// SECRET_FOO=v1 # length=12
|
||||||
Length int
|
Length int
|
||||||
|
// Charset comes from the charset modifier at the secret version environment
|
||||||
|
// variable. For Example:
|
||||||
|
// SECRET_FOO=v1 # charset=default,special
|
||||||
|
Charset string
|
||||||
// RemoteName is the name of the secret on the server. For example:
|
// RemoteName is the name of the secret on the server. For example:
|
||||||
// name: ${STACK_NAME}_test_pass_two_${SECRET_TEST_PASS_TWO_VERSION}
|
// name: ${STACK_NAME}_test_pass_two_${SECRET_TEST_PASS_TWO_VERSION}
|
||||||
// With the following:
|
// With the following:
|
||||||
@ -44,11 +48,11 @@ type Secret struct {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// GeneratePasswords generates passwords.
|
// GeneratePasswords generates passwords.
|
||||||
func GeneratePasswords(count, length uint) ([]string, error) {
|
func GeneratePasswords(count, length uint, charset string) ([]string, error) {
|
||||||
passwords, err := passgen.GeneratePasswords(
|
passwords, err := passgen.GeneratePasswords(
|
||||||
count,
|
count,
|
||||||
length,
|
length,
|
||||||
passgen.AlphabetDefault,
|
charset,
|
||||||
)
|
)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
@ -150,6 +154,9 @@ func ReadSecretsConfig(appEnvPath string, composeFiles []string, stackName strin
|
|||||||
}
|
}
|
||||||
value.Length = length
|
value.Length = length
|
||||||
}
|
}
|
||||||
|
|
||||||
|
charset := modifierValues["charset"]
|
||||||
|
value.Charset = resolveCharset(charset)
|
||||||
break
|
break
|
||||||
}
|
}
|
||||||
secretValues[secretId] = value
|
secretValues[secretId] = value
|
||||||
@ -158,6 +165,22 @@ func ReadSecretsConfig(appEnvPath string, composeFiles []string, stackName strin
|
|||||||
return secretValues, nil
|
return secretValues, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// resolveCharset sets the passgen Alphabet required for a secret
|
||||||
|
func resolveCharset(input string) string {
|
||||||
|
switch strings.ToLower(input) {
|
||||||
|
case "special":
|
||||||
|
return passgen.AlphabetSpecial
|
||||||
|
case "safespecial":
|
||||||
|
return "!@#%^&*_-+="
|
||||||
|
case "default,special", "special,default":
|
||||||
|
return passgen.AlphabetDefault + passgen.AlphabetSpecial
|
||||||
|
case "default,safespecial", "safespecial,default":
|
||||||
|
return passgen.AlphabetDefault + "!@#%^&*_-+="
|
||||||
|
default:
|
||||||
|
return passgen.AlphabetDefault // Fallback to default
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// GenerateSecrets generates secrets locally and sends them to a remote server for storage.
|
// GenerateSecrets generates secrets locally and sends them to a remote server for storage.
|
||||||
func GenerateSecrets(cl *dockerClient.Client, secrets map[string]Secret, server string) (map[string]string, error) {
|
func GenerateSecrets(cl *dockerClient.Client, secrets map[string]Secret, server string) (map[string]string, error) {
|
||||||
secretsGenerated := map[string]string{}
|
secretsGenerated := map[string]string{}
|
||||||
@ -173,7 +196,7 @@ func GenerateSecrets(cl *dockerClient.Client, secrets map[string]Secret, server
|
|||||||
log.Debugf("attempting to generate and store %s on %s", secret.RemoteName, server)
|
log.Debugf("attempting to generate and store %s on %s", secret.RemoteName, server)
|
||||||
|
|
||||||
if secret.Length > 0 {
|
if secret.Length > 0 {
|
||||||
passwords, err := GeneratePasswords(1, uint(secret.Length))
|
passwords, err := GeneratePasswords(1, uint(secret.Length), secret.Charset)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
ch <- err
|
ch <- err
|
||||||
return
|
return
|
||||||
|
@ -17,16 +17,37 @@ func TestReadSecretsConfig(t *testing.T) {
|
|||||||
assert.Equal(t, "test_example_com_test_pass_one_v2", secretsFromConfig["test_pass_one"].RemoteName)
|
assert.Equal(t, "test_example_com_test_pass_one_v2", secretsFromConfig["test_pass_one"].RemoteName)
|
||||||
assert.Equal(t, "v2", secretsFromConfig["test_pass_one"].Version)
|
assert.Equal(t, "v2", secretsFromConfig["test_pass_one"].Version)
|
||||||
assert.Equal(t, 0, secretsFromConfig["test_pass_one"].Length)
|
assert.Equal(t, 0, secretsFromConfig["test_pass_one"].Length)
|
||||||
|
assert.Equal(t, "abcdefghijkmnopqrstuvwxyzABCDEFGHJKLMNPQRSTUVWXYZ23456789", secretsFromConfig["test_pass_one"].Charset)
|
||||||
|
|
||||||
// Has a length modifier
|
// Has a length modifier
|
||||||
assert.Equal(t, "test_example_com_test_pass_two_v1", secretsFromConfig["test_pass_two"].RemoteName)
|
assert.Equal(t, "test_example_com_test_pass_two_v1", secretsFromConfig["test_pass_two"].RemoteName)
|
||||||
assert.Equal(t, "v1", secretsFromConfig["test_pass_two"].Version)
|
assert.Equal(t, "v1", secretsFromConfig["test_pass_two"].Version)
|
||||||
assert.Equal(t, 10, secretsFromConfig["test_pass_two"].Length)
|
assert.Equal(t, 10, secretsFromConfig["test_pass_two"].Length)
|
||||||
|
assert.Equal(t, "abcdefghijkmnopqrstuvwxyzABCDEFGHJKLMNPQRSTUVWXYZ23456789", secretsFromConfig["test_pass_two"].Charset)
|
||||||
|
|
||||||
// Secret name does not include the secret id
|
// Secret name does not include the secret id
|
||||||
assert.Equal(t, "test_example_com_pass_three_v2", secretsFromConfig["test_pass_three"].RemoteName)
|
assert.Equal(t, "test_example_com_pass_three_v2", secretsFromConfig["test_pass_three"].RemoteName)
|
||||||
assert.Equal(t, "v2", secretsFromConfig["test_pass_three"].Version)
|
assert.Equal(t, "v2", secretsFromConfig["test_pass_three"].Version)
|
||||||
assert.Equal(t, 0, secretsFromConfig["test_pass_three"].Length)
|
assert.Equal(t, 0, secretsFromConfig["test_pass_three"].Length)
|
||||||
|
assert.Equal(t, "abcdefghijkmnopqrstuvwxyzABCDEFGHJKLMNPQRSTUVWXYZ23456789", secretsFromConfig["test_pass_three"].Charset)
|
||||||
|
|
||||||
|
// Has a length modifier and a charset=default,safespecial modifier
|
||||||
|
assert.Equal(t, "test_example_com_test_pass_four_v1", secretsFromConfig["test_pass_four"].RemoteName)
|
||||||
|
assert.Equal(t, "v1", secretsFromConfig["test_pass_four"].Version)
|
||||||
|
assert.Equal(t, 12, secretsFromConfig["test_pass_four"].Length)
|
||||||
|
assert.Equal(t, "abcdefghijkmnopqrstuvwxyzABCDEFGHJKLMNPQRSTUVWXYZ23456789!@#%^&*_-+=", secretsFromConfig["test_pass_four"].Charset)
|
||||||
|
|
||||||
|
// Has a length modifier and a charset=default,special modifier
|
||||||
|
assert.Equal(t, "test_example_com_test_pass_five_v1", secretsFromConfig["test_pass_five"].RemoteName)
|
||||||
|
assert.Equal(t, "v1", secretsFromConfig["test_pass_five"].Version)
|
||||||
|
assert.Equal(t, 12, secretsFromConfig["test_pass_five"].Length)
|
||||||
|
assert.Equal(t, "abcdefghijkmnopqrstuvwxyzABCDEFGHJKLMNPQRSTUVWXYZ23456789!@#$%^&*_-+=", secretsFromConfig["test_pass_five"].Charset)
|
||||||
|
|
||||||
|
// Has only a charset=default,special modifier, which gets setted but ignored in the generation
|
||||||
|
assert.Equal(t, "test_example_com_test_pass_six_v1", secretsFromConfig["test_pass_six"].RemoteName)
|
||||||
|
assert.Equal(t, "v1", secretsFromConfig["test_pass_six"].Version)
|
||||||
|
assert.Equal(t, 0, secretsFromConfig["test_pass_six"].Length)
|
||||||
|
assert.Equal(t, "abcdefghijkmnopqrstuvwxyzABCDEFGHJKLMNPQRSTUVWXYZ23456789!@#$%^&*_-+=", secretsFromConfig["test_pass_six"].Charset)
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestReadSecretsConfigWithLongDomain(t *testing.T) {
|
func TestReadSecretsConfigWithLongDomain(t *testing.T) {
|
||||||
|
@ -1,3 +1,6 @@
|
|||||||
SECRET_TEST_PASS_ONE_VERSION=v2
|
SECRET_TEST_PASS_ONE_VERSION=v2
|
||||||
SECRET_TEST_PASS_TWO_VERSION=v1 # length=10
|
SECRET_TEST_PASS_TWO_VERSION=v1 # length=10
|
||||||
SECRET_TEST_PASS_THREE_VERSION=v2
|
SECRET_TEST_PASS_THREE_VERSION=v2
|
||||||
|
SECRET_TEST_PASS_FOUR_VERSION=v1 # length=12 charset=default,safespecial
|
||||||
|
SECRET_TEST_PASS_FIVE_VERSION=v1 # length=12 charset=default,special
|
||||||
|
SECRET_TEST_PASS_SIX_VERSION=v1 # charset=default,special
|
||||||
|
@ -8,6 +8,9 @@ services:
|
|||||||
- test_pass_one
|
- test_pass_one
|
||||||
- test_pass_two
|
- test_pass_two
|
||||||
- test_pass_three
|
- test_pass_three
|
||||||
|
- test_pass_four
|
||||||
|
- test_pass_five
|
||||||
|
- test_pass_six
|
||||||
|
|
||||||
secrets:
|
secrets:
|
||||||
test_pass_one:
|
test_pass_one:
|
||||||
@ -19,3 +22,12 @@ secrets:
|
|||||||
test_pass_three:
|
test_pass_three:
|
||||||
external: true
|
external: true
|
||||||
name: ${STACK_NAME}_pass_three_${SECRET_TEST_PASS_THREE_VERSION} # secretId and name don't match
|
name: ${STACK_NAME}_pass_three_${SECRET_TEST_PASS_THREE_VERSION} # secretId and name don't match
|
||||||
|
test_pass_four:
|
||||||
|
external: true
|
||||||
|
name: ${STACK_NAME}_test_pass_four_${SECRET_TEST_PASS_FOUR_VERSION}
|
||||||
|
test_pass_five:
|
||||||
|
external: true
|
||||||
|
name: ${STACK_NAME}_test_pass_five_${SECRET_TEST_PASS_FIVE_VERSION}
|
||||||
|
test_pass_six:
|
||||||
|
external: true
|
||||||
|
name: ${STACK_NAME}_test_pass_six_${SECRET_TEST_PASS_SIX_VERSION}
|
||||||
|
Reference in New Issue
Block a user