mirror of
https://github.com/minio/minio.git
synced 2025-11-20 01:50:24 -05:00
kms: encrypt IAM/config data with the KMS (#12041)
This commit changes the config/IAM encryption process. Instead of encrypting config data (users, policies etc.) with the root credentials MinIO now encrypts this data with a KMS - if configured. Therefore, this PR moves the MinIO-KMS configuration (via env. variables) to a "top-level" configuration. The KMS configuration cannot be stored in the config file since it is used to decrypt the config file in the first place. As a consequence, this commit also removes support for Hashicorp Vault - which has been deprecated anyway. Signed-off-by: Andreas Auernhammer <aead@mail.de>
This commit is contained in:
committed by
Harshavardhana
parent
e05e14309c
commit
3455f786fa
@@ -1,3 +1,5 @@
|
||||
// +build fips
|
||||
|
||||
// MinIO Cloud Storage, (C) 2021 MinIO, Inc.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
@@ -12,8 +14,6 @@
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
//+build fips
|
||||
|
||||
package fips
|
||||
|
||||
import (
|
||||
@@ -37,6 +37,6 @@ func cipherSuitesTLS() []uint16 {
|
||||
}
|
||||
}
|
||||
|
||||
func ellipticCurvesTLS() []tls.Curve {
|
||||
func ellipticCurvesTLS() []tls.CurveID {
|
||||
return []tls.CurveID{tls.CurveP256}
|
||||
}
|
||||
|
||||
@@ -52,7 +52,7 @@ func Parse(s string) (KMS, error) {
|
||||
}
|
||||
|
||||
// New returns a single-key KMS that derives new DEKs from the
|
||||
// given key.
|
||||
// given key. The given key must always be 32 bytes.
|
||||
func New(keyID string, key []byte) (KMS, error) {
|
||||
if len(key) != 32 {
|
||||
return nil, errors.New("kms: invalid key length " + strconv.Itoa(len(key)))
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* MinIO Cloud Storage, (C) 2018 MinIO, Inc.
|
||||
* MinIO Cloud Storage, (C) 2018-2021 MinIO, Inc.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
@@ -19,21 +19,18 @@ package madmin
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"crypto/sha256"
|
||||
"errors"
|
||||
"io"
|
||||
"io/ioutil"
|
||||
|
||||
"github.com/minio/minio/pkg/argon2"
|
||||
"github.com/minio/minio/pkg/fips"
|
||||
"github.com/secure-io/sio-go"
|
||||
"github.com/secure-io/sio-go/sioutil"
|
||||
"golang.org/x/crypto/pbkdf2"
|
||||
)
|
||||
|
||||
var idKey func([]byte, []byte, []byte, []byte, uint32) []byte
|
||||
|
||||
func init() {
|
||||
idKey = argon2.NewIDKey(1, 64*1024, 4)
|
||||
}
|
||||
|
||||
// EncryptData encrypts the data with an unique key
|
||||
// derived from password using the Argon2id PBKDF.
|
||||
//
|
||||
@@ -43,24 +40,35 @@ func init() {
|
||||
func EncryptData(password string, data []byte) ([]byte, error) {
|
||||
salt := sioutil.MustRandom(32)
|
||||
|
||||
// Derive an unique 256 bit key from the password and the random salt.
|
||||
key := idKey([]byte(password), salt, nil, nil, 32)
|
||||
|
||||
var (
|
||||
id byte
|
||||
err error
|
||||
stream *sio.Stream
|
||||
)
|
||||
if useAES() { // Only use AES-GCM if we can use an optimized implementation
|
||||
id = aesGcm
|
||||
if fips.Enabled() {
|
||||
key := pbkdf2.Key([]byte(password), salt, pbkdf2Cost, 32, sha256.New)
|
||||
stream, err = sio.AES_256_GCM.Stream(key)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
id = pbkdf2AESGCM
|
||||
} else {
|
||||
id = c20p1305
|
||||
stream, err = sio.ChaCha20Poly1305.Stream(key)
|
||||
}
|
||||
if err != nil {
|
||||
return nil, err
|
||||
key := argon2.IDKey([]byte(password), salt, argon2idTime, argon2idMemory, argon2idThreads, 32)
|
||||
if sioutil.NativeAES() {
|
||||
stream, err = sio.AES_256_GCM.Stream(key)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
id = argon2idAESGCM
|
||||
} else {
|
||||
stream, err = sio.ChaCha20Poly1305.Stream(key)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
id = argon2idChaCHa20Poly1305
|
||||
}
|
||||
}
|
||||
|
||||
nonce := sioutil.MustRandom(stream.NonceSize())
|
||||
|
||||
// ciphertext = salt || AEAD ID | nonce | encrypted data
|
||||
@@ -110,33 +118,43 @@ func DecryptData(password string, data io.Reader) ([]byte, error) {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
key := idKey([]byte(password), salt[:], nil, nil, 32)
|
||||
var (
|
||||
err error
|
||||
stream *sio.Stream
|
||||
)
|
||||
switch id[0] {
|
||||
case aesGcm:
|
||||
switch {
|
||||
case id[0] == argon2idAESGCM:
|
||||
key := argon2.IDKey([]byte(password), salt[:], argon2idTime, argon2idMemory, argon2idThreads, 32)
|
||||
stream, err = sio.AES_256_GCM.Stream(key)
|
||||
case c20p1305:
|
||||
case id[0] == argon2idChaCHa20Poly1305:
|
||||
key := argon2.IDKey([]byte(password), salt[:], argon2idTime, argon2idMemory, argon2idThreads, 32)
|
||||
stream, err = sio.ChaCha20Poly1305.Stream(key)
|
||||
case id[0] == pbkdf2AESGCM:
|
||||
key := pbkdf2.Key([]byte(password), salt[:], pbkdf2Cost, 32, sha256.New)
|
||||
stream, err = sio.AES_256_GCM.Stream(key)
|
||||
default:
|
||||
err = errors.New("madmin: invalid AEAD algorithm ID")
|
||||
err = errors.New("madmin: invalid encryption algorithm ID")
|
||||
}
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
enBytes, err := ioutil.ReadAll(stream.DecryptReader(data, nonce[:], nil))
|
||||
plaintext, err := ioutil.ReadAll(stream.DecryptReader(data, nonce[:], nil))
|
||||
if err != nil {
|
||||
if err == sio.NotAuthentic {
|
||||
return enBytes, ErrMaliciousData
|
||||
}
|
||||
return nil, err
|
||||
}
|
||||
return enBytes, err
|
||||
return plaintext, err
|
||||
}
|
||||
|
||||
const (
|
||||
aesGcm = 0x00
|
||||
c20p1305 = 0x01
|
||||
argon2idAESGCM = 0x00
|
||||
argon2idChaCHa20Poly1305 = 0x01
|
||||
pbkdf2AESGCM = 0x02
|
||||
)
|
||||
|
||||
const (
|
||||
argon2idTime = 1
|
||||
argon2idMemory = 64 * 1024
|
||||
argon2idThreads = 4
|
||||
pbkdf2Cost = 8192
|
||||
)
|
||||
|
||||
@@ -1,22 +0,0 @@
|
||||
// MinIO Cloud Storage, (C) 2021 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.
|
||||
|
||||
// +build fips
|
||||
|
||||
package madmin
|
||||
|
||||
// useAES always returns true since AES is the only
|
||||
// option out of AES-GCM and ChaCha20-Poly1305 that
|
||||
// is approved by the NIST.
|
||||
func useAES() bool { return true }
|
||||
@@ -1,24 +0,0 @@
|
||||
// MinIO Cloud Storage, (C) 2021 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.
|
||||
|
||||
// +build !fips
|
||||
|
||||
package madmin
|
||||
|
||||
import "github.com/secure-io/sio-go/sioutil"
|
||||
|
||||
// useAES returns true if the executing CPU provides
|
||||
// AES-GCM hardware instructions and an optimized
|
||||
// assembler implementation is available.
|
||||
func useAES() bool { return sioutil.NativeAES() }
|
||||
Reference in New Issue
Block a user