Introduce STS client grants API and OPA policy integration (#6168)

This PR introduces two new features

- AWS STS compatible STS API named AssumeRoleWithClientGrants

```
POST /?Action=AssumeRoleWithClientGrants&Token=<jwt>
```

This API endpoint returns temporary access credentials, access
tokens signature types supported by this API

  - RSA keys
  - ECDSA keys

Fetches the required public key from the JWKS endpoints, provides
them as rsa or ecdsa public keys.

- External policy engine support, in this case OPA policy engine

- Credentials are stored on disks
This commit is contained in:
Harshavardhana
2018-10-09 14:00:01 -07:00
committed by kannappanr
parent 16a100b597
commit 54ae364def
76 changed files with 7249 additions and 713 deletions

View File

@@ -20,9 +20,6 @@ import (
"bytes"
"context"
"encoding/json"
"errors"
"io"
"io/ioutil"
"os"
"path"
"runtime"
@@ -30,7 +27,6 @@ import (
"time"
"github.com/minio/minio/cmd/logger"
"github.com/minio/minio/pkg/hash"
"github.com/minio/minio/pkg/quick"
)
@@ -63,16 +59,10 @@ func saveServerConfig(ctx context.Context, objAPI ObjectLayer, config *serverCon
}
// Create a backup of the current config
reader, err := readConfig(ctx, objAPI, configFile)
oldData, err := readConfig(ctx, objAPI, configFile)
if err == nil {
var oldData []byte
oldData, err = ioutil.ReadAll(reader)
if err != nil {
return err
}
backupConfigFile := path.Join(minioConfigPrefix, minioConfigBackupFile)
err = saveConfig(objAPI, backupConfigFile, oldData)
if err != nil {
if err = saveConfig(ctx, objAPI, backupConfigFile, oldData); err != nil {
return err
}
} else {
@@ -82,40 +72,18 @@ func saveServerConfig(ctx context.Context, objAPI ObjectLayer, config *serverCon
}
// Save the new config in the std config path
return saveConfig(objAPI, configFile, data)
}
func readConfigEtcd(configFile string) ([]byte, error) {
ctx, cancel := context.WithTimeout(context.Background(), 5*time.Minute)
resp, err := globalEtcdClient.Get(ctx, configFile)
defer cancel()
if err != nil {
return nil, err
}
if resp.Count == 0 {
return nil, errConfigNotFound
}
for _, ev := range resp.Kvs {
if string(ev.Key) == configFile {
return ev.Value, nil
}
}
return nil, errConfigNotFound
return saveConfig(ctx, objAPI, configFile, data)
}
func readServerConfig(ctx context.Context, objAPI ObjectLayer) (*serverConfig, error) {
var configData []byte
var err error
configFile := path.Join(minioConfigPrefix, minioConfigFile)
if globalEtcdClient != nil {
configData, err = readConfigEtcd(configFile)
configData, err = readConfigEtcd(ctx, globalEtcdClient, configFile)
} else {
var reader io.Reader
reader, err = readConfig(ctx, objAPI, configFile)
if err != nil {
return nil, err
}
configData, err = ioutil.ReadAll(reader)
configData, err = readConfig(ctx, objAPI, configFile)
}
if err != nil {
return nil, err
@@ -130,82 +98,17 @@ func readServerConfig(ctx context.Context, objAPI ObjectLayer) (*serverConfig, e
}
var config = &serverConfig{}
if err := json.Unmarshal(configData, config); err != nil {
if err = json.Unmarshal(configData, config); err != nil {
return nil, err
}
if err := quick.CheckData(config); err != nil {
if err = quick.CheckData(config); err != nil {
return nil, err
}
return config, nil
}
func checkServerConfigEtcd(configFile string) error {
ctx, cancel := context.WithTimeout(context.Background(), 5*time.Minute)
resp, err := globalEtcdClient.Get(ctx, configFile)
defer cancel()
if err != nil {
return err
}
if resp.Count == 0 {
return errConfigNotFound
}
return nil
}
func checkServerConfig(ctx context.Context, objAPI ObjectLayer) error {
configFile := path.Join(minioConfigPrefix, minioConfigFile)
if globalEtcdClient != nil {
return checkServerConfigEtcd(configFile)
}
if _, err := objAPI.GetObjectInfo(ctx, minioMetaBucket, configFile, ObjectOptions{}); err != nil {
// Convert ObjectNotFound to errConfigNotFound
if isErrObjectNotFound(err) {
return errConfigNotFound
}
logger.GetReqInfo(ctx).AppendTags("configFile", configFile)
logger.LogIf(ctx, err)
return err
}
return nil
}
func saveConfig(objAPI ObjectLayer, configFile string, data []byte) error {
hashReader, err := hash.NewReader(bytes.NewReader(data), int64(len(data)), "", getSHA256Hash(data), int64(len(data)))
if err != nil {
return err
}
_, err = objAPI.PutObject(context.Background(), minioMetaBucket, configFile, hashReader, nil, ObjectOptions{})
return err
}
var errConfigNotFound = errors.New("config file not found")
func readConfig(ctx context.Context, objAPI ObjectLayer, configFile string) (*bytes.Buffer, error) {
var buffer bytes.Buffer
// Read entire content by setting size to -1
if err := objAPI.GetObject(ctx, minioMetaBucket, configFile, 0, -1, &buffer, "", ObjectOptions{}); err != nil {
// Convert ObjectNotFound and IncompleteBody errors into errConfigNotFound
if isErrObjectNotFound(err) || isErrIncompleteBody(err) {
return nil, errConfigNotFound
}
logger.GetReqInfo(ctx).AppendTags("configFile", configFile)
logger.LogIf(ctx, err)
return nil, err
}
// Return config not found on empty content.
if buffer.Len() == 0 {
return nil, errConfigNotFound
}
return &buffer, nil
}
// ConfigSys - config system.
type ConfigSys struct{}
@@ -257,8 +160,9 @@ func NewConfigSys() *ConfigSys {
func migrateConfigToMinioSys(objAPI ObjectLayer) error {
defer os.Rename(getConfigFile(), getConfigFile()+".deprecated")
configFile := path.Join(minioConfigPrefix, minioConfigFile)
// Verify if backend already has the file.
if err := checkServerConfig(context.Background(), objAPI); err != errConfigNotFound {
if err := checkConfig(context.Background(), objAPI, configFile); err != errConfigNotFound {
return err
} // if errConfigNotFound proceed to migrate..
@@ -287,7 +191,14 @@ func initConfig(objAPI ObjectLayer) error {
resp, err := globalEtcdClient.Get(ctx, getConfigFile())
cancel()
if err == nil && resp.Count > 0 {
return migrateConfig()
if err = migrateConfig(); err != nil {
return err
}
// Migrates etcd ${HOME}/.minio/config.json to '/config/config.json'
if err := migrateConfigToMinioSys(objAPI); err != nil {
return err
}
}
} else {
if isFile(getConfigFile()) {
@@ -303,10 +214,15 @@ func initConfig(objAPI ObjectLayer) error {
}
}
if err := checkServerConfig(context.Background(), objAPI); err != nil {
configFile := path.Join(minioConfigPrefix, minioConfigFile)
// Watch config for changes and reloads them in-memory.
go watchConfig(objAPI, configFile, loadConfig)
if err := checkConfig(context.Background(), objAPI, configFile); err != nil {
if err == errConfigNotFound {
// Config file does not exist, we create it fresh and return upon success.
if err = newConfig(objAPI); err != nil {
if err = newSrvConfig(objAPI); err != nil {
return err
}
} else {