minio/cmd/credential.go
Harshavardhana 31dff87903 Honor envs properly for access and secret key. (#3703)
Also changes the behavior of `secretKeyHash` which is
not necessary to be sent over the network, each node
has its own secretKeyHash to validate.

Fixes #3696
Partial(fix) #3700 (More changes needed with some code cleanup)
2017-02-07 12:51:43 -08:00

140 lines
4 KiB
Go

/*
* Minio Cloud Storage, (C) 2015, 2016 Minio, Inc.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package cmd
import (
"crypto/rand"
"encoding/base64"
"os"
"github.com/minio/mc/pkg/console"
"golang.org/x/crypto/bcrypt"
)
const (
accessKeyMinLen = 5
accessKeyMaxLen = 20
secretKeyMinLen = 8
secretKeyMaxLen = 40
alphaNumericTable = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ"
alphaNumericTableLen = byte(len(alphaNumericTable))
)
func mustGetAccessKey() string {
keyBytes := make([]byte, accessKeyMaxLen)
if _, err := rand.Read(keyBytes); err != nil {
console.Fatalf("Unable to generate access key. Err: %s.\n", err)
}
for i := 0; i < accessKeyMaxLen; i++ {
keyBytes[i] = alphaNumericTable[keyBytes[i]%alphaNumericTableLen]
}
return string(keyBytes)
}
func mustGetSecretKey() string {
keyBytes := make([]byte, secretKeyMaxLen)
if _, err := rand.Read(keyBytes); err != nil {
console.Fatalf("Unable to generate secret key. Err: %s.\n", err)
}
return string([]byte(base64.StdEncoding.EncodeToString(keyBytes))[:secretKeyMaxLen])
}
// isAccessKeyValid - validate access key for right length.
func isAccessKeyValid(accessKey string) bool {
return len(accessKey) >= accessKeyMinLen && len(accessKey) <= accessKeyMaxLen
}
// isSecretKeyValid - validate secret key for right length.
func isSecretKeyValid(secretKey string) bool {
return len(secretKey) >= secretKeyMinLen && len(secretKey) <= secretKeyMaxLen
}
// credential container for access and secret keys.
type credential struct {
AccessKey string `json:"accessKey,omitempty"`
SecretKey string `json:"secretKey,omitempty"`
secretKeyHash []byte
}
// Generate a bcrypt hashed key for input secret key.
func mustGetHashedSecretKey(secretKey string) []byte {
hashedSecretKey, err := bcrypt.GenerateFromPassword([]byte(secretKey), bcrypt.DefaultCost)
if err != nil {
console.Fatalf("Unable to generate secret hash for secret key. Err: %s.\n", err)
}
return hashedSecretKey
}
// Initialize a new credential object
func newCredential() credential {
return newCredentialWithKeys(mustGetAccessKey(), mustGetSecretKey())
}
func newCredentialWithKeys(accessKey, secretKey string) credential {
secretHash := mustGetHashedSecretKey(secretKey)
return credential{accessKey, secretKey, secretHash}
}
// Validate incoming auth keys.
func validateAuthKeys(accessKey, secretKey string) error {
// Validate the env values before proceeding.
if !isAccessKeyValid(accessKey) {
return errInvalidAccessKeyLength
}
if !isSecretKeyValid(secretKey) {
return errInvalidSecretKeyLength
}
return nil
}
// Variant of getCredentialFromEnv but upon error fails right here.
func mustGetCredentialFromEnv() credential {
creds, err := getCredentialFromEnv()
if err != nil {
console.Fatalf("Unable to load credentials from environment. Err: %s.\n", err)
}
return creds
}
// Converts accessKey and secretKeys into credential object which
// contains bcrypt secret key hash for future validation.
func getCredentialFromEnv() (credential, error) {
// Fetch access keys from environment variables and update the config.
accessKey := os.Getenv("MINIO_ACCESS_KEY")
secretKey := os.Getenv("MINIO_SECRET_KEY")
// Envs are set globally.
globalIsEnvCreds = accessKey != "" && secretKey != ""
if globalIsEnvCreds {
// Validate the env values before proceeding.
if err := validateAuthKeys(accessKey, secretKey); err != nil {
return credential{}, err
}
// Return credential object.
return newCredentialWithKeys(accessKey, secretKey), nil
}
return credential{}, nil
}