config/main: Re-write config files - add to new config v3
- New config format.
```
{
"version": "3",
"address": ":9000",
"backend": {
"type": "fs",
"disk": "/path"
},
"credential": {
"accessKey": "WLGDGYAQYIGI833EV05A",
"secretKey": "BYvgJM101sHngl2uzjXS/OBF/aMxAN06JrJ3qJlF"
},
"region": "us-east-1",
"logger": {
"file": {
"enable": false,
"fileName": "",
"level": "error"
},
"syslog": {
"enable": false,
"address": "",
"level": "debug"
},
"console": {
"enable": true,
"level": "fatal"
}
}
}
```
New command lines in lieu of supporting XL.
Minio initialize filesystem backend.
~~~
$ minio init fs <path>
~~~
Minio initialize XL backend.
~~~
$ minio init xl <url1>...<url16>
~~~
For 'fs' backend it starts the server.
~~~
$ minio server
~~~
For 'xl' backend it waits for servers to join.
~~~
$ minio server
... [PROGRESS BAR] of servers connecting
~~~
Now on other servers execute 'join' and they connect.
~~~
....
minio join <url1> -- from <url2> && minio server
minio join <url1> -- from <url3> && minio server
...
...
minio join <url1> -- from <url16> && minio server
~~~
2016-02-13 00:27:10 +01:00
|
|
|
/*
|
2019-09-10 01:12:29 +02:00
|
|
|
* MinIO Cloud Storage, (C) 2016-2019 MinIO, Inc.
|
config/main: Re-write config files - add to new config v3
- New config format.
```
{
"version": "3",
"address": ":9000",
"backend": {
"type": "fs",
"disk": "/path"
},
"credential": {
"accessKey": "WLGDGYAQYIGI833EV05A",
"secretKey": "BYvgJM101sHngl2uzjXS/OBF/aMxAN06JrJ3qJlF"
},
"region": "us-east-1",
"logger": {
"file": {
"enable": false,
"fileName": "",
"level": "error"
},
"syslog": {
"enable": false,
"address": "",
"level": "debug"
},
"console": {
"enable": true,
"level": "fatal"
}
}
}
```
New command lines in lieu of supporting XL.
Minio initialize filesystem backend.
~~~
$ minio init fs <path>
~~~
Minio initialize XL backend.
~~~
$ minio init xl <url1>...<url16>
~~~
For 'fs' backend it starts the server.
~~~
$ minio server
~~~
For 'xl' backend it waits for servers to join.
~~~
$ minio server
... [PROGRESS BAR] of servers connecting
~~~
Now on other servers execute 'join' and they connect.
~~~
....
minio join <url1> -- from <url2> && minio server
minio join <url1> -- from <url3> && minio server
...
...
minio join <url1> -- from <url16> && minio server
~~~
2016-02-13 00:27:10 +01:00
|
|
|
*
|
|
|
|
* 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.
|
|
|
|
*/
|
|
|
|
|
2016-08-19 01:23:42 +02:00
|
|
|
package cmd
|
config/main: Re-write config files - add to new config v3
- New config format.
```
{
"version": "3",
"address": ":9000",
"backend": {
"type": "fs",
"disk": "/path"
},
"credential": {
"accessKey": "WLGDGYAQYIGI833EV05A",
"secretKey": "BYvgJM101sHngl2uzjXS/OBF/aMxAN06JrJ3qJlF"
},
"region": "us-east-1",
"logger": {
"file": {
"enable": false,
"fileName": "",
"level": "error"
},
"syslog": {
"enable": false,
"address": "",
"level": "debug"
},
"console": {
"enable": true,
"level": "fatal"
}
}
}
```
New command lines in lieu of supporting XL.
Minio initialize filesystem backend.
~~~
$ minio init fs <path>
~~~
Minio initialize XL backend.
~~~
$ minio init xl <url1>...<url16>
~~~
For 'fs' backend it starts the server.
~~~
$ minio server
~~~
For 'xl' backend it waits for servers to join.
~~~
$ minio server
... [PROGRESS BAR] of servers connecting
~~~
Now on other servers execute 'join' and they connect.
~~~
....
minio join <url1> -- from <url2> && minio server
minio join <url1> -- from <url3> && minio server
...
...
minio join <url1> -- from <url16> && minio server
~~~
2016-02-13 00:27:10 +01:00
|
|
|
|
|
|
|
import (
|
2020-12-04 18:32:35 +01:00
|
|
|
"context"
|
2021-02-13 03:17:52 +01:00
|
|
|
"crypto/tls"
|
2019-12-05 00:32:37 +01:00
|
|
|
"fmt"
|
2019-10-08 07:47:56 +02:00
|
|
|
"strings"
|
config/main: Re-write config files - add to new config v3
- New config format.
```
{
"version": "3",
"address": ":9000",
"backend": {
"type": "fs",
"disk": "/path"
},
"credential": {
"accessKey": "WLGDGYAQYIGI833EV05A",
"secretKey": "BYvgJM101sHngl2uzjXS/OBF/aMxAN06JrJ3qJlF"
},
"region": "us-east-1",
"logger": {
"file": {
"enable": false,
"fileName": "",
"level": "error"
},
"syslog": {
"enable": false,
"address": "",
"level": "debug"
},
"console": {
"enable": true,
"level": "fatal"
}
}
}
```
New command lines in lieu of supporting XL.
Minio initialize filesystem backend.
~~~
$ minio init fs <path>
~~~
Minio initialize XL backend.
~~~
$ minio init xl <url1>...<url16>
~~~
For 'fs' backend it starts the server.
~~~
$ minio server
~~~
For 'xl' backend it waits for servers to join.
~~~
$ minio server
... [PROGRESS BAR] of servers connecting
~~~
Now on other servers execute 'join' and they connect.
~~~
....
minio join <url1> -- from <url2> && minio server
minio join <url1> -- from <url3> && minio server
...
...
minio join <url1> -- from <url16> && minio server
~~~
2016-02-13 00:27:10 +01:00
|
|
|
"sync"
|
|
|
|
|
2019-10-04 19:35:33 +02:00
|
|
|
"github.com/minio/minio/cmd/config"
|
2020-04-14 21:46:37 +02:00
|
|
|
"github.com/minio/minio/cmd/config/api"
|
2019-10-04 19:35:33 +02:00
|
|
|
"github.com/minio/minio/cmd/config/cache"
|
|
|
|
"github.com/minio/minio/cmd/config/compress"
|
2020-09-10 23:19:32 +02:00
|
|
|
"github.com/minio/minio/cmd/config/dns"
|
2019-10-30 08:04:39 +01:00
|
|
|
"github.com/minio/minio/cmd/config/etcd"
|
2020-10-14 22:51:51 +02:00
|
|
|
"github.com/minio/minio/cmd/config/heal"
|
2019-10-23 07:59:13 +02:00
|
|
|
xldap "github.com/minio/minio/cmd/config/identity/ldap"
|
|
|
|
"github.com/minio/minio/cmd/config/identity/openid"
|
2019-10-09 08:11:15 +02:00
|
|
|
"github.com/minio/minio/cmd/config/notify"
|
2019-10-23 07:59:13 +02:00
|
|
|
"github.com/minio/minio/cmd/config/policy/opa"
|
2021-02-17 21:04:11 +01:00
|
|
|
"github.com/minio/minio/cmd/config/scanner"
|
2019-10-07 07:50:24 +02:00
|
|
|
"github.com/minio/minio/cmd/config/storageclass"
|
2018-08-17 21:52:14 +02:00
|
|
|
"github.com/minio/minio/cmd/crypto"
|
2019-02-06 21:07:03 +01:00
|
|
|
xhttp "github.com/minio/minio/cmd/http"
|
2018-04-20 02:24:43 +02:00
|
|
|
"github.com/minio/minio/cmd/logger"
|
2019-10-08 07:47:56 +02:00
|
|
|
"github.com/minio/minio/cmd/logger/target/http"
|
2019-10-04 19:35:33 +02:00
|
|
|
"github.com/minio/minio/pkg/env"
|
2020-01-21 01:48:19 +01:00
|
|
|
"github.com/minio/minio/pkg/madmin"
|
config/main: Re-write config files - add to new config v3
- New config format.
```
{
"version": "3",
"address": ":9000",
"backend": {
"type": "fs",
"disk": "/path"
},
"credential": {
"accessKey": "WLGDGYAQYIGI833EV05A",
"secretKey": "BYvgJM101sHngl2uzjXS/OBF/aMxAN06JrJ3qJlF"
},
"region": "us-east-1",
"logger": {
"file": {
"enable": false,
"fileName": "",
"level": "error"
},
"syslog": {
"enable": false,
"address": "",
"level": "debug"
},
"console": {
"enable": true,
"level": "fatal"
}
}
}
```
New command lines in lieu of supporting XL.
Minio initialize filesystem backend.
~~~
$ minio init fs <path>
~~~
Minio initialize XL backend.
~~~
$ minio init xl <url1>...<url16>
~~~
For 'fs' backend it starts the server.
~~~
$ minio server
~~~
For 'xl' backend it waits for servers to join.
~~~
$ minio server
... [PROGRESS BAR] of servers connecting
~~~
Now on other servers execute 'join' and they connect.
~~~
....
minio join <url1> -- from <url2> && minio server
minio join <url1> -- from <url3> && minio server
...
...
minio join <url1> -- from <url16> && minio server
~~~
2016-02-13 00:27:10 +01:00
|
|
|
)
|
|
|
|
|
2019-12-05 00:32:37 +01:00
|
|
|
func initHelp() {
|
2019-11-27 18:36:08 +01:00
|
|
|
var kvs = map[string]config.KVS{
|
|
|
|
config.EtcdSubSys: etcd.DefaultKVS,
|
|
|
|
config.CacheSubSys: cache.DefaultKVS,
|
|
|
|
config.CompressionSubSys: compress.DefaultKVS,
|
|
|
|
config.IdentityLDAPSubSys: xldap.DefaultKVS,
|
|
|
|
config.IdentityOpenIDSubSys: openid.DefaultKVS,
|
|
|
|
config.PolicyOPASubSys: opa.DefaultKVS,
|
|
|
|
config.RegionSubSys: config.DefaultRegionKVS,
|
2020-04-14 21:46:37 +02:00
|
|
|
config.APISubSys: api.DefaultKVS,
|
2019-11-27 18:36:08 +01:00
|
|
|
config.CredentialsSubSys: config.DefaultCredentialKVS,
|
2019-12-13 21:57:11 +01:00
|
|
|
config.KmsVaultSubSys: crypto.DefaultVaultKVS,
|
|
|
|
config.KmsKesSubSys: crypto.DefaultKesKVS,
|
2019-11-27 18:36:08 +01:00
|
|
|
config.LoggerWebhookSubSys: logger.DefaultKVS,
|
|
|
|
config.AuditWebhookSubSys: logger.DefaultAuditKVS,
|
2020-10-14 22:51:51 +02:00
|
|
|
config.HealSubSys: heal.DefaultKVS,
|
2021-02-17 21:04:11 +01:00
|
|
|
config.ScannerSubSys: scanner.DefaultKVS,
|
2019-11-27 18:36:08 +01:00
|
|
|
}
|
|
|
|
for k, v := range notify.DefaultNotificationKVS {
|
|
|
|
kvs[k] = v
|
|
|
|
}
|
2020-06-13 05:04:01 +02:00
|
|
|
if globalIsErasure {
|
2019-12-05 00:32:37 +01:00
|
|
|
kvs[config.StorageClassSubSys] = storageclass.DefaultKVS
|
|
|
|
}
|
2019-11-27 18:36:08 +01:00
|
|
|
config.RegisterDefaultKVS(kvs)
|
|
|
|
|
|
|
|
// Captures help for each sub-system
|
|
|
|
var helpSubSys = config.HelpKVS{
|
|
|
|
config.HelpKV{
|
|
|
|
Key: config.RegionSubSys,
|
2019-12-05 00:32:37 +01:00
|
|
|
Description: "label the location of the server",
|
2019-11-27 18:36:08 +01:00
|
|
|
},
|
|
|
|
config.HelpKV{
|
|
|
|
Key: config.CacheSubSys,
|
2019-12-05 00:32:37 +01:00
|
|
|
Description: "add caching storage tier",
|
2019-11-27 18:36:08 +01:00
|
|
|
},
|
|
|
|
config.HelpKV{
|
|
|
|
Key: config.CompressionSubSys,
|
2019-12-05 00:32:37 +01:00
|
|
|
Description: "enable server side compression of objects",
|
2019-11-27 18:36:08 +01:00
|
|
|
},
|
|
|
|
config.HelpKV{
|
|
|
|
Key: config.EtcdSubSys,
|
2019-12-05 00:32:37 +01:00
|
|
|
Description: "federate multiple clusters for IAM and Bucket DNS",
|
2019-11-27 18:36:08 +01:00
|
|
|
},
|
|
|
|
config.HelpKV{
|
|
|
|
Key: config.IdentityOpenIDSubSys,
|
2019-12-05 00:32:37 +01:00
|
|
|
Description: "enable OpenID SSO support",
|
2019-11-27 18:36:08 +01:00
|
|
|
},
|
|
|
|
config.HelpKV{
|
|
|
|
Key: config.IdentityLDAPSubSys,
|
2019-12-05 00:32:37 +01:00
|
|
|
Description: "enable LDAP SSO support",
|
2019-11-27 18:36:08 +01:00
|
|
|
},
|
|
|
|
config.HelpKV{
|
|
|
|
Key: config.PolicyOPASubSys,
|
2020-07-28 20:47:57 +02:00
|
|
|
Description: "[DEPRECATED] enable external OPA for policy enforcement",
|
2019-11-27 18:36:08 +01:00
|
|
|
},
|
|
|
|
config.HelpKV{
|
|
|
|
Key: config.KmsVaultSubSys,
|
2019-12-06 22:53:51 +01:00
|
|
|
Description: "enable external HashiCorp Vault key management service",
|
2019-11-27 18:36:08 +01:00
|
|
|
},
|
2019-12-13 21:57:11 +01:00
|
|
|
config.HelpKV{
|
|
|
|
Key: config.KmsKesSubSys,
|
|
|
|
Description: "enable external MinIO key encryption service",
|
|
|
|
},
|
2020-04-14 21:46:37 +02:00
|
|
|
config.HelpKV{
|
|
|
|
Key: config.APISubSys,
|
|
|
|
Description: "manage global HTTP API call specific features, such as throttling, authentication types, etc.",
|
|
|
|
},
|
2020-09-12 09:08:12 +02:00
|
|
|
config.HelpKV{
|
2020-10-14 22:51:51 +02:00
|
|
|
Key: config.HealSubSys,
|
|
|
|
Description: "manage object healing frequency and bitrot verification checks",
|
2020-09-12 09:08:12 +02:00
|
|
|
},
|
2020-12-04 18:32:35 +01:00
|
|
|
config.HelpKV{
|
2021-02-17 21:04:11 +01:00
|
|
|
Key: config.ScannerSubSys,
|
2021-02-27 00:11:42 +01:00
|
|
|
Description: "manage namespace scanning for usage calculation, lifecycle, healing and more",
|
2020-12-04 18:32:35 +01:00
|
|
|
},
|
2019-11-27 18:36:08 +01:00
|
|
|
config.HelpKV{
|
|
|
|
Key: config.LoggerWebhookSubSys,
|
2019-12-05 00:32:37 +01:00
|
|
|
Description: "send server logs to webhook endpoints",
|
2019-11-27 18:36:08 +01:00
|
|
|
MultipleTargets: true,
|
|
|
|
},
|
|
|
|
config.HelpKV{
|
|
|
|
Key: config.AuditWebhookSubSys,
|
2019-12-05 00:32:37 +01:00
|
|
|
Description: "send audit logs to webhook endpoints",
|
2019-11-27 18:36:08 +01:00
|
|
|
MultipleTargets: true,
|
|
|
|
},
|
|
|
|
config.HelpKV{
|
|
|
|
Key: config.NotifyWebhookSubSys,
|
2019-12-05 00:32:37 +01:00
|
|
|
Description: "publish bucket notifications to webhook endpoints",
|
2019-11-27 18:36:08 +01:00
|
|
|
MultipleTargets: true,
|
|
|
|
},
|
|
|
|
config.HelpKV{
|
|
|
|
Key: config.NotifyAMQPSubSys,
|
2019-12-05 00:32:37 +01:00
|
|
|
Description: "publish bucket notifications to AMQP endpoints",
|
2019-11-27 18:36:08 +01:00
|
|
|
MultipleTargets: true,
|
|
|
|
},
|
|
|
|
config.HelpKV{
|
|
|
|
Key: config.NotifyKafkaSubSys,
|
2019-12-05 00:32:37 +01:00
|
|
|
Description: "publish bucket notifications to Kafka endpoints",
|
2019-11-27 18:36:08 +01:00
|
|
|
MultipleTargets: true,
|
|
|
|
},
|
|
|
|
config.HelpKV{
|
|
|
|
Key: config.NotifyMQTTSubSys,
|
2019-12-05 00:32:37 +01:00
|
|
|
Description: "publish bucket notifications to MQTT endpoints",
|
2019-11-27 18:36:08 +01:00
|
|
|
MultipleTargets: true,
|
|
|
|
},
|
|
|
|
config.HelpKV{
|
|
|
|
Key: config.NotifyNATSSubSys,
|
2019-12-05 00:32:37 +01:00
|
|
|
Description: "publish bucket notifications to NATS endpoints",
|
2019-11-27 18:36:08 +01:00
|
|
|
MultipleTargets: true,
|
|
|
|
},
|
|
|
|
config.HelpKV{
|
|
|
|
Key: config.NotifyNSQSubSys,
|
2019-12-05 00:32:37 +01:00
|
|
|
Description: "publish bucket notifications to NSQ endpoints",
|
2019-11-27 18:36:08 +01:00
|
|
|
MultipleTargets: true,
|
|
|
|
},
|
|
|
|
config.HelpKV{
|
|
|
|
Key: config.NotifyMySQLSubSys,
|
2019-12-06 22:53:51 +01:00
|
|
|
Description: "publish bucket notifications to MySQL databases",
|
2019-11-27 18:36:08 +01:00
|
|
|
MultipleTargets: true,
|
|
|
|
},
|
|
|
|
config.HelpKV{
|
|
|
|
Key: config.NotifyPostgresSubSys,
|
2019-12-06 22:53:51 +01:00
|
|
|
Description: "publish bucket notifications to Postgres databases",
|
2019-11-27 18:36:08 +01:00
|
|
|
MultipleTargets: true,
|
|
|
|
},
|
|
|
|
config.HelpKV{
|
2019-12-06 22:53:51 +01:00
|
|
|
Key: config.NotifyESSubSys,
|
|
|
|
Description: "publish bucket notifications to Elasticsearch endpoints",
|
2019-11-27 18:36:08 +01:00
|
|
|
MultipleTargets: true,
|
|
|
|
},
|
|
|
|
config.HelpKV{
|
2019-12-06 22:53:51 +01:00
|
|
|
Key: config.NotifyRedisSubSys,
|
|
|
|
Description: "publish bucket notifications to Redis datastores",
|
2019-11-27 18:36:08 +01:00
|
|
|
MultipleTargets: true,
|
|
|
|
},
|
|
|
|
}
|
|
|
|
|
2020-06-13 05:04:01 +02:00
|
|
|
if globalIsErasure {
|
2019-12-05 00:32:37 +01:00
|
|
|
helpSubSys = append(helpSubSys, config.HelpKV{})
|
|
|
|
copy(helpSubSys[2:], helpSubSys[1:])
|
|
|
|
helpSubSys[1] = config.HelpKV{
|
|
|
|
Key: config.StorageClassSubSys,
|
|
|
|
Description: "define object level redundancy",
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2019-11-27 18:36:08 +01:00
|
|
|
var helpMap = map[string]config.HelpKVS{
|
|
|
|
"": helpSubSys, // Help for all sub-systems.
|
|
|
|
config.RegionSubSys: config.RegionHelp,
|
2020-04-14 21:46:37 +02:00
|
|
|
config.APISubSys: api.Help,
|
2019-12-05 00:32:37 +01:00
|
|
|
config.StorageClassSubSys: storageclass.Help,
|
2019-11-27 18:36:08 +01:00
|
|
|
config.EtcdSubSys: etcd.Help,
|
|
|
|
config.CacheSubSys: cache.Help,
|
|
|
|
config.CompressionSubSys: compress.Help,
|
2020-10-14 22:51:51 +02:00
|
|
|
config.HealSubSys: heal.Help,
|
2021-02-17 21:04:11 +01:00
|
|
|
config.ScannerSubSys: scanner.Help,
|
2019-11-27 18:36:08 +01:00
|
|
|
config.IdentityOpenIDSubSys: openid.Help,
|
|
|
|
config.IdentityLDAPSubSys: xldap.Help,
|
|
|
|
config.PolicyOPASubSys: opa.Help,
|
2019-12-13 21:57:11 +01:00
|
|
|
config.KmsVaultSubSys: crypto.HelpVault,
|
|
|
|
config.KmsKesSubSys: crypto.HelpKes,
|
2019-11-27 18:36:08 +01:00
|
|
|
config.LoggerWebhookSubSys: logger.Help,
|
|
|
|
config.AuditWebhookSubSys: logger.HelpAudit,
|
|
|
|
config.NotifyAMQPSubSys: notify.HelpAMQP,
|
|
|
|
config.NotifyKafkaSubSys: notify.HelpKafka,
|
|
|
|
config.NotifyMQTTSubSys: notify.HelpMQTT,
|
|
|
|
config.NotifyNATSSubSys: notify.HelpNATS,
|
|
|
|
config.NotifyNSQSubSys: notify.HelpNSQ,
|
|
|
|
config.NotifyMySQLSubSys: notify.HelpMySQL,
|
|
|
|
config.NotifyPostgresSubSys: notify.HelpPostgres,
|
|
|
|
config.NotifyRedisSubSys: notify.HelpRedis,
|
|
|
|
config.NotifyWebhookSubSys: notify.HelpWebhook,
|
|
|
|
config.NotifyESSubSys: notify.HelpES,
|
|
|
|
}
|
|
|
|
|
|
|
|
config.RegisterHelpSubSys(helpMap)
|
|
|
|
}
|
|
|
|
|
2017-03-31 07:26:24 +02:00
|
|
|
var (
|
2017-11-29 22:12:47 +01:00
|
|
|
// globalServerConfig server config.
|
2019-10-23 07:59:13 +02:00
|
|
|
globalServerConfig config.Config
|
2017-11-29 22:12:47 +01:00
|
|
|
globalServerConfigMu sync.RWMutex
|
2017-03-31 07:26:24 +02:00
|
|
|
)
|
|
|
|
|
2021-01-22 21:09:24 +01:00
|
|
|
func validateConfig(s config.Config, setDriveCounts []int) error {
|
2020-12-04 18:32:35 +01:00
|
|
|
// We must have a global lock for this so nobody else modifies env while we do.
|
|
|
|
defer env.LockSetEnv()()
|
|
|
|
|
2019-10-31 07:39:09 +01:00
|
|
|
// Disable merging env values with config for validation.
|
|
|
|
env.SetEnvOff()
|
|
|
|
|
2019-11-09 18:27:23 +01:00
|
|
|
// Enable env values to validate KMS.
|
2019-10-31 07:39:09 +01:00
|
|
|
defer env.SetEnvOn()
|
|
|
|
|
2019-10-23 07:59:13 +02:00
|
|
|
if _, err := config.LookupCreds(s[config.CredentialsSubSys][config.Default]); err != nil {
|
|
|
|
return err
|
2018-08-19 22:57:18 +02:00
|
|
|
}
|
2019-11-09 18:27:23 +01:00
|
|
|
|
2019-10-23 07:59:13 +02:00
|
|
|
if _, err := config.LookupRegion(s[config.RegionSubSys][config.Default]); err != nil {
|
|
|
|
return err
|
2019-10-07 07:50:24 +02:00
|
|
|
}
|
2019-11-09 18:27:23 +01:00
|
|
|
|
2020-04-14 21:46:37 +02:00
|
|
|
if _, err := api.LookupConfig(s[config.APISubSys][config.Default]); err != nil {
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
|
2020-06-13 05:04:01 +02:00
|
|
|
if globalIsErasure {
|
2021-01-22 21:09:24 +01:00
|
|
|
for _, setDriveCount := range setDriveCounts {
|
|
|
|
if _, err := storageclass.LookupConfig(s[config.StorageClassSubSys][config.Default], setDriveCount); err != nil {
|
|
|
|
return err
|
|
|
|
}
|
2018-08-19 22:57:18 +02:00
|
|
|
}
|
|
|
|
}
|
2019-11-09 18:27:23 +01:00
|
|
|
|
2019-10-23 07:59:13 +02:00
|
|
|
if _, err := cache.LookupConfig(s[config.CacheSubSys][config.Default]); err != nil {
|
|
|
|
return err
|
2018-08-19 22:57:18 +02:00
|
|
|
}
|
2019-11-09 18:27:23 +01:00
|
|
|
|
2020-12-04 18:32:35 +01:00
|
|
|
compCfg, err := compress.LookupConfig(s[config.CompressionSubSys][config.Default])
|
|
|
|
if err != nil {
|
2019-10-23 07:59:13 +02:00
|
|
|
return err
|
2018-07-18 20:22:29 +02:00
|
|
|
}
|
2020-12-04 18:32:35 +01:00
|
|
|
objAPI := newObjectLayerFn()
|
|
|
|
if objAPI != nil {
|
|
|
|
if compCfg.Enabled && !objAPI.IsCompressionSupported() {
|
|
|
|
return fmt.Errorf("Backend does not support compression")
|
|
|
|
}
|
|
|
|
}
|
2019-11-09 18:27:23 +01:00
|
|
|
|
2021-02-17 21:04:11 +01:00
|
|
|
if _, err = heal.LookupConfig(s[config.HealSubSys][config.Default]); err != nil {
|
2020-09-12 09:08:12 +02:00
|
|
|
return err
|
|
|
|
}
|
|
|
|
|
2021-02-17 21:04:11 +01:00
|
|
|
if _, err = scanner.LookupConfig(s[config.ScannerSubSys][config.Default]); err != nil {
|
2020-12-04 18:32:35 +01:00
|
|
|
return err
|
|
|
|
}
|
|
|
|
|
2019-11-09 18:27:23 +01:00
|
|
|
{
|
|
|
|
etcdCfg, err := etcd.LookupConfig(s[config.EtcdSubSys][config.Default], globalRootCAs)
|
|
|
|
if err != nil {
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
if etcdCfg.Enabled {
|
|
|
|
etcdClnt, err := etcd.New(etcdCfg)
|
|
|
|
if err != nil {
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
etcdClnt.Close()
|
|
|
|
}
|
|
|
|
}
|
|
|
|
{
|
2021-02-13 03:17:52 +01:00
|
|
|
kmsCfg, err := crypto.LookupConfig(s, globalCertsCADir.Get(), newCustomHTTPTransportWithHTTP2(
|
|
|
|
&tls.Config{
|
|
|
|
RootCAs: globalRootCAs,
|
|
|
|
}, defaultDialTimeout)())
|
2019-11-09 18:27:23 +01:00
|
|
|
if err != nil {
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
|
2019-12-13 21:57:11 +01:00
|
|
|
// Set env to enable master key validation.
|
|
|
|
// this is needed only for KMS.
|
|
|
|
env.SetEnvOn()
|
2019-12-05 00:32:37 +01:00
|
|
|
|
2019-12-13 21:57:11 +01:00
|
|
|
if _, err = crypto.NewKMS(kmsCfg); err != nil {
|
|
|
|
return err
|
2019-11-09 18:27:23 +01:00
|
|
|
}
|
2019-12-13 21:57:11 +01:00
|
|
|
|
|
|
|
// Disable merging env values for the rest.
|
|
|
|
env.SetEnvOff()
|
2019-11-09 18:27:23 +01:00
|
|
|
}
|
|
|
|
|
2019-10-23 07:59:13 +02:00
|
|
|
if _, err := openid.LookupConfig(s[config.IdentityOpenIDSubSys][config.Default],
|
2020-03-22 06:10:13 +01:00
|
|
|
NewGatewayHTTPTransport(), xhttp.DrainBody); err != nil {
|
2019-10-23 07:59:13 +02:00
|
|
|
return err
|
2018-07-18 20:22:29 +02:00
|
|
|
}
|
2019-11-09 18:27:23 +01:00
|
|
|
|
2020-03-22 06:47:26 +01:00
|
|
|
{
|
|
|
|
cfg, err := xldap.Lookup(s[config.IdentityLDAPSubSys][config.Default],
|
|
|
|
globalRootCAs)
|
|
|
|
if err != nil {
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
if cfg.Enabled {
|
|
|
|
conn, cerr := cfg.Connect()
|
|
|
|
if cerr != nil {
|
|
|
|
return cerr
|
|
|
|
}
|
|
|
|
conn.Close()
|
|
|
|
}
|
2018-07-18 20:22:29 +02:00
|
|
|
}
|
2019-11-09 18:27:23 +01:00
|
|
|
|
2019-10-23 07:59:13 +02:00
|
|
|
if _, err := opa.LookupConfig(s[config.PolicyOPASubSys][config.Default],
|
2020-03-22 06:10:13 +01:00
|
|
|
NewGatewayHTTPTransport(), xhttp.DrainBody); err != nil {
|
2019-10-23 07:59:13 +02:00
|
|
|
return err
|
2018-07-18 20:22:29 +02:00
|
|
|
}
|
2019-11-09 18:27:23 +01:00
|
|
|
|
2019-10-23 07:59:13 +02:00
|
|
|
if _, err := logger.LookupConfig(s); err != nil {
|
|
|
|
return err
|
2018-07-18 20:22:29 +02:00
|
|
|
}
|
2019-11-09 18:27:23 +01:00
|
|
|
|
certs: refactor cert manager to support multiple certificates (#10207)
This commit refactors the certificate management implementation
in the `certs` package such that multiple certificates can be
specified at the same time. Therefore, the following layout of
the `certs/` directory is expected:
```
certs/
│
├─ public.crt
├─ private.key
├─ CAs/ // CAs directory is ignored
│ │
│ ...
│
├─ example.com/
│ │
│ ├─ public.crt
│ └─ private.key
└─ foobar.org/
│
├─ public.crt
└─ private.key
...
```
However, directory names like `example.com` are just for human
readability/organization and don't have any meaning w.r.t whether
a particular certificate is served or not. This decision is made based
on the SNI sent by the client and the SAN of the certificate.
***
The `Manager` will pick a certificate based on the client trying
to establish a TLS connection. In particular, it looks at the client
hello (i.e. SNI) to determine which host the client tries to access.
If the manager can find a certificate that matches the SNI it
returns this certificate to the client.
However, the client may choose to not send an SNI or tries to access
a server directly via IP (`https://<ip>:<port>`). In this case, we
cannot use the SNI to determine which certificate to serve. However,
we also should not pick "the first" certificate that would be accepted
by the client (based on crypto. parameters - like a signature algorithm)
because it may be an internal certificate that contains internal hostnames.
We would disclose internal infrastructure details doing so.
Therefore, the `Manager` returns the "default" certificate when the
client does not specify an SNI. The default certificate the top-level
`public.crt` - i.e. `certs/public.crt`.
This approach has some consequences:
- It's the operator's responsibility to ensure that the top-level
`public.crt` does not disclose any information (i.e. hostnames)
that are not publicly visible. However, this was the case in the
past already.
- Any other `public.crt` - except for the top-level one - must not
contain any IP SAN. The reason for this restriction is that the
Manager cannot match a SNI to an IP b/c the SNI is the server host
name. The entire purpose of SNI is to indicate which host the client
tries to connect to when multiple hosts run on the same IP. So, a
client will not set the SNI to an IP.
If we would allow IP SANs in a lower-level `public.crt` a user would
expect that it is possible to connect to MinIO directly via IP address
and that the MinIO server would pick "the right" certificate. However,
the MinIO server cannot determine which certificate to serve, and
therefore always picks the "default" one. This may lead to all sorts
of confusing errors like:
"It works if I use `https:instance.minio.local` but not when I use
`https://10.0.2.1`.
These consequences/limitations should be pointed out / explained in our
docs in an appropriate way. However, the support for multiple
certificates should not have any impact on how deployment with a single
certificate function today.
Co-authored-by: Harshavardhana <harsha@minio.io>
2020-09-04 08:33:37 +02:00
|
|
|
return notify.TestNotificationTargets(GlobalContext, s, NewGatewayHTTPTransport(), globalNotificationSys.ConfiguredTargetIDs())
|
2019-10-23 07:59:13 +02:00
|
|
|
}
|
2018-07-18 20:22:29 +02:00
|
|
|
|
2021-01-22 21:09:24 +01:00
|
|
|
func lookupConfigs(s config.Config, setDriveCounts []int) {
|
2020-04-09 18:30:02 +02:00
|
|
|
ctx := GlobalContext
|
2019-12-15 02:27:57 +01:00
|
|
|
|
|
|
|
var err error
|
2019-10-23 07:59:13 +02:00
|
|
|
if !globalActiveCred.IsValid() {
|
2019-10-30 08:04:39 +01:00
|
|
|
// Env doesn't seem to be set, we fallback to lookup creds from the config.
|
2019-10-23 07:59:13 +02:00
|
|
|
globalActiveCred, err = config.LookupCreds(s[config.CredentialsSubSys][config.Default])
|
|
|
|
if err != nil {
|
2019-12-15 02:27:57 +01:00
|
|
|
logger.LogIf(ctx, fmt.Errorf("Invalid credentials configuration: %w", err))
|
2018-07-18 20:22:29 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2020-09-10 23:19:32 +02:00
|
|
|
if dnsURL, dnsUser, dnsPass, ok := env.LookupEnv(config.EnvDNSWebhook); ok {
|
|
|
|
globalDNSConfig, err = dns.NewOperatorDNS(dnsURL,
|
|
|
|
dns.Authentication(dnsUser, dnsPass),
|
|
|
|
dns.RootCAs(globalRootCAs))
|
|
|
|
if err != nil {
|
|
|
|
if globalIsGateway {
|
|
|
|
logger.FatalIf(err, "Unable to initialize remote webhook DNS config")
|
|
|
|
} else {
|
|
|
|
logger.LogIf(ctx, fmt.Errorf("Unable to initialize remote webhook DNS config %w", err))
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2020-03-19 00:19:29 +01:00
|
|
|
etcdCfg, err := etcd.LookupConfig(s[config.EtcdSubSys][config.Default], globalRootCAs)
|
2019-10-30 08:04:39 +01:00
|
|
|
if err != nil {
|
2020-06-16 07:09:39 +02:00
|
|
|
if globalIsGateway {
|
|
|
|
logger.FatalIf(err, "Unable to initialize etcd config")
|
|
|
|
} else {
|
|
|
|
logger.LogIf(ctx, fmt.Errorf("Unable to initialize etcd config: %w", err))
|
|
|
|
}
|
2019-10-30 08:04:39 +01:00
|
|
|
}
|
|
|
|
|
2019-12-15 02:27:57 +01:00
|
|
|
if etcdCfg.Enabled {
|
2020-06-19 02:31:56 +02:00
|
|
|
if globalEtcdClient == nil {
|
|
|
|
globalEtcdClient, err = etcd.New(etcdCfg)
|
|
|
|
if err != nil {
|
|
|
|
if globalIsGateway {
|
|
|
|
logger.FatalIf(err, "Unable to initialize etcd config")
|
|
|
|
} else {
|
|
|
|
logger.LogIf(ctx, fmt.Errorf("Unable to initialize etcd config: %w", err))
|
|
|
|
}
|
2020-06-17 05:15:21 +02:00
|
|
|
}
|
|
|
|
}
|
2020-06-19 02:31:56 +02:00
|
|
|
|
2020-09-10 23:19:32 +02:00
|
|
|
if len(globalDomainNames) != 0 && !globalDomainIPs.IsEmpty() && globalEtcdClient != nil {
|
|
|
|
if globalDNSConfig != nil {
|
|
|
|
// if global DNS is already configured, indicate with a warning, incase
|
|
|
|
// users are confused.
|
|
|
|
logger.LogIf(ctx, fmt.Errorf("DNS store is already configured with %s, not using etcd for DNS store", globalDNSConfig))
|
|
|
|
} else {
|
|
|
|
globalDNSConfig, err = dns.NewCoreDNS(etcdCfg.Config,
|
|
|
|
dns.DomainNames(globalDomainNames),
|
|
|
|
dns.DomainIPs(globalDomainIPs),
|
|
|
|
dns.DomainPort(globalMinioPort),
|
|
|
|
dns.CoreDNSPath(etcdCfg.CoreDNSPath),
|
|
|
|
)
|
|
|
|
if err != nil {
|
|
|
|
if globalIsGateway {
|
|
|
|
logger.FatalIf(err, "Unable to initialize DNS config")
|
|
|
|
} else {
|
|
|
|
logger.LogIf(ctx, fmt.Errorf("Unable to initialize DNS config for %s: %w",
|
|
|
|
globalDomainNames, err))
|
|
|
|
}
|
2020-06-16 07:09:39 +02:00
|
|
|
}
|
|
|
|
}
|
2020-06-17 05:15:21 +02:00
|
|
|
}
|
2019-10-30 08:04:39 +01:00
|
|
|
}
|
|
|
|
|
2019-12-29 17:56:45 +01:00
|
|
|
// Bucket federation is 'true' only when IAM assets are not namespaced
|
|
|
|
// per tenant and all tenants interested in globally available users
|
|
|
|
// if namespace was requested such as specifying etcdPathPrefix then
|
|
|
|
// we assume that users are interested in global bucket support
|
|
|
|
// but not federation.
|
|
|
|
globalBucketFederation = etcdCfg.PathPrefix == "" && etcdCfg.Enabled
|
|
|
|
|
2019-10-23 07:59:13 +02:00
|
|
|
globalServerRegion, err = config.LookupRegion(s[config.RegionSubSys][config.Default])
|
|
|
|
if err != nil {
|
2019-12-15 02:27:57 +01:00
|
|
|
logger.LogIf(ctx, fmt.Errorf("Invalid region configuration: %w", err))
|
2018-08-15 06:41:47 +02:00
|
|
|
}
|
|
|
|
|
2020-04-14 21:46:37 +02:00
|
|
|
apiConfig, err := api.LookupConfig(s[config.APISubSys][config.Default])
|
|
|
|
if err != nil {
|
|
|
|
logger.LogIf(ctx, fmt.Errorf("Invalid api configuration: %w", err))
|
|
|
|
}
|
|
|
|
|
2021-01-22 21:09:24 +01:00
|
|
|
globalAPIConfig.init(apiConfig, setDriveCounts)
|
2020-04-14 21:46:37 +02:00
|
|
|
|
2020-09-12 08:03:08 +02:00
|
|
|
// Initialize remote instance transport once.
|
|
|
|
getRemoteInstanceTransportOnce.Do(func() {
|
|
|
|
getRemoteInstanceTransport = newGatewayHTTPTransport(apiConfig.RemoteTransportDeadline)
|
|
|
|
})
|
|
|
|
|
2020-06-13 05:04:01 +02:00
|
|
|
if globalIsErasure {
|
2021-01-22 21:09:24 +01:00
|
|
|
for i, setDriveCount := range setDriveCounts {
|
|
|
|
sc, err := storageclass.LookupConfig(s[config.StorageClassSubSys][config.Default], setDriveCount)
|
|
|
|
if err != nil {
|
|
|
|
logger.LogIf(ctx, fmt.Errorf("Unable to initialize storage class config: %w", err))
|
|
|
|
break
|
|
|
|
}
|
|
|
|
// if we validated all setDriveCounts and it was successful
|
|
|
|
// proceed to store the correct storage class globally.
|
|
|
|
if i == len(setDriveCounts)-1 {
|
|
|
|
globalStorageClass = sc
|
|
|
|
}
|
2019-10-07 07:50:24 +02:00
|
|
|
}
|
2018-08-15 06:41:47 +02:00
|
|
|
}
|
2018-04-05 17:18:42 +02:00
|
|
|
|
2019-10-23 07:59:13 +02:00
|
|
|
globalCacheConfig, err = cache.LookupConfig(s[config.CacheSubSys][config.Default])
|
2019-10-04 19:35:33 +02:00
|
|
|
if err != nil {
|
2020-06-16 07:09:39 +02:00
|
|
|
if globalIsGateway {
|
|
|
|
logger.FatalIf(err, "Unable to setup cache")
|
|
|
|
} else {
|
|
|
|
logger.LogIf(ctx, fmt.Errorf("Unable to setup cache: %w", err))
|
|
|
|
}
|
2018-08-15 06:41:47 +02:00
|
|
|
}
|
2018-08-17 21:52:14 +02:00
|
|
|
|
2019-10-23 07:59:13 +02:00
|
|
|
if globalCacheConfig.Enabled {
|
2019-10-04 19:35:33 +02:00
|
|
|
if cacheEncKey := env.Get(cache.EnvCacheEncryptionMasterKey, ""); cacheEncKey != "" {
|
2019-10-08 07:47:56 +02:00
|
|
|
globalCacheKMS, err = crypto.ParseMasterKey(cacheEncKey)
|
2019-10-04 19:35:33 +02:00
|
|
|
if err != nil {
|
2019-12-15 02:27:57 +01:00
|
|
|
logger.LogIf(ctx, fmt.Errorf("Unable to setup encryption cache: %w", err))
|
2019-10-04 19:35:33 +02:00
|
|
|
}
|
|
|
|
}
|
2018-08-17 21:52:14 +02:00
|
|
|
}
|
2018-09-28 05:36:17 +02:00
|
|
|
|
2021-02-13 03:17:52 +01:00
|
|
|
kmsCfg, err := crypto.LookupConfig(s, globalCertsCADir.Get(), newCustomHTTPTransportWithHTTP2(
|
|
|
|
&tls.Config{
|
|
|
|
RootCAs: globalRootCAs,
|
|
|
|
}, defaultDialTimeout)())
|
2019-10-08 07:47:56 +02:00
|
|
|
if err != nil {
|
2019-12-15 02:27:57 +01:00
|
|
|
logger.LogIf(ctx, fmt.Errorf("Unable to setup KMS config: %w", err))
|
2019-10-08 07:47:56 +02:00
|
|
|
}
|
|
|
|
|
2019-10-23 07:59:13 +02:00
|
|
|
GlobalKMS, err = crypto.NewKMS(kmsCfg)
|
2019-10-08 07:47:56 +02:00
|
|
|
if err != nil {
|
2019-12-15 02:27:57 +01:00
|
|
|
logger.LogIf(ctx, fmt.Errorf("Unable to setup KMS with current KMS config: %w", err))
|
2019-10-08 07:47:56 +02:00
|
|
|
}
|
2021-01-30 02:55:37 +01:00
|
|
|
globalAutoEncryption = kmsCfg.AutoEncryption // Enable auto-encryption if enabled
|
2019-10-08 07:47:56 +02:00
|
|
|
|
2021-01-30 02:55:37 +01:00
|
|
|
if kmsCfg.Vault.Enabled {
|
|
|
|
const deprecationWarning = `Native Hashicorp Vault support is deprecated and will be removed on 2021-10-01. Please migrate to KES + Hashicorp Vault: https://github.com/minio/kes/wiki/Hashicorp-Vault-Keystore
|
|
|
|
Note that native Hashicorp Vault and KES + Hashicorp Vault are not compatible.
|
|
|
|
If you need help to migrate smoothly visit: https://min.io/pricing`
|
|
|
|
logger.LogIf(ctx, fmt.Errorf(deprecationWarning))
|
2020-09-03 21:43:45 +02:00
|
|
|
}
|
2018-10-12 20:32:18 +02:00
|
|
|
|
2019-10-23 07:59:13 +02:00
|
|
|
globalOpenIDConfig, err = openid.LookupConfig(s[config.IdentityOpenIDSubSys][config.Default],
|
2020-03-22 06:10:13 +01:00
|
|
|
NewGatewayHTTPTransport(), xhttp.DrainBody)
|
2019-10-07 07:50:24 +02:00
|
|
|
if err != nil {
|
2019-12-15 02:27:57 +01:00
|
|
|
logger.LogIf(ctx, fmt.Errorf("Unable to initialize OpenID: %w", err))
|
2019-10-07 07:50:24 +02:00
|
|
|
}
|
|
|
|
|
2019-10-23 07:59:13 +02:00
|
|
|
opaCfg, err := opa.LookupConfig(s[config.PolicyOPASubSys][config.Default],
|
2020-03-22 06:10:13 +01:00
|
|
|
NewGatewayHTTPTransport(), xhttp.DrainBody)
|
2019-10-07 07:50:24 +02:00
|
|
|
if err != nil {
|
2019-12-15 02:27:57 +01:00
|
|
|
logger.LogIf(ctx, fmt.Errorf("Unable to initialize OPA: %w", err))
|
2018-10-12 20:32:18 +02:00
|
|
|
}
|
2019-09-10 01:12:29 +02:00
|
|
|
|
2019-10-23 07:59:13 +02:00
|
|
|
globalOpenIDValidators = getOpenIDValidators(globalOpenIDConfig)
|
|
|
|
globalPolicyOPA = opa.New(opaCfg)
|
2019-10-07 07:50:24 +02:00
|
|
|
|
2019-10-23 07:59:13 +02:00
|
|
|
globalLDAPConfig, err = xldap.Lookup(s[config.IdentityLDAPSubSys][config.Default],
|
|
|
|
globalRootCAs)
|
2019-09-10 01:12:29 +02:00
|
|
|
if err != nil {
|
2019-12-15 02:27:57 +01:00
|
|
|
logger.LogIf(ctx, fmt.Errorf("Unable to parse LDAP configuration: %w", err))
|
2019-09-10 01:12:29 +02:00
|
|
|
}
|
2019-10-08 07:47:56 +02:00
|
|
|
|
|
|
|
// Load logger targets based on user's configuration
|
|
|
|
loggerUserAgent := getUserAgent(getMinioMode())
|
|
|
|
|
2019-10-23 07:59:13 +02:00
|
|
|
loggerCfg, err := logger.LookupConfig(s)
|
2019-10-08 07:47:56 +02:00
|
|
|
if err != nil {
|
2019-12-15 02:27:57 +01:00
|
|
|
logger.LogIf(ctx, fmt.Errorf("Unable to initialize logger: %w", err))
|
2019-10-08 07:47:56 +02:00
|
|
|
}
|
|
|
|
|
2020-10-03 01:19:44 +02:00
|
|
|
for k, l := range loggerCfg.HTTP {
|
2019-10-08 07:47:56 +02:00
|
|
|
if l.Enabled {
|
|
|
|
// Enable http logging
|
2020-08-16 19:25:00 +02:00
|
|
|
if err = logger.AddTarget(
|
2020-10-03 01:19:44 +02:00
|
|
|
http.New(
|
|
|
|
http.WithTargetName(k),
|
|
|
|
http.WithEndpoint(l.Endpoint),
|
2020-04-02 05:53:07 +02:00
|
|
|
http.WithAuthToken(l.AuthToken),
|
|
|
|
http.WithUserAgent(loggerUserAgent),
|
|
|
|
http.WithLogKind(string(logger.All)),
|
|
|
|
http.WithTransport(NewGatewayHTTPTransport()),
|
|
|
|
),
|
2020-08-16 19:25:00 +02:00
|
|
|
); err != nil {
|
|
|
|
logger.LogIf(ctx, fmt.Errorf("Unable to initialize console HTTP target: %w", err))
|
|
|
|
}
|
2019-10-08 07:47:56 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2020-10-03 01:19:44 +02:00
|
|
|
for k, l := range loggerCfg.Audit {
|
2019-10-08 07:47:56 +02:00
|
|
|
if l.Enabled {
|
|
|
|
// Enable http audit logging
|
2020-08-16 19:25:00 +02:00
|
|
|
if err = logger.AddAuditTarget(
|
2020-10-03 01:19:44 +02:00
|
|
|
http.New(
|
|
|
|
http.WithTargetName(k),
|
|
|
|
http.WithEndpoint(l.Endpoint),
|
2020-04-02 05:53:07 +02:00
|
|
|
http.WithAuthToken(l.AuthToken),
|
|
|
|
http.WithUserAgent(loggerUserAgent),
|
|
|
|
http.WithLogKind(string(logger.All)),
|
2021-03-01 18:19:13 +01:00
|
|
|
http.WithTransport(NewGatewayHTTPTransportWithClientCerts(l.ClientCert, l.ClientKey)),
|
2020-04-02 05:53:07 +02:00
|
|
|
),
|
2020-08-16 19:25:00 +02:00
|
|
|
); err != nil {
|
|
|
|
logger.LogIf(ctx, fmt.Errorf("Unable to initialize audit HTTP target: %w", err))
|
|
|
|
}
|
2019-10-08 07:47:56 +02:00
|
|
|
}
|
|
|
|
}
|
2019-12-22 07:35:50 +01:00
|
|
|
|
certs: refactor cert manager to support multiple certificates (#10207)
This commit refactors the certificate management implementation
in the `certs` package such that multiple certificates can be
specified at the same time. Therefore, the following layout of
the `certs/` directory is expected:
```
certs/
│
├─ public.crt
├─ private.key
├─ CAs/ // CAs directory is ignored
│ │
│ ...
│
├─ example.com/
│ │
│ ├─ public.crt
│ └─ private.key
└─ foobar.org/
│
├─ public.crt
└─ private.key
...
```
However, directory names like `example.com` are just for human
readability/organization and don't have any meaning w.r.t whether
a particular certificate is served or not. This decision is made based
on the SNI sent by the client and the SAN of the certificate.
***
The `Manager` will pick a certificate based on the client trying
to establish a TLS connection. In particular, it looks at the client
hello (i.e. SNI) to determine which host the client tries to access.
If the manager can find a certificate that matches the SNI it
returns this certificate to the client.
However, the client may choose to not send an SNI or tries to access
a server directly via IP (`https://<ip>:<port>`). In this case, we
cannot use the SNI to determine which certificate to serve. However,
we also should not pick "the first" certificate that would be accepted
by the client (based on crypto. parameters - like a signature algorithm)
because it may be an internal certificate that contains internal hostnames.
We would disclose internal infrastructure details doing so.
Therefore, the `Manager` returns the "default" certificate when the
client does not specify an SNI. The default certificate the top-level
`public.crt` - i.e. `certs/public.crt`.
This approach has some consequences:
- It's the operator's responsibility to ensure that the top-level
`public.crt` does not disclose any information (i.e. hostnames)
that are not publicly visible. However, this was the case in the
past already.
- Any other `public.crt` - except for the top-level one - must not
contain any IP SAN. The reason for this restriction is that the
Manager cannot match a SNI to an IP b/c the SNI is the server host
name. The entire purpose of SNI is to indicate which host the client
tries to connect to when multiple hosts run on the same IP. So, a
client will not set the SNI to an IP.
If we would allow IP SANs in a lower-level `public.crt` a user would
expect that it is possible to connect to MinIO directly via IP address
and that the MinIO server would pick "the right" certificate. However,
the MinIO server cannot determine which certificate to serve, and
therefore always picks the "default" one. This may lead to all sorts
of confusing errors like:
"It works if I use `https:instance.minio.local` but not when I use
`https://10.0.2.1`.
These consequences/limitations should be pointed out / explained in our
docs in an appropriate way. However, the support for multiple
certificates should not have any impact on how deployment with a single
certificate function today.
Co-authored-by: Harshavardhana <harsha@minio.io>
2020-09-04 08:33:37 +02:00
|
|
|
globalConfigTargetList, err = notify.GetNotificationTargets(GlobalContext, s, NewGatewayHTTPTransport(), false)
|
2019-12-22 07:35:50 +01:00
|
|
|
if err != nil {
|
|
|
|
logger.LogIf(ctx, fmt.Errorf("Unable to initialize notification target(s): %w", err))
|
|
|
|
}
|
2020-03-22 06:10:13 +01:00
|
|
|
|
certs: refactor cert manager to support multiple certificates (#10207)
This commit refactors the certificate management implementation
in the `certs` package such that multiple certificates can be
specified at the same time. Therefore, the following layout of
the `certs/` directory is expected:
```
certs/
│
├─ public.crt
├─ private.key
├─ CAs/ // CAs directory is ignored
│ │
│ ...
│
├─ example.com/
│ │
│ ├─ public.crt
│ └─ private.key
└─ foobar.org/
│
├─ public.crt
└─ private.key
...
```
However, directory names like `example.com` are just for human
readability/organization and don't have any meaning w.r.t whether
a particular certificate is served or not. This decision is made based
on the SNI sent by the client and the SAN of the certificate.
***
The `Manager` will pick a certificate based on the client trying
to establish a TLS connection. In particular, it looks at the client
hello (i.e. SNI) to determine which host the client tries to access.
If the manager can find a certificate that matches the SNI it
returns this certificate to the client.
However, the client may choose to not send an SNI or tries to access
a server directly via IP (`https://<ip>:<port>`). In this case, we
cannot use the SNI to determine which certificate to serve. However,
we also should not pick "the first" certificate that would be accepted
by the client (based on crypto. parameters - like a signature algorithm)
because it may be an internal certificate that contains internal hostnames.
We would disclose internal infrastructure details doing so.
Therefore, the `Manager` returns the "default" certificate when the
client does not specify an SNI. The default certificate the top-level
`public.crt` - i.e. `certs/public.crt`.
This approach has some consequences:
- It's the operator's responsibility to ensure that the top-level
`public.crt` does not disclose any information (i.e. hostnames)
that are not publicly visible. However, this was the case in the
past already.
- Any other `public.crt` - except for the top-level one - must not
contain any IP SAN. The reason for this restriction is that the
Manager cannot match a SNI to an IP b/c the SNI is the server host
name. The entire purpose of SNI is to indicate which host the client
tries to connect to when multiple hosts run on the same IP. So, a
client will not set the SNI to an IP.
If we would allow IP SANs in a lower-level `public.crt` a user would
expect that it is possible to connect to MinIO directly via IP address
and that the MinIO server would pick "the right" certificate. However,
the MinIO server cannot determine which certificate to serve, and
therefore always picks the "default" one. This may lead to all sorts
of confusing errors like:
"It works if I use `https:instance.minio.local` but not when I use
`https://10.0.2.1`.
These consequences/limitations should be pointed out / explained in our
docs in an appropriate way. However, the support for multiple
certificates should not have any impact on how deployment with a single
certificate function today.
Co-authored-by: Harshavardhana <harsha@minio.io>
2020-09-04 08:33:37 +02:00
|
|
|
globalEnvTargetList, err = notify.GetNotificationTargets(GlobalContext, newServerConfig(), NewGatewayHTTPTransport(), true)
|
2020-03-14 08:01:15 +01:00
|
|
|
if err != nil {
|
|
|
|
logger.LogIf(ctx, fmt.Errorf("Unable to initialize notification target(s): %w", err))
|
|
|
|
}
|
2020-12-04 18:32:35 +01:00
|
|
|
|
|
|
|
// Apply dynamic config values
|
2021-01-22 21:09:24 +01:00
|
|
|
logger.LogIf(ctx, applyDynamicConfig(ctx, newObjectLayerFn(), s))
|
2020-12-04 18:32:35 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
// applyDynamicConfig will apply dynamic config values.
|
|
|
|
// Dynamic systems should be in config.SubSystemsDynamic as well.
|
2021-01-22 21:09:24 +01:00
|
|
|
func applyDynamicConfig(ctx context.Context, objAPI ObjectLayer, s config.Config) error {
|
|
|
|
if objAPI == nil {
|
|
|
|
return nil
|
|
|
|
}
|
|
|
|
|
2020-12-04 18:32:35 +01:00
|
|
|
// Read all dynamic configs.
|
|
|
|
// API
|
|
|
|
apiConfig, err := api.LookupConfig(s[config.APISubSys][config.Default])
|
|
|
|
if err != nil {
|
|
|
|
logger.LogIf(ctx, fmt.Errorf("Invalid api configuration: %w", err))
|
|
|
|
}
|
|
|
|
|
|
|
|
// Compression
|
|
|
|
cmpCfg, err := compress.LookupConfig(s[config.CompressionSubSys][config.Default])
|
|
|
|
if err != nil {
|
|
|
|
return fmt.Errorf("Unable to setup Compression: %w", err)
|
|
|
|
}
|
2021-01-22 21:09:24 +01:00
|
|
|
|
|
|
|
// Validate if the object layer supports compression.
|
|
|
|
if cmpCfg.Enabled && !objAPI.IsCompressionSupported() {
|
|
|
|
return fmt.Errorf("Backend does not support compression")
|
2020-12-04 18:32:35 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
// Heal
|
|
|
|
healCfg, err := heal.LookupConfig(s[config.HealSubSys][config.Default])
|
|
|
|
if err != nil {
|
2021-01-22 21:09:24 +01:00
|
|
|
return fmt.Errorf("Unable to apply heal config: %w", err)
|
2020-12-04 18:32:35 +01:00
|
|
|
}
|
|
|
|
|
2021-02-17 21:04:11 +01:00
|
|
|
// Scanner
|
|
|
|
scannerCfg, err := scanner.LookupConfig(s[config.ScannerSubSys][config.Default])
|
2020-12-04 18:32:35 +01:00
|
|
|
if err != nil {
|
2021-02-17 21:04:11 +01:00
|
|
|
return fmt.Errorf("Unable to apply scanner config: %w", err)
|
2020-12-04 18:32:35 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
// Apply configurations.
|
|
|
|
// We should not fail after this.
|
2021-01-22 21:09:24 +01:00
|
|
|
globalAPIConfig.init(apiConfig, objAPI.SetDriveCounts())
|
2020-12-04 18:32:35 +01:00
|
|
|
|
|
|
|
globalCompressConfigMu.Lock()
|
|
|
|
globalCompressConfig = cmpCfg
|
|
|
|
globalCompressConfigMu.Unlock()
|
|
|
|
|
|
|
|
globalHealConfigMu.Lock()
|
|
|
|
globalHealConfig = healCfg
|
|
|
|
globalHealConfigMu.Unlock()
|
|
|
|
|
2021-03-30 22:59:02 +02:00
|
|
|
// update dynamic scanner values.
|
|
|
|
scannerCycle.Update(scannerCfg.Cycle)
|
2021-02-17 21:04:11 +01:00
|
|
|
logger.LogIf(ctx, scannerSleeper.Update(scannerCfg.Delay, scannerCfg.MaxWait))
|
2020-12-04 18:32:35 +01:00
|
|
|
|
|
|
|
// Update all dynamic config values in memory.
|
|
|
|
globalServerConfigMu.Lock()
|
|
|
|
defer globalServerConfigMu.Unlock()
|
|
|
|
if globalServerConfig != nil {
|
|
|
|
for k := range config.SubSystemsDynamic {
|
|
|
|
globalServerConfig[k] = s[k]
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return nil
|
2017-03-31 07:26:24 +02:00
|
|
|
}
|
|
|
|
|
2019-11-19 22:48:13 +01:00
|
|
|
// Help - return sub-system level help
|
|
|
|
type Help struct {
|
|
|
|
SubSys string `json:"subSys"`
|
|
|
|
Description string `json:"description"`
|
|
|
|
MultipleTargets bool `json:"multipleTargets"`
|
|
|
|
KeysHelp config.HelpKVS `json:"keysHelp"`
|
|
|
|
}
|
|
|
|
|
2019-10-23 07:59:13 +02:00
|
|
|
// GetHelp - returns help for sub-sys, a key for a sub-system or all the help.
|
2019-11-19 22:48:13 +01:00
|
|
|
func GetHelp(subSys, key string, envOnly bool) (Help, error) {
|
2019-10-23 07:59:13 +02:00
|
|
|
if len(subSys) == 0 {
|
2019-11-27 18:36:08 +01:00
|
|
|
return Help{KeysHelp: config.HelpSubSysMap[subSys]}, nil
|
2018-09-06 17:03:18 +02:00
|
|
|
}
|
2019-10-30 08:04:39 +01:00
|
|
|
subSystemValue := strings.SplitN(subSys, config.SubSystemSeparator, 2)
|
|
|
|
if len(subSystemValue) == 0 {
|
2019-12-15 02:27:57 +01:00
|
|
|
return Help{}, config.Errorf("invalid number of arguments %s", subSys)
|
2019-10-30 08:04:39 +01:00
|
|
|
}
|
|
|
|
|
2019-11-27 18:36:08 +01:00
|
|
|
subSys = subSystemValue[0]
|
|
|
|
|
|
|
|
subSysHelp, ok := config.HelpSubSysMap[""].Lookup(subSys)
|
|
|
|
if !ok {
|
2019-12-15 02:27:57 +01:00
|
|
|
return Help{}, config.Errorf("unknown sub-system %s", subSys)
|
2018-09-06 17:03:18 +02:00
|
|
|
}
|
2019-10-30 08:04:39 +01:00
|
|
|
|
2019-11-27 18:36:08 +01:00
|
|
|
h, ok := config.HelpSubSysMap[subSys]
|
|
|
|
if !ok {
|
2019-12-15 02:27:57 +01:00
|
|
|
return Help{}, config.Errorf("unknown sub-system %s", subSys)
|
2019-11-27 18:36:08 +01:00
|
|
|
}
|
2019-10-23 07:59:13 +02:00
|
|
|
if key != "" {
|
2019-11-19 22:48:13 +01:00
|
|
|
value, ok := h.Lookup(key)
|
2019-10-23 07:59:13 +02:00
|
|
|
if !ok {
|
2019-12-15 02:27:57 +01:00
|
|
|
return Help{}, config.Errorf("unknown key %s for sub-system %s",
|
|
|
|
key, subSys)
|
2019-10-30 08:04:39 +01:00
|
|
|
}
|
2019-11-19 22:48:13 +01:00
|
|
|
h = config.HelpKVS{value}
|
2018-11-07 19:23:13 +01:00
|
|
|
}
|
|
|
|
|
2019-11-19 22:48:13 +01:00
|
|
|
envHelp := config.HelpKVS{}
|
2019-10-30 08:04:39 +01:00
|
|
|
if envOnly {
|
2020-01-21 01:48:19 +01:00
|
|
|
// Only for multiple targets, make sure
|
|
|
|
// to list the ENV, for regular k/v EnableKey is
|
|
|
|
// implicit, for ENVs we cannot make it implicit.
|
|
|
|
if subSysHelp.MultipleTargets {
|
|
|
|
envK := config.EnvPrefix + strings.Join([]string{
|
|
|
|
strings.ToTitle(subSys), strings.ToTitle(madmin.EnableKey),
|
|
|
|
}, config.EnvWordDelimiter)
|
|
|
|
envHelp = append(envHelp, config.HelpKV{
|
|
|
|
Key: envK,
|
|
|
|
Description: fmt.Sprintf("enable %s target, default is 'off'", subSys),
|
|
|
|
Optional: false,
|
|
|
|
Type: "on|off",
|
|
|
|
})
|
|
|
|
}
|
2019-11-19 22:48:13 +01:00
|
|
|
for _, hkv := range h {
|
2019-10-30 08:04:39 +01:00
|
|
|
envK := config.EnvPrefix + strings.Join([]string{
|
2019-11-19 22:48:13 +01:00
|
|
|
strings.ToTitle(subSys), strings.ToTitle(hkv.Key),
|
2019-10-30 08:04:39 +01:00
|
|
|
}, config.EnvWordDelimiter)
|
2019-11-19 22:48:13 +01:00
|
|
|
envHelp = append(envHelp, config.HelpKV{
|
|
|
|
Key: envK,
|
|
|
|
Description: hkv.Description,
|
|
|
|
Optional: hkv.Optional,
|
|
|
|
Type: hkv.Type,
|
|
|
|
})
|
2019-10-30 08:04:39 +01:00
|
|
|
}
|
2019-11-19 22:48:13 +01:00
|
|
|
h = envHelp
|
|
|
|
}
|
|
|
|
|
|
|
|
return Help{
|
|
|
|
SubSys: subSys,
|
|
|
|
Description: subSysHelp.Description,
|
|
|
|
MultipleTargets: subSysHelp.MultipleTargets,
|
|
|
|
KeysHelp: h,
|
|
|
|
}, nil
|
2019-10-23 07:59:13 +02:00
|
|
|
}
|
2018-09-06 17:03:18 +02:00
|
|
|
|
2019-10-23 07:59:13 +02:00
|
|
|
func newServerConfig() config.Config {
|
2019-11-14 02:38:05 +01:00
|
|
|
return config.New()
|
2017-03-01 18:17:04 +01:00
|
|
|
}
|
|
|
|
|
2018-10-09 23:00:01 +02:00
|
|
|
// newSrvConfig - initialize a new server config, saves env parameters if
|
2018-08-15 06:41:47 +02:00
|
|
|
// found, otherwise use default parameters
|
2018-10-09 23:00:01 +02:00
|
|
|
func newSrvConfig(objAPI ObjectLayer) error {
|
2018-08-15 06:41:47 +02:00
|
|
|
// Initialize server config.
|
|
|
|
srvCfg := newServerConfig()
|
|
|
|
|
2017-02-07 21:51:43 +01:00
|
|
|
// hold the mutex lock before a new config is assigned.
|
2017-11-29 22:12:47 +01:00
|
|
|
globalServerConfigMu.Lock()
|
|
|
|
globalServerConfig = srvCfg
|
|
|
|
globalServerConfigMu.Unlock()
|
2017-02-07 21:51:43 +01:00
|
|
|
|
|
|
|
// Save config into file.
|
2020-04-09 18:30:02 +02:00
|
|
|
return saveServerConfig(GlobalContext, objAPI, globalServerConfig)
|
2017-02-07 21:51:43 +01:00
|
|
|
}
|
|
|
|
|
2019-10-23 07:59:13 +02:00
|
|
|
func getValidConfig(objAPI ObjectLayer) (config.Config, error) {
|
2020-04-09 18:30:02 +02:00
|
|
|
return readServerConfig(GlobalContext, objAPI)
|
config/main: Re-write config files - add to new config v3
- New config format.
```
{
"version": "3",
"address": ":9000",
"backend": {
"type": "fs",
"disk": "/path"
},
"credential": {
"accessKey": "WLGDGYAQYIGI833EV05A",
"secretKey": "BYvgJM101sHngl2uzjXS/OBF/aMxAN06JrJ3qJlF"
},
"region": "us-east-1",
"logger": {
"file": {
"enable": false,
"fileName": "",
"level": "error"
},
"syslog": {
"enable": false,
"address": "",
"level": "debug"
},
"console": {
"enable": true,
"level": "fatal"
}
}
}
```
New command lines in lieu of supporting XL.
Minio initialize filesystem backend.
~~~
$ minio init fs <path>
~~~
Minio initialize XL backend.
~~~
$ minio init xl <url1>...<url16>
~~~
For 'fs' backend it starts the server.
~~~
$ minio server
~~~
For 'xl' backend it waits for servers to join.
~~~
$ minio server
... [PROGRESS BAR] of servers connecting
~~~
Now on other servers execute 'join' and they connect.
~~~
....
minio join <url1> -- from <url2> && minio server
minio join <url1> -- from <url3> && minio server
...
...
minio join <url1> -- from <url16> && minio server
~~~
2016-02-13 00:27:10 +01:00
|
|
|
}
|
|
|
|
|
2019-10-30 08:04:39 +01:00
|
|
|
// loadConfig - loads a new config from disk, overrides params
|
|
|
|
// from env if found and valid
|
2020-12-01 20:59:03 +01:00
|
|
|
func loadConfig(objAPI ObjectLayer) error {
|
|
|
|
srvCfg, err := getValidConfig(objAPI)
|
|
|
|
if err != nil {
|
|
|
|
return err
|
2017-03-16 19:06:17 +01:00
|
|
|
}
|
2016-12-07 12:41:54 +01:00
|
|
|
|
2018-08-15 06:41:47 +02:00
|
|
|
// Override any values from ENVs.
|
2021-01-22 21:09:24 +01:00
|
|
|
lookupConfigs(srvCfg, objAPI.SetDriveCounts())
|
2018-03-29 23:38:26 +02:00
|
|
|
|
2017-03-31 07:26:24 +02:00
|
|
|
// hold the mutex lock before a new config is assigned.
|
2017-11-29 22:12:47 +01:00
|
|
|
globalServerConfigMu.Lock()
|
|
|
|
globalServerConfig = srvCfg
|
|
|
|
globalServerConfigMu.Unlock()
|
config/main: Re-write config files - add to new config v3
- New config format.
```
{
"version": "3",
"address": ":9000",
"backend": {
"type": "fs",
"disk": "/path"
},
"credential": {
"accessKey": "WLGDGYAQYIGI833EV05A",
"secretKey": "BYvgJM101sHngl2uzjXS/OBF/aMxAN06JrJ3qJlF"
},
"region": "us-east-1",
"logger": {
"file": {
"enable": false,
"fileName": "",
"level": "error"
},
"syslog": {
"enable": false,
"address": "",
"level": "debug"
},
"console": {
"enable": true,
"level": "fatal"
}
}
}
```
New command lines in lieu of supporting XL.
Minio initialize filesystem backend.
~~~
$ minio init fs <path>
~~~
Minio initialize XL backend.
~~~
$ minio init xl <url1>...<url16>
~~~
For 'fs' backend it starts the server.
~~~
$ minio server
~~~
For 'xl' backend it waits for servers to join.
~~~
$ minio server
... [PROGRESS BAR] of servers connecting
~~~
Now on other servers execute 'join' and they connect.
~~~
....
minio join <url1> -- from <url2> && minio server
minio join <url1> -- from <url3> && minio server
...
...
minio join <url1> -- from <url16> && minio server
~~~
2016-02-13 00:27:10 +01:00
|
|
|
|
2017-03-31 07:26:24 +02:00
|
|
|
return nil
|
config/main: Re-write config files - add to new config v3
- New config format.
```
{
"version": "3",
"address": ":9000",
"backend": {
"type": "fs",
"disk": "/path"
},
"credential": {
"accessKey": "WLGDGYAQYIGI833EV05A",
"secretKey": "BYvgJM101sHngl2uzjXS/OBF/aMxAN06JrJ3qJlF"
},
"region": "us-east-1",
"logger": {
"file": {
"enable": false,
"fileName": "",
"level": "error"
},
"syslog": {
"enable": false,
"address": "",
"level": "debug"
},
"console": {
"enable": true,
"level": "fatal"
}
}
}
```
New command lines in lieu of supporting XL.
Minio initialize filesystem backend.
~~~
$ minio init fs <path>
~~~
Minio initialize XL backend.
~~~
$ minio init xl <url1>...<url16>
~~~
For 'fs' backend it starts the server.
~~~
$ minio server
~~~
For 'xl' backend it waits for servers to join.
~~~
$ minio server
... [PROGRESS BAR] of servers connecting
~~~
Now on other servers execute 'join' and they connect.
~~~
....
minio join <url1> -- from <url2> && minio server
minio join <url1> -- from <url3> && minio server
...
...
minio join <url1> -- from <url16> && minio server
~~~
2016-02-13 00:27:10 +01:00
|
|
|
}
|
2018-03-15 21:03:41 +01:00
|
|
|
|
2019-10-02 00:07:20 +02:00
|
|
|
// getOpenIDValidators - returns ValidatorList which contains
|
2018-10-09 23:00:01 +02:00
|
|
|
// enabled providers in server config.
|
|
|
|
// A new authentication provider is added like below
|
2019-10-02 00:07:20 +02:00
|
|
|
// * Add a new provider in pkg/iam/openid package.
|
2019-10-23 07:59:13 +02:00
|
|
|
func getOpenIDValidators(cfg openid.Config) *openid.Validators {
|
2019-10-02 00:07:20 +02:00
|
|
|
validators := openid.NewValidators()
|
2018-10-09 23:00:01 +02:00
|
|
|
|
2019-10-23 07:59:13 +02:00
|
|
|
if cfg.JWKS.URL != nil {
|
|
|
|
validators.Add(openid.NewJWT(cfg))
|
2018-10-09 23:00:01 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
return validators
|
|
|
|
}
|