mirror of
https://github.com/minio/minio.git
synced 2024-12-24 06:05:55 -05:00
5a80cbec2a
This PR adds pass-through, single encryption at gateway and double encryption support (gateway encryption with pass through of SSE headers to backend). If KMS is set up (either with Vault as KMS or using MINIO_SSE_MASTER_KEY),gateway will automatically perform single encryption. If MINIO_GATEWAY_SSE is set up in addition to Vault KMS, double encryption is performed.When neither KMS nor MINIO_GATEWAY_SSE is set, do a pass through to backend. When double encryption is specified, MINIO_GATEWAY_SSE can be set to "C" for SSE-C encryption at gateway and backend, "S3" for SSE-S3 encryption at gateway/backend or both to support more than one option. Fixes #6323, #6696
310 lines
8.8 KiB
Go
310 lines
8.8 KiB
Go
/*
|
|
* Minio Cloud Storage, (C) 2017, 2018 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 (
|
|
"context"
|
|
"fmt"
|
|
"net/url"
|
|
"os"
|
|
"os/signal"
|
|
"strings"
|
|
"syscall"
|
|
|
|
"github.com/gorilla/mux"
|
|
"github.com/minio/cli"
|
|
xhttp "github.com/minio/minio/cmd/http"
|
|
"github.com/minio/minio/cmd/logger"
|
|
"github.com/minio/minio/pkg/certs"
|
|
)
|
|
|
|
func init() {
|
|
logger.Init(GOPATH, GOROOT)
|
|
logger.RegisterUIError(fmtError)
|
|
}
|
|
|
|
var (
|
|
gatewayCmd = cli.Command{
|
|
Name: "gateway",
|
|
Usage: "start object storage gateway",
|
|
Flags: append(serverFlags, globalFlags...),
|
|
HideHelpCommand: true,
|
|
}
|
|
)
|
|
|
|
// RegisterGatewayCommand registers a new command for gateway.
|
|
func RegisterGatewayCommand(cmd cli.Command) error {
|
|
cmd.Flags = append(append(cmd.Flags, append(cmd.Flags, serverFlags...)...), globalFlags...)
|
|
gatewayCmd.Subcommands = append(gatewayCmd.Subcommands, cmd)
|
|
return nil
|
|
}
|
|
|
|
// ParseGatewayEndpoint - Return endpoint.
|
|
func ParseGatewayEndpoint(arg string) (endPoint string, secure bool, err error) {
|
|
schemeSpecified := len(strings.Split(arg, "://")) > 1
|
|
if !schemeSpecified {
|
|
// Default connection will be "secure".
|
|
arg = "https://" + arg
|
|
}
|
|
|
|
u, err := url.Parse(arg)
|
|
if err != nil {
|
|
return "", false, err
|
|
}
|
|
|
|
switch u.Scheme {
|
|
case "http":
|
|
return u.Host, false, nil
|
|
case "https":
|
|
return u.Host, true, nil
|
|
default:
|
|
return "", false, fmt.Errorf("Unrecognized scheme %s", u.Scheme)
|
|
}
|
|
}
|
|
|
|
// ValidateGatewayArguments - Validate gateway arguments.
|
|
func ValidateGatewayArguments(serverAddr, endpointAddr string) error {
|
|
if err := CheckLocalServerAddr(serverAddr); err != nil {
|
|
return err
|
|
}
|
|
|
|
if endpointAddr != "" {
|
|
// Reject the endpoint if it points to the gateway handler itself.
|
|
sameTarget, err := sameLocalAddrs(endpointAddr, serverAddr)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
if sameTarget {
|
|
return fmt.Errorf("endpoint points to the local gateway")
|
|
}
|
|
}
|
|
return nil
|
|
}
|
|
|
|
// StartGateway - handler for 'minio gateway <name>'.
|
|
func StartGateway(ctx *cli.Context, gw Gateway) {
|
|
if gw == nil {
|
|
logger.FatalIf(errUnexpected, "Gateway implementation not initialized")
|
|
}
|
|
|
|
// Disable logging until gateway initialization is complete, any
|
|
// error during initialization will be shown as a fatal message
|
|
logger.Disable = true
|
|
|
|
// Validate if we have access, secret set through environment.
|
|
gatewayName := gw.Name()
|
|
if ctx.Args().First() == "help" {
|
|
cli.ShowCommandHelpAndExit(ctx, gatewayName, 1)
|
|
}
|
|
|
|
// Handle common command args.
|
|
handleCommonCmdArgs(ctx)
|
|
|
|
// Get port to listen on from gateway address
|
|
globalMinioHost, globalMinioPort = mustSplitHostPort(globalCLIContext.Addr)
|
|
|
|
// On macOS, if a process already listens on LOCALIPADDR:PORT, net.Listen() falls back
|
|
// to IPv6 address ie minio will start listening on IPv6 address whereas another
|
|
// (non-)minio process is listening on IPv4 of given port.
|
|
// To avoid this error situation we check for port availability.
|
|
logger.FatalIf(checkPortAvailability(globalMinioPort), "Unable to start the gateway")
|
|
|
|
// Check and load TLS certificates.
|
|
var err error
|
|
globalPublicCerts, globalTLSCerts, globalIsSSL, err = getTLSConfig()
|
|
logger.FatalIf(err, "Invalid TLS certificate file")
|
|
|
|
// Check and load Root CAs.
|
|
globalRootCAs, err = getRootCAs(globalCertsCADir.Get())
|
|
logger.FatalIf(err, "Failed to read root CAs (%v)", err)
|
|
|
|
// Handle common env vars.
|
|
handleCommonEnvVars()
|
|
|
|
// Handle gateway specific env
|
|
handleGatewayEnvVars()
|
|
|
|
// Validate if we have access, secret set through environment.
|
|
if !globalIsEnvCreds {
|
|
logger.Fatal(uiErrEnvCredentialsMissingGateway(nil), "Unable to start gateway")
|
|
}
|
|
|
|
// Set system resources to maximum.
|
|
logger.LogIf(context.Background(), setMaxResources())
|
|
|
|
initNSLock(false) // Enable local namespace lock.
|
|
|
|
router := mux.NewRouter().SkipClean(true)
|
|
|
|
if globalEtcdClient != nil {
|
|
// Enable STS router if etcd is enabled.
|
|
registerSTSRouter(router)
|
|
}
|
|
|
|
// Enable IAM admin APIs if etcd is enabled, if not just enable basic
|
|
// operations such as profiling, server info etc.
|
|
registerAdminRouter(router, globalEtcdClient != nil)
|
|
|
|
// Add healthcheck router
|
|
registerHealthCheckRouter(router)
|
|
|
|
// Add server metrics router
|
|
registerMetricsRouter(router)
|
|
|
|
// Register web router when its enabled.
|
|
if globalIsBrowserEnabled {
|
|
logger.FatalIf(registerWebRouter(router), "Unable to configure web browser")
|
|
}
|
|
|
|
// Currently only NAS and S3 gateway support encryption headers.
|
|
encryptionEnabled := gatewayName == "s3" || gatewayName == "nas"
|
|
|
|
// Add API router.
|
|
registerAPIRouter(router, encryptionEnabled)
|
|
|
|
// Dummy endpoint representing gateway instance.
|
|
globalEndpoints = []Endpoint{{
|
|
URL: &url.URL{Path: "/minio/gateway"},
|
|
IsLocal: true,
|
|
}}
|
|
|
|
// Initialize Admin Peers.
|
|
initGlobalAdminPeers(globalEndpoints)
|
|
|
|
var getCert certs.GetCertificateFunc
|
|
if globalTLSCerts != nil {
|
|
getCert = globalTLSCerts.GetCertificate
|
|
}
|
|
|
|
globalHTTPServer = xhttp.NewServer([]string{globalCLIContext.Addr}, criticalErrorHandler{registerHandlers(router, globalHandlers...)}, getCert)
|
|
globalHTTPServer.UpdateBytesReadFunc = globalConnStats.incInputBytes
|
|
globalHTTPServer.UpdateBytesWrittenFunc = globalConnStats.incOutputBytes
|
|
go func() {
|
|
globalHTTPServerErrorCh <- globalHTTPServer.Start()
|
|
}()
|
|
|
|
signal.Notify(globalOSSignalCh, os.Interrupt, syscall.SIGTERM)
|
|
|
|
// !!! Do not move this block !!!
|
|
// For all gateways, the config needs to be loaded from env
|
|
// prior to initializing the gateway layer
|
|
{
|
|
// Initialize server config.
|
|
srvCfg := newServerConfig()
|
|
|
|
// Override any values from ENVs.
|
|
srvCfg.loadFromEnvs()
|
|
|
|
// hold the mutex lock before a new config is assigned.
|
|
globalServerConfigMu.Lock()
|
|
globalServerConfig = srvCfg
|
|
globalServerConfigMu.Unlock()
|
|
}
|
|
|
|
newObject, err := gw.NewGatewayLayer(globalServerConfig.GetCredential())
|
|
if err != nil {
|
|
// Stop watching for any certificate changes.
|
|
globalTLSCerts.Stop()
|
|
|
|
globalHTTPServer.Shutdown()
|
|
logger.FatalIf(err, "Unable to initialize gateway backend")
|
|
}
|
|
|
|
if globalEtcdClient != nil && gatewayName == "nas" {
|
|
// Create a new config system.
|
|
globalConfigSys = NewConfigSys()
|
|
|
|
// Load globalServerConfig from etcd
|
|
_ = globalConfigSys.Init(newObject)
|
|
}
|
|
|
|
// Load logger subsystem
|
|
loadLoggers()
|
|
|
|
// This is only to uniquely identify each gateway deployments.
|
|
globalDeploymentID = os.Getenv("MINIO_GATEWAY_DEPLOYMENT_ID")
|
|
|
|
var cacheConfig = globalServerConfig.GetCacheConfig()
|
|
if len(cacheConfig.Drives) > 0 {
|
|
var err error
|
|
// initialize the new disk cache objects.
|
|
globalCacheObjectAPI, err = newServerCacheObjects(cacheConfig)
|
|
logger.FatalIf(err, "Unable to initialize disk caching")
|
|
}
|
|
|
|
// Re-enable logging
|
|
logger.Disable = false
|
|
|
|
// Create new IAM system.
|
|
globalIAMSys = NewIAMSys()
|
|
if globalEtcdClient != nil {
|
|
// Initialize IAM sys.
|
|
_ = globalIAMSys.Init(newObject)
|
|
}
|
|
|
|
// Create new policy system.
|
|
globalPolicySys = NewPolicySys()
|
|
|
|
// Initialize policy system.
|
|
go globalPolicySys.Init(newObject)
|
|
|
|
// Create new notification system.
|
|
globalNotificationSys = NewNotificationSys(globalServerConfig, globalEndpoints)
|
|
if globalEtcdClient != nil && newObject.IsNotificationSupported() {
|
|
_ = globalNotificationSys.Init(newObject)
|
|
}
|
|
|
|
// Encryption support checks in gateway mode.
|
|
{
|
|
|
|
if (globalAutoEncryption || GlobalKMS != nil) && !newObject.IsEncryptionSupported() {
|
|
logger.Fatal(errInvalidArgument,
|
|
"Encryption support is requested but (%s) gateway does not support encryption", gw.Name())
|
|
}
|
|
|
|
if GlobalGatewaySSE.IsSet() && GlobalKMS == nil {
|
|
logger.Fatal(uiErrInvalidGWSSEEnvValue(nil).Msg("MINIO_GATEWAY_SSE set but KMS is not configured"),
|
|
"Unable to start gateway with SSE")
|
|
}
|
|
}
|
|
|
|
// Once endpoints are finalized, initialize the new object api.
|
|
globalObjLayerMutex.Lock()
|
|
globalObjectAPI = newObject
|
|
globalObjLayerMutex.Unlock()
|
|
|
|
// Prints the formatted startup message once object layer is initialized.
|
|
if !globalCLIContext.Quiet {
|
|
mode := globalMinioModeGatewayPrefix + gatewayName
|
|
// Check update mode.
|
|
checkUpdate(mode)
|
|
|
|
// Print a warning message if gateway is not ready for production before the startup banner.
|
|
if !gw.Production() {
|
|
logger.StartupMessage(colorYellow(" *** Warning: Not Ready for Production ***"))
|
|
}
|
|
|
|
// Print gateway startup message.
|
|
printGatewayStartupMessage(getAPIEndpoints(), gatewayName)
|
|
}
|
|
|
|
// Set uptime time after object layer has initialized.
|
|
globalBootTime = UTCNow()
|
|
|
|
handleSignals()
|
|
}
|