1
0
mirror of https://github.com/minio/mc.git synced 2025-11-12 01:02:26 +03:00
Files
mc/cmd/config-host-add.go
Anis Elleuch d83e73b85b Pick a random bucket name when probing for signature version (#2491)
Probing buckets is a mechanism used to automatically detect supported
S3 signature version. However, it seems that probe-bucket-sign is already
used by someone, the thing that makes probing fails with 403 error. This
PR changes the code to pick a random bucket name when probing.
2018-07-24 20:19:26 -07:00

245 lines
7.2 KiB
Go

/*
* Minio Client (C) 2017 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 (
"github.com/fatih/color"
"github.com/minio/cli"
"github.com/minio/mc/pkg/console"
"github.com/minio/mc/pkg/probe"
)
var hostAddFlags = []cli.Flag{
cli.StringFlag{
Name: "lookup",
Value: "auto",
Usage: "bucket lookup supported by the server. Valid options are `[dns,path,auto]`",
},
cli.StringFlag{
Name: "api",
Usage: "API signature. Valid options are `[S3v4, S3v2]`",
},
}
var configHostAddCmd = cli.Command{
Name: "add",
ShortName: "a",
Usage: "Add a new host to configuration file.",
Action: mainConfigHostAdd,
Before: setGlobalsFromContext,
Flags: append(hostAddFlags, globalFlags...),
HideHelpCommand: true,
CustomHelpTemplate: `NAME:
{{.HelpName}} - {{.Usage}}
USAGE:
{{.HelpName}} ALIAS URL ACCESS-KEY SECRET-KEY
FLAGS:
{{range .VisibleFlags}}{{.}}
{{end}}
EXAMPLES:
1. Add Amazon S3 storage service under "mys3" alias. For security reasons turn off bash history momentarily.
$ set +o history
$ {{.HelpName}} mys3 https://s3.amazonaws.com \
BKIKJAA5BMMU2RHO6IBB V8f1CwQqAcwo80UEIJEjc5gVQUSSx5ohQ9GSrr12
$ set -o history
2. Add Amazon S3 accelerated storage service under "mys3-accel" alias. For security reasons turn off bash history momentarily.
$ set +o history
$ {{.HelpName}} mys3-accel https://s3-accelerate.amazonaws.com \
BKIKJAA5BMMU2RHO6IBB V8f1CwQqAcwo80UEIJEjc5gVQUSSx5ohQ9GSrr12
$ set -o history
3. Add Amazon S3 IAM temporary credentials with limited access, please make sure to override the signature probe by explicitly
providing the signature type.
$ set +o history
$ {{.HelpName}} mys3-iam https://s3.amazonaws.com \
BKIKJAA5BMMU2RHO6IBB V8f1CwQqAcwo80UEIJEjc5gVQUSSx5ohQ9GSrr12 --api "s3v4"
$ set -o history
4. Add S3 API compatible storage service under "myminio" alias, to use dns style bucket lookup. For security reasons turn off bash history momentarily.
$ set +o history
$ {{.HelpName}} myminio http://localhost:9000 \
minio minio123 --api "s3v4" --lookup "dns"
$ set -o history
`,
}
// checkConfigHostAddSyntax - verifies input arguments to 'config host add'.
func checkConfigHostAddSyntax(ctx *cli.Context) {
args := ctx.Args()
argsNr := len(args)
if argsNr < 4 || argsNr > 5 {
fatalIf(errInvalidArgument().Trace(ctx.Args().Tail()...),
"Incorrect number of arguments for host add command.")
}
alias := args.Get(0)
url := args.Get(1)
accessKey := args.Get(2)
secretKey := args.Get(3)
api := ctx.String("api")
bucketLookup := ctx.String("lookup")
if !isValidAlias(alias) {
fatalIf(errInvalidAlias(alias), "Invalid alias.")
}
if !isValidHostURL(url) {
fatalIf(errInvalidURL(url), "Invalid URL.")
}
if !isValidAccessKey(accessKey) {
fatalIf(errInvalidArgument().Trace(accessKey),
"Invalid access key `"+accessKey+"`.")
}
if !isValidSecretKey(secretKey) {
fatalIf(errInvalidArgument().Trace(secretKey),
"Invalid secret key `"+secretKey+"`.")
}
if api != "" && !isValidAPI(api) { // Empty value set to default "S3v4".
fatalIf(errInvalidArgument().Trace(api),
"Unrecognized API signature. Valid options are `[S3v4, S3v2]`.")
}
if !isValidLookup(bucketLookup) {
fatalIf(errInvalidArgument().Trace(bucketLookup),
"Unrecognized bucket lookup. Valid options are `[dns,auto, path]`.")
}
}
// addHost - add a host config.
func addHost(alias string, hostCfgV9 hostConfigV9) {
mcCfgV9, err := loadMcConfig()
fatalIf(err.Trace(globalMCConfigVersion), "Unable to load config `"+mustGetMcConfigPath()+"`.")
// Add new host.
mcCfgV9.Hosts[alias] = hostCfgV9
err = saveMcConfig(mcCfgV9)
fatalIf(err.Trace(alias), "Unable to update hosts in config version `"+mustGetMcConfigPath()+"`.")
printMsg(hostMessage{
op: "add",
Alias: alias,
URL: hostCfgV9.URL,
AccessKey: hostCfgV9.AccessKey,
SecretKey: hostCfgV9.SecretKey,
API: hostCfgV9.API,
Lookup: hostCfgV9.Lookup,
})
}
// probeS3Signature - auto probe S3 server signature: issue a Stat call
// using v4 signature then v2 in case of failure.
func probeS3Signature(accessKey, secretKey, url string) (string, *probe.Error) {
// Test s3 connection for API auto probe
s3Config := &Config{
// S3 connection parameters
Insecure: globalInsecure,
AccessKey: accessKey,
SecretKey: secretKey,
Signature: "s3v4",
HostURL: urlJoinPath(url, "probe-bucket-sign-"+newRandomID(32)),
}
s3Client, err := s3New(s3Config)
if err != nil {
return "", err
}
if _, err = s3Client.Stat(false, false, ""); err != nil {
switch err.ToGoError().(type) {
case BucketDoesNotExist:
// Bucket doesn't exist, means signature probing worked V4.
default:
// Attempt with signature v2, since v4 seem to have failed.
s3Config.Signature = "s3v2"
s3Client, err = s3New(s3Config)
if err != nil {
return "", err
}
if _, err = s3Client.Stat(false, false, ""); err != nil {
switch err.ToGoError().(type) {
case BucketDoesNotExist:
// Bucket doesn't exist, means signature probing worked with V2.
default:
return "", err
}
}
}
}
return s3Config.Signature, nil
}
// buildS3Config constructs an S3 Config and does
// signature auto-probe when needed.
func buildS3Config(url, accessKey, secretKey, api, lookup string) (*Config, *probe.Error) {
s3Config := newS3Config(url, &hostConfigV9{
AccessKey: accessKey,
SecretKey: secretKey,
URL: url,
Lookup: lookup,
})
// If api is provided we do not auto probe signature, this is
// required in situations when signature type is provided by the user.
if api != "" {
s3Config.Signature = api
return s3Config, nil
}
// Probe S3 signature version
api, err := probeS3Signature(accessKey, secretKey, url)
if err != nil {
return nil, err.Trace(url, accessKey, secretKey, api, lookup)
}
s3Config.Signature = api
// Success.
return s3Config, nil
}
func mainConfigHostAdd(ctx *cli.Context) error {
checkConfigHostAddSyntax(ctx)
console.SetColor("HostMessage", color.New(color.FgGreen))
var (
args = ctx.Args()
url = args.Get(1)
accessKey = args.Get(2)
secretKey = args.Get(3)
api = ctx.String("api")
lookup = ctx.String("lookup")
)
s3Config, err := buildS3Config(url, accessKey, secretKey, api, lookup)
fatalIf(err.Trace(ctx.Args()...), "Unable to initialize new config from the provided credentials.")
addHost(ctx.Args().Get(0), hostConfigV9{
URL: s3Config.HostURL,
AccessKey: s3Config.AccessKey,
SecretKey: s3Config.SecretKey,
API: s3Config.Signature,
Lookup: lookup,
}) // Add a host with specified credentials.
return nil
}