From 729b883dc822ebf952fd55ae12fd5b4c426d9c7c Mon Sep 17 00:00:00 2001 From: Nizamudeen Date: Sun, 5 Jan 2020 01:01:23 +0530 Subject: [PATCH] ceph: Generating a strong ceph dashboard password Replaced `math/rand` with more secure `crypto/rand` which will generate CSPRNG. Changed the length of dashboard password from 10 to 20 and included more special characters that can strengthen password. Passwords before this change: QoMmqLkaOf,8tqTyWF1sZ Passwords after this change: L{QZ@_c'Rl7$uvW:UHU1, fP-OjX`UVw0J0Ka/scS( Resolves: https://github.com/rook/rook/issues/4571 Signed-off-by: Nizamudeen --- pkg/operator/ceph/cluster/mgr/dashboard.go | 36 ++++++++++++------- .../ceph/cluster/mgr/dashboard_test.go | 9 +++-- 2 files changed, 29 insertions(+), 16 deletions(-) diff --git a/pkg/operator/ceph/cluster/mgr/dashboard.go b/pkg/operator/ceph/cluster/mgr/dashboard.go index ebf400b46..1754863f4 100755 --- a/pkg/operator/ceph/cluster/mgr/dashboard.go +++ b/pkg/operator/ceph/cluster/mgr/dashboard.go @@ -19,7 +19,7 @@ package mgr import ( "context" - "math/rand" + "crypto/rand" "os/exec" "strconv" "syscall" @@ -40,7 +40,7 @@ const ( dashboardPortHTTP = 7000 dashboardUsername = "admin" dashboardPasswordName = "rook-ceph-dashboard-password" - passwordLength = 10 + passwordLength = 20 passwordKeyName = "password" certAlreadyConfiguredErrorCode = 5 invalidArgErrorCode = int(syscall.EINVAL) @@ -50,10 +50,6 @@ var ( dashboardInitWaitTime = 5 * time.Second ) -func init() { - rand.Seed(time.Now().UnixNano()) -} - func (c *Cluster) configureDashboardService() error { dashboardService := c.makeDashboardService(AppName) if c.dashboard.Enabled { @@ -253,7 +249,10 @@ func (c *Cluster) getOrGenerateDashboardPassword() (string, error) { } // Generate a password - password := generatePassword(passwordLength) + password, err := generatePassword(passwordLength) + if err != nil { + return "", errors.Wrapf(err, "failed to generate password") + } // Store the keyring in a secret secrets := map[string][]byte{ @@ -276,15 +275,26 @@ func (c *Cluster) getOrGenerateDashboardPassword() (string, error) { return password, nil } -func generatePassword(length int) string { - const passwordChars = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789" - passwd := make([]byte, length) - for i := range passwd { - passwd[i] = passwordChars[rand.Intn(len(passwordChars))] +func generatePassword(length int) (string, error) { + const passwordChars = "!\"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\\]^_`abcdefghijklmnopqrstuvwxyz{|}~" + passwd, err := generateRandomBytes(length) + if err != nil { + return "", errors.Wrapf(err, "failed to generate password") } - return string(passwd) + for i, pass := range passwd { + passwd[i] = passwordChars[pass%byte(len(passwordChars))] + } + return string(passwd), nil } +// generateRandomBytes returns securely generated random bytes. +func generateRandomBytes(length int) ([]byte, error) { + bytes := make([]byte, length) + if _, err := rand.Read(bytes); err != nil { + return nil, errors.Wrapf(err, "failed to generate random bytes") + } + return bytes, nil +} func decodeSecret(secret *v1.Secret) (string, error) { password, ok := secret.Data[passwordKeyName] if !ok { diff --git a/pkg/operator/ceph/cluster/mgr/dashboard_test.go b/pkg/operator/ceph/cluster/mgr/dashboard_test.go index 820ca9598..c97f55dbd 100644 --- a/pkg/operator/ceph/cluster/mgr/dashboard_test.go +++ b/pkg/operator/ceph/cluster/mgr/dashboard_test.go @@ -33,14 +33,17 @@ import ( ) func TestGeneratePassword(t *testing.T) { - password := generatePassword(0) + password, err := generatePassword(0) + require.Nil(t, err) assert.Equal(t, "", password) - password = generatePassword(1) + password, err = generatePassword(1) + require.Nil(t, err) assert.Equal(t, 1, len(password)) logger.Infof("password: %s", password) - password = generatePassword(10) + password, err = generatePassword(10) + require.Nil(t, err) assert.Equal(t, 10, len(password)) logger.Infof("password: %s", password) }