mirror of
				https://github.com/minio/minio.git
				synced 2025-11-04 10:11:09 +01:00 
			
		
		
		
	- Supports migrating only when the credential ENVs are set, so any FS mode deployments which do not have ENVs set will continue to remain as is. - Credential ENVs can be rotated using MINIO_ACCESS_KEY_OLD and MINIO_SECRET_KEY_OLD envs, in such scenarios it allowed to rotate the encrypted content to a new admin key.
		
			
				
	
	
		
			244 lines
		
	
	
		
			7.9 KiB
		
	
	
	
		
			Go
		
	
	
	
	
	
			
		
		
	
	
			244 lines
		
	
	
		
			7.9 KiB
		
	
	
	
		
			Go
		
	
	
	
	
	
/*
 | 
						|
 * MinIO Cloud Storage, (C) 2017-2019 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/x509"
 | 
						|
	"errors"
 | 
						|
	"net"
 | 
						|
	"path/filepath"
 | 
						|
	"strings"
 | 
						|
	"time"
 | 
						|
 | 
						|
	dns2 "github.com/miekg/dns"
 | 
						|
	"github.com/minio/cli"
 | 
						|
	"github.com/minio/minio-go/v6/pkg/set"
 | 
						|
	"github.com/minio/minio/cmd/config"
 | 
						|
	"github.com/minio/minio/cmd/logger"
 | 
						|
	"github.com/minio/minio/pkg/auth"
 | 
						|
	"github.com/minio/minio/pkg/certs"
 | 
						|
	"github.com/minio/minio/pkg/env"
 | 
						|
)
 | 
						|
 | 
						|
func verifyObjectLayerFeatures(name string, objAPI ObjectLayer) {
 | 
						|
	if (globalAutoEncryption || GlobalKMS != nil) && !objAPI.IsEncryptionSupported() {
 | 
						|
		logger.Fatal(errInvalidArgument,
 | 
						|
			"Encryption support is requested but '%s' does not support encryption", name)
 | 
						|
	}
 | 
						|
 | 
						|
	if strings.HasPrefix(name, "gateway") {
 | 
						|
		if GlobalGatewaySSE.IsSet() && GlobalKMS == nil {
 | 
						|
			uiErr := config.ErrInvalidGWSSEEnvValue(nil).Msg("MINIO_GATEWAY_SSE set but KMS is not configured")
 | 
						|
			logger.Fatal(uiErr, "Unable to start gateway with SSE")
 | 
						|
		}
 | 
						|
	}
 | 
						|
 | 
						|
	if globalCompressConfig.Enabled && !objAPI.IsCompressionSupported() {
 | 
						|
		logger.Fatal(errInvalidArgument,
 | 
						|
			"Compression support is requested but '%s' does not support compression", name)
 | 
						|
	}
 | 
						|
}
 | 
						|
 | 
						|
// Check for updates and print a notification message
 | 
						|
func checkUpdate(mode string) {
 | 
						|
	// Its OK to ignore any errors during doUpdate() here.
 | 
						|
	if updateMsg, _, currentReleaseTime, latestReleaseTime, err := getUpdateInfo(2*time.Second, mode); err == nil {
 | 
						|
		if updateMsg == "" {
 | 
						|
			return
 | 
						|
		}
 | 
						|
		if globalInplaceUpdateDisabled {
 | 
						|
			logStartupMessage(updateMsg)
 | 
						|
		} else {
 | 
						|
			logStartupMessage(prepareUpdateMessage("Run `mc admin update`", latestReleaseTime.Sub(currentReleaseTime)))
 | 
						|
		}
 | 
						|
	}
 | 
						|
}
 | 
						|
 | 
						|
func newConfigDirFromCtx(ctx *cli.Context, option string, getDefaultDir func() string) (*ConfigDir, bool) {
 | 
						|
	var dir string
 | 
						|
	var dirSet bool
 | 
						|
 | 
						|
	switch {
 | 
						|
	case ctx.IsSet(option):
 | 
						|
		dir = ctx.String(option)
 | 
						|
		dirSet = true
 | 
						|
	case ctx.GlobalIsSet(option):
 | 
						|
		dir = ctx.GlobalString(option)
 | 
						|
		dirSet = true
 | 
						|
		// cli package does not expose parent's option option.  Below code is workaround.
 | 
						|
		if dir == "" || dir == getDefaultDir() {
 | 
						|
			dirSet = false // Unset to false since GlobalIsSet() true is a false positive.
 | 
						|
			if ctx.Parent().GlobalIsSet(option) {
 | 
						|
				dir = ctx.Parent().GlobalString(option)
 | 
						|
				dirSet = true
 | 
						|
			}
 | 
						|
		}
 | 
						|
	default:
 | 
						|
		// Neither local nor global option is provided.  In this case, try to use
 | 
						|
		// default directory.
 | 
						|
		dir = getDefaultDir()
 | 
						|
		if dir == "" {
 | 
						|
			logger.FatalIf(errInvalidArgument, "%s option must be provided", option)
 | 
						|
		}
 | 
						|
	}
 | 
						|
 | 
						|
	if dir == "" {
 | 
						|
		logger.FatalIf(errors.New("empty directory"), "%s directory cannot be empty", option)
 | 
						|
	}
 | 
						|
 | 
						|
	// Disallow relative paths, figure out absolute paths.
 | 
						|
	dirAbs, err := filepath.Abs(dir)
 | 
						|
	logger.FatalIf(err, "Unable to fetch absolute path for %s=%s", option, dir)
 | 
						|
 | 
						|
	logger.FatalIf(mkdirAllIgnorePerm(dirAbs), "Unable to create directory specified %s=%s", option, dir)
 | 
						|
 | 
						|
	return &ConfigDir{path: dirAbs}, dirSet
 | 
						|
}
 | 
						|
 | 
						|
func handleCommonCmdArgs(ctx *cli.Context) {
 | 
						|
 | 
						|
	// Get "json" flag from command line argument and
 | 
						|
	// enable json and quite modes if json flag is turned on.
 | 
						|
	globalCLIContext.JSON = ctx.IsSet("json") || ctx.GlobalIsSet("json")
 | 
						|
	if globalCLIContext.JSON {
 | 
						|
		logger.EnableJSON()
 | 
						|
	}
 | 
						|
 | 
						|
	// Get quiet flag from command line argument.
 | 
						|
	globalCLIContext.Quiet = ctx.IsSet("quiet") || ctx.GlobalIsSet("quiet")
 | 
						|
	if globalCLIContext.Quiet {
 | 
						|
		logger.EnableQuiet()
 | 
						|
	}
 | 
						|
 | 
						|
	// Get anonymous flag from command line argument.
 | 
						|
	globalCLIContext.Anonymous = ctx.IsSet("anonymous") || ctx.GlobalIsSet("anonymous")
 | 
						|
	if globalCLIContext.Anonymous {
 | 
						|
		logger.EnableAnonymous()
 | 
						|
	}
 | 
						|
 | 
						|
	// Fetch address option
 | 
						|
	globalCLIContext.Addr = ctx.GlobalString("address")
 | 
						|
	if globalCLIContext.Addr == "" || globalCLIContext.Addr == ":"+globalMinioDefaultPort {
 | 
						|
		globalCLIContext.Addr = ctx.String("address")
 | 
						|
	}
 | 
						|
 | 
						|
	// Set all config, certs and CAs directories.
 | 
						|
	var configSet, certsSet bool
 | 
						|
	globalConfigDir, configSet = newConfigDirFromCtx(ctx, "config-dir", defaultConfigDir.Get)
 | 
						|
	globalCertsDir, certsSet = newConfigDirFromCtx(ctx, "certs-dir", defaultCertsDir.Get)
 | 
						|
 | 
						|
	// Remove this code when we deprecate and remove config-dir.
 | 
						|
	// This code is to make sure we inherit from the config-dir
 | 
						|
	// option if certs-dir is not provided.
 | 
						|
	if !certsSet && configSet {
 | 
						|
		globalCertsDir = &ConfigDir{path: filepath.Join(globalConfigDir.Get(), certsDir)}
 | 
						|
	}
 | 
						|
 | 
						|
	globalCertsCADir = &ConfigDir{path: filepath.Join(globalCertsDir.Get(), certsCADir)}
 | 
						|
 | 
						|
	logger.FatalIf(mkdirAllIgnorePerm(globalCertsCADir.Get()), "Unable to create certs CA directory at %s", globalCertsCADir.Get())
 | 
						|
 | 
						|
	// Check "compat" flag from command line argument.
 | 
						|
	globalCLIContext.StrictS3Compat = ctx.IsSet("compat") || ctx.GlobalIsSet("compat")
 | 
						|
}
 | 
						|
 | 
						|
func handleCommonEnvVars() {
 | 
						|
	var err error
 | 
						|
	globalBrowserEnabled, err = config.ParseBool(env.Get(config.EnvBrowser, config.StateOn))
 | 
						|
	if err != nil {
 | 
						|
		logger.Fatal(config.ErrInvalidBrowserValue(err), "Invalid MINIO_BROWSER value in environment variable")
 | 
						|
	}
 | 
						|
 | 
						|
	domains := env.Get(config.EnvDomain, "")
 | 
						|
	if len(domains) != 0 {
 | 
						|
		for _, domainName := range strings.Split(domains, config.ValueSeparator) {
 | 
						|
			if _, ok := dns2.IsDomainName(domainName); !ok {
 | 
						|
				logger.Fatal(config.ErrInvalidDomainValue(nil).Msg("Unknown value `%s`", domainName),
 | 
						|
					"Invalid MINIO_DOMAIN value in environment variable")
 | 
						|
			}
 | 
						|
			globalDomainNames = append(globalDomainNames, domainName)
 | 
						|
		}
 | 
						|
	}
 | 
						|
 | 
						|
	publicIPs := env.Get(config.EnvPublicIPs, "")
 | 
						|
	if len(publicIPs) != 0 {
 | 
						|
		minioEndpoints := strings.Split(publicIPs, config.ValueSeparator)
 | 
						|
		var domainIPs = set.NewStringSet()
 | 
						|
		for _, endpoint := range minioEndpoints {
 | 
						|
			if net.ParseIP(endpoint) == nil {
 | 
						|
				// Checking if the IP is a DNS entry.
 | 
						|
				addrs, err := net.LookupHost(endpoint)
 | 
						|
				if err != nil {
 | 
						|
					logger.FatalIf(err, "Unable to initialize MinIO server with [%s] invalid entry found in MINIO_PUBLIC_IPS", endpoint)
 | 
						|
				}
 | 
						|
				for _, addr := range addrs {
 | 
						|
					domainIPs.Add(addr)
 | 
						|
				}
 | 
						|
				continue
 | 
						|
			}
 | 
						|
			domainIPs.Add(endpoint)
 | 
						|
		}
 | 
						|
		updateDomainIPs(domainIPs)
 | 
						|
	} else {
 | 
						|
		// Add found interfaces IP address to global domain IPS,
 | 
						|
		// loopback addresses will be naturally dropped.
 | 
						|
		updateDomainIPs(localIP4)
 | 
						|
	}
 | 
						|
 | 
						|
	// In place update is true by default if the MINIO_UPDATE is not set
 | 
						|
	// or is not set to 'off', if MINIO_UPDATE is set to 'off' then
 | 
						|
	// in-place update is off.
 | 
						|
	globalInplaceUpdateDisabled = strings.EqualFold(env.Get(config.EnvUpdate, config.StateOn), config.StateOff)
 | 
						|
 | 
						|
	accessKey := env.Get(config.EnvAccessKey, "")
 | 
						|
	secretKey := env.Get(config.EnvSecretKey, "")
 | 
						|
	if accessKey != "" && secretKey != "" {
 | 
						|
		cred, err := auth.CreateCredentials(accessKey, secretKey)
 | 
						|
		if err != nil {
 | 
						|
			logger.Fatal(config.ErrInvalidCredentials(err),
 | 
						|
				"Unable to validate credentials inherited from the shell environment")
 | 
						|
		}
 | 
						|
		globalActiveCred = cred
 | 
						|
		globalConfigEncrypted = true
 | 
						|
	}
 | 
						|
}
 | 
						|
 | 
						|
func logStartupMessage(msg string) {
 | 
						|
	if globalConsoleSys != nil {
 | 
						|
		globalConsoleSys.Send(msg, string(logger.All))
 | 
						|
	}
 | 
						|
	logger.StartupMessage(msg)
 | 
						|
}
 | 
						|
 | 
						|
func getTLSConfig() (x509Certs []*x509.Certificate, c *certs.Certs, secureConn bool, err error) {
 | 
						|
	if !(isFile(getPublicCertFile()) && isFile(getPrivateKeyFile())) {
 | 
						|
		return nil, nil, false, nil
 | 
						|
	}
 | 
						|
 | 
						|
	if x509Certs, err = config.ParsePublicCertFile(getPublicCertFile()); err != nil {
 | 
						|
		return nil, nil, false, err
 | 
						|
	}
 | 
						|
 | 
						|
	c, err = certs.New(getPublicCertFile(), getPrivateKeyFile(), config.LoadX509KeyPair)
 | 
						|
	if err != nil {
 | 
						|
		return nil, nil, false, err
 | 
						|
	}
 | 
						|
 | 
						|
	secureConn = true
 | 
						|
	return x509Certs, c, secureConn, nil
 | 
						|
}
 |