Repository: minio/minio (language: go)

Issue:
Root Disabled by Default makes docs misleading
## NOTE
If this case is urgent, please subscribe to [Subnet](https://min.io/pricing) so that our 24/7 support team may help you faster.


Root is disabled when following docs. Following [this guide for linux](https://min.io/docs/minio/linux/index.html) root is disabled. 


## Expected Behavior
To be able to login as root after installing per the docs

## Current Behavior
Account is disabled and I cannot access minio console

## Possible Solution
Update docs

## Steps to Reproduce (for bugs)
1. Follow the install guide on https://min.io/docs/minio/linux/index.html
2. Error occurs when accessing console

## Context
<!--- How has this issue affected you? What are you trying to accomplish? -->
<!--- Providing context helps us come up with a solution that is most useful in the real world -->


## Your Environment

* Version used (`minio --version`): minio version RELEASE.2023-05-04T21-44-30Z (commit-id=5569acd95cbc8c7d3fac59cf2aba77baa1b9bbeb)
* Server setup and configuration: default from link above with single directory
* Operating System and version (`uname -a`): Linux  4.18.0-425.13.1.el8_7.x86_64 #1 SMP Thu Feb 2 13:01:45 EST 2023 x86_64 x86_64 x86_64 GNU/Linux



Discussion / hints:
root is never disabled by default @bck01215 root is only disabled if you ask for it. 

```
MINIO_API_ROOT_ACCESS=off
```

> `MINIO_API_ROOT_ACCESS=off`

Interesting. As stated before, I've followed the docs above.
![image](https://github.com/minio/minio/assets/77836661/fa5e5a70-14ce-47aa-8c82-e4534ecbb52f)

I experience this issue with podman as well. I've completely removed all data and started from scratch.

/etc/default/minio

```
MINIO_ROOT_USER=****
MINIO_ROOT_PASSWORD=****
MINIO_API_ROOT_ACCESS=on #previously absent
MINIO_VOLUMES='/opt/minio'
MINIO_OPTS='--console-address ":5002" --address ":5001"'
MINIO_SERVER_URL=http://minio01.service.com:5001
```
Systemd
```
[Unit]
Description=MinIO
Documentation=https://docs.min.io
Wants=network-online.target
After=network-online.target
AssertFileIsExecutable=/usr/local/bin/minio

[Service]
Type=notify

WorkingDirectory=/usr/local

User=root
Group=root

EnvironmentFile=-/etc/default/minio
ExecStartPre=/bin/bash -c "if [ -z \"${MINIO_VOLUMES}\" ]; then echo \"Variable MINIO_VOLUMES not set in /etc/default/minio\"; exit 1; fi"
ExecStart=/usr/local/bin/minio server $MINIO_OPTS $MINIO_VOLUMES

# Let systemd restart this service always
Restart=always

# Specifies the maximum file descriptor number that can be opened by this process
LimitNOFILE=1048576

# Specifies the maximum number of threads this process can create
TasksMax=infinity

# Disable timeout logic and wait until process is stopped
TimeoutStopSec=infinity
SendSIGKILL=no

[Install]
WantedBy=multi-user.target

# Built for ${project.name}-${project.version} (${project.name})
```
@harshavardhana  I tested with [minio-20230131022419.0.0.x86_64.rpm](https://dl.min.io/server/minio/release/linux-amd64/archive/minio-20230131022419.0.0.x86_64.rpm) and the issue does not occur
Here is what I did 

```
~ wget https://dl.minio.io/server/minio/release/linux-amd64/minio
~ chmod +x minio
~ MINIO_ROOT_USER=myroot MINIO_ROOT_PASSWORD=myrootpassword ./minio server /tmp/fresh
Formatting 1st pool, 1 set(s), 1 drives per set.
WARNING: Host local has more than 0 drives of set. A host failure will result in data becoming unavailable.
MinIO Object Storage Server
Copyright: 2015-2023 MinIO, Inc.
License: GNU AGPLv3 <https://www.gnu.org/licenses/agpl-3.0.html>
Version: RELEASE.2023-05-04T21-44-30Z (go1.20.3 linux/amd64)

Status:         1 Online, 0 Offline. 
S3-API: http://10.0.0.185:9000  http://172.17.0.1:9000  http://172.19.0.1:9000  http://172.23.0.1:9000  http://127.0.0.1:9000           
RootUser: myroot 
RootPass: myrootpassword 

Console: http://10.0.0.185:45419 http://172.17.0.1:45419 http://172.19.0.1:45419 http://172.23.0.1:45419 http://127.0.0.1:45419      
RootUser: myroot 
RootPass: myrootpassword 

Command-line: https://min.io/docs/minio/linux/reference/minio-mc.html#quickstart
   $ mc alias set myminio http://10.0.0.185:9000 myroot myrootpassword

Documentation: https://min.io/docs/minio/linux/index.html
Warning: The standard parity is set to 0. This can lead to data loss.

~ mc alias set myroot http://localhost:9000 myroot myrootpassword
Added `myroot` successfully.

~ mc admin info myroot/
●  localhost:9000
   Uptime: 44 seconds 
   Version: 2023-05-04T21:44:30Z
   Network: 1/1 OK 
   Drives: 1/1 OK 
   Pool: 1

Pools:
   1st, Erasure sets: 1, Drives per erasure set: 1

1 drive online, 0 drives offline
```

Unless you forgot something that you were you playing around with. Check if you have by mistake did `mc admin config set alias/ api root_access=off`

But this is definitely not the default behavior.

Fix patch:
diff --git a/cmd/handler-api.go b/cmd/handler-api.go
index 29fe8f17d810d..05f357328fbbd 100644
--- a/cmd/handler-api.go
+++ b/cmd/handler-api.go
@@ -97,8 +97,17 @@ func (t *apiConfig) init(cfg api.Config, setDriveCounts []int) {
 	t.mu.Lock()
 	defer t.mu.Unlock()
 
-	t.clusterDeadline = cfg.ClusterDeadline
-	t.corsAllowOrigins = cfg.CorsAllowOrigin
+	clusterDeadline := cfg.ClusterDeadline
+	if clusterDeadline == 0 {
+		clusterDeadline = 10 * time.Second
+	}
+	t.clusterDeadline = clusterDeadline
+	corsAllowOrigin := cfg.CorsAllowOrigin
+	if len(corsAllowOrigin) == 0 {
+		corsAllowOrigin = []string{"*"}
+	}
+	t.corsAllowOrigins = corsAllowOrigin
+
 	maxSetDrives := 0
 	for _, setDriveCount := range setDriveCounts {
 		t.totalDriveCount += setDriveCount
@@ -136,13 +145,16 @@ func (t *apiConfig) init(cfg api.Config, setDriveCounts []int) {
 		t.requestsPool = make(chan struct{}, apiRequestsMaxPerNode)
 	}
 	t.requestsDeadline = cfg.RequestsDeadline
-	t.listQuorum = cfg.ListQuorum
+	listQuorum := cfg.ListQuorum
+	if listQuorum == "" {
+		listQuorum = "strict"
+	}
+	t.listQuorum = listQuorum
 	if globalReplicationPool != nil &&
 		cfg.ReplicationPriority != t.replicationPriority {
 		globalReplicationPool.ResizeWorkerPriority(cfg.ReplicationPriority)
 	}
 	t.replicationPriority = cfg.ReplicationPriority
-
 	if globalTransitionState != nil && cfg.TransitionWorkers != t.transitionWorkers {
 		globalTransitionState.UpdateWorkers(cfg.TransitionWorkers)
 	}
@@ -181,6 +193,10 @@ func (t *apiConfig) getListQuorum() string {
 	t.mu.RLock()
 	defer t.mu.RUnlock()
 
+	if t.listQuorum == "" {
+		return "strict"
+	}
+
 	return t.listQuorum
 }
 
@@ -188,6 +204,10 @@ func (t *apiConfig) getCorsAllowOrigins() []string {
 	t.mu.RLock()
 	defer t.mu.RUnlock()
 
+	if len(t.corsAllowOrigins) == 0 {
+		return []string{"*"}
+	}
+
 	corsAllowOrigins := make([]string, len(t.corsAllowOrigins))
 	copy(corsAllowOrigins, t.corsAllowOrigins)
 	return corsAllowOrigins
@@ -316,6 +336,10 @@ func (t *apiConfig) getReplicationPriority() string {
 	t.mu.RLock()
 	defer t.mu.RUnlock()
 
+	if t.replicationPriority == "" {
+		return "auto"
+	}
+
 	return t.replicationPriority
 }
 
@@ -323,5 +347,9 @@ func (t *apiConfig) getTransitionWorkers() int {
 	t.mu.RLock()
 	defer t.mu.RUnlock()
 
+	if t.transitionWorkers <= 0 {
+		return runtime.GOMAXPROCS(0) / 2
+	}
+
 	return t.transitionWorkers
 }
diff --git a/internal/config/api/api.go b/internal/config/api/api.go
index 3509379fca7aa..ee0b7550fa33c 100644
--- a/internal/config/api/api.go
+++ b/internal/config/api/api.go
@@ -21,7 +21,6 @@ import (
 	"encoding/json"
 	"errors"
 	"fmt"
-	"runtime"
 	"strconv"
 	"strings"
 	"time"
@@ -180,12 +179,23 @@ func LookupConfig(kvs config.KVS) (cfg Config, err error) {
 		return cfg, err
 	}
 
+	disableODirect := env.Get(EnvAPIDisableODirect, kvs.Get(apiDisableODirect)) == config.EnableOn
+	gzipObjects := env.Get(EnvAPIGzipObjects, kvs.Get(apiGzipObjects)) == config.EnableOn
+	rootAccess := env.Get(EnvAPIRootAccess, kvs.Get(apiRootAccess)) == config.EnableOn
+
+	cfg = Config{
+		DisableODirect: disableODirect,
+		GzipObjects:    gzipObjects,
+		RootAccess:     rootAccess,
+	}
+
 	// Check environment variables parameters
 	requestsMax, err := strconv.Atoi(env.Get(EnvAPIRequestsMax, kvs.GetWithDefault(apiRequestsMax, DefaultKVS)))
 	if err != nil {
 		return cfg, err
 	}
 
+	cfg.RequestsMax = requestsMax
 	if requestsMax < 0 {
 		return cfg, errors.New("invalid API max requests value")
 	}
@@ -194,28 +204,33 @@ func LookupConfig(kvs config.KVS) (cfg Config, err error) {
 	if err != nil {
 		return cfg, err
 	}
+	cfg.RequestsDeadline = requestsDeadline
 
 	clusterDeadline, err := time.ParseDuration(env.Get(EnvAPIClusterDeadline, kvs.GetWithDefault(apiClusterDeadline, DefaultKVS)))
 	if err != nil {
 		return cfg, err
 	}
+	cfg.ClusterDeadline = clusterDeadline
 
 	corsAllowOrigin := strings.Split(env.Get(EnvAPICorsAllowOrigin, kvs.Get(apiCorsAllowOrigin)), ",")
 	if len(corsAllowOrigin) == 0 {
 		corsAllowOrigin = []string{"*"} // defaults to '*'
 	}
+	cfg.CorsAllowOrigin = corsAllowOrigin
 
 	remoteTransportDeadline, err := time.ParseDuration(env.Get(EnvAPIRemoteTransportDeadline, kvs.GetWithDefault(apiRemoteTransportDeadline, DefaultKVS)))
 	if err != nil {
 		return cfg, err
 	}
+	cfg.RemoteTransportDeadline = remoteTransportDeadline
 
 	listQuorum := env.Get(EnvAPIListQuorum, kvs.GetWithDefault(apiListQuorum, DefaultKVS))
 	switch listQuorum {
 	case "strict", "optimal", "reduced", "disk":
 	default:
-		return cfg, fmt.Errorf("invalid value %v for list_quorum", listQuorum)
+		return cfg, fmt.Errorf("invalid value %v for list_quorum: will default to 'strict'", listQuorum)
 	}
+	cfg.ListQuorum = listQuorum
 
 	replicationPriority := env.Get(EnvAPIReplicationPriority, kvs.GetWithDefault(apiReplicationPriority, DefaultKVS))
 	switch replicationPriority {
@@ -223,14 +238,13 @@ func LookupConfig(kvs config.KVS) (cfg Config, err error) {
 	default:
 		return cfg, fmt.Errorf("invalid value %v for replication_priority", replicationPriority)
 	}
+	cfg.ReplicationPriority = replicationPriority
 
 	transitionWorkers, err := strconv.Atoi(env.Get(EnvAPITransitionWorkers, kvs.GetWithDefault(apiTransitionWorkers, DefaultKVS)))
 	if err != nil {
 		return cfg, err
 	}
-	if transitionWorkers < runtime.GOMAXPROCS(0)/2 {
-		return cfg, config.ErrInvalidTransitionWorkersValue(nil)
-	}
+	cfg.TransitionWorkers = transitionWorkers
 
 	v := env.Get(EnvAPIDeleteCleanupInterval, kvs.Get(apiDeleteCleanupInterval))
 	if v == "" {
@@ -241,35 +255,19 @@ func LookupConfig(kvs config.KVS) (cfg Config, err error) {
 	if err != nil {
 		return cfg, err
 	}
+	cfg.DeleteCleanupInterval = deleteCleanupInterval
 
 	staleUploadsCleanupInterval, err := time.ParseDuration(env.Get(EnvAPIStaleUploadsCleanupInterval, kvs.GetWithDefault(apiStaleUploadsCleanupInterval, DefaultKVS)))
 	if err != nil {
 		return cfg, err
 	}
+	cfg.StaleUploadsCleanupInterval = staleUploadsCleanupInterval
 
 	staleUploadsExpiry, err := time.ParseDuration(env.Get(EnvAPIStaleUploadsExpiry, kvs.GetWithDefault(apiStaleUploadsExpiry, DefaultKVS)))
 	if err != nil {
 		return cfg, err
 	}
+	cfg.StaleUploadsExpiry = staleUploadsExpiry
 
-	disableODirect := env.Get(EnvAPIDisableODirect, kvs.Get(apiDisableODirect)) == config.EnableOn
-	gzipObjects := env.Get(EnvAPIGzipObjects, kvs.Get(apiGzipObjects)) == config.EnableOn
-	rootAccess := env.Get(EnvAPIRootAccess, kvs.Get(apiRootAccess)) == config.EnableOn
-
-	return Config{
-		RequestsMax:                 requestsMax,
-		RequestsDeadline:            requestsDeadline,
-		ClusterDeadline:             clusterDeadline,
-		CorsAllowOrigin:             corsAllowOrigin,
-		RemoteTransportDeadline:     remoteTransportDeadline,
-		ListQuorum:                  listQuorum,
-		ReplicationPriority:         replicationPriority,
-		TransitionWorkers:           transitionWorkers,
-		StaleUploadsCleanupInterval: staleUploadsCleanupInterval,
-		StaleUploadsExpiry:          staleUploadsExpiry,
-		DeleteCleanupInterval:       deleteCleanupInterval,
-		DisableODirect:              disableODirect,
-		GzipObjects:                 gzipObjects,
-		RootAccess:                  rootAccess,
-	}, nil
+	return cfg, nil
 }


Test patch: