diff --git a/cmd/gateway/manta/gateway-manta.go b/cmd/gateway/manta/gateway-manta.go index 557e39ba5..845e74489 100644 --- a/cmd/gateway/manta/gateway-manta.go +++ b/cmd/gateway/manta/gateway-manta.go @@ -32,7 +32,6 @@ import ( "github.com/joyent/triton-go/authentication" tclient "github.com/joyent/triton-go/client" "github.com/joyent/triton-go/storage" - "github.com/minio/cli" minio "github.com/minio/minio/cmd" "github.com/minio/minio/pkg/auth" @@ -68,6 +67,7 @@ ENVIRONMENT VARIABLES: MINIO_ACCESS_KEY: The Manta account name. MINIO_SECRET_KEY: A KeyID associated with the Manta account. MANTA_KEY_MATERIAL: The path to the SSH Key associated with the Manta account if the MINIO_SECRET_KEY is not in SSH Agent. + MANTA_SUBUSER: The username of a user who has limited access to your account. BROWSER: MINIO_BROWSER: To disable web browser access, set this value to "off". @@ -140,7 +140,14 @@ func (g *Manta) NewGatewayLayer(creds auth.Credentials) (minio.GatewayLayer, err keyMaterial := os.Getenv("MANTA_KEY_MATERIAL") if keyMaterial == "" { - signer, err = authentication.NewSSHAgentSigner(creds.SecretKey, creds.AccessKey) + input := authentication.SSHAgentSignerInput{ + KeyID: creds.SecretKey, + AccountName: creds.AccessKey, + } + if userName, ok := os.LookupEnv("MANTA_SUBUSER"); ok { + input.Username = userName + } + signer, err = authentication.NewSSHAgentSigner(input) if err != nil { return nil, errors.Trace(err) } @@ -168,7 +175,16 @@ func (g *Manta) NewGatewayLayer(creds auth.Credentials) (minio.GatewayLayer, err keyBytes = []byte(keyMaterial) } - signer, err = authentication.NewPrivateKeySigner(creds.SecretKey, keyBytes, creds.AccessKey) + input := authentication.PrivateKeySignerInput{ + KeyID: creds.SecretKey, + PrivateKeyMaterial: keyBytes, + AccountName: creds.AccessKey, + } + if userName, ok := os.LookupEnv("MANTA_SUBUSER"); ok { + input.Username = userName + } + + signer, err = authentication.NewPrivateKeySigner(input) if err != nil { return nil, errors.Trace(err) } diff --git a/docs/gateway/manta.md b/docs/gateway/manta.md index 1c4ad3238..70d745613 100644 --- a/docs/gateway/manta.md +++ b/docs/gateway/manta.md @@ -7,7 +7,8 @@ Minio Gateway adds Amazon S3 compatibility to Manta Object Storage. docker run -p 9000:9000 --name manta-s3 \ -e "MINIO_ACCESS_KEY=joyentaccountname" \ -e "MINIO_SECRET_KEY=joyentkeyid" \ - -e "MINIO_KEY_MATERIAL=~/.ssh/id_rsa + -e "MANTA_KEY_MATERIAL=~/.ssh/id_rsa" \ + -e "MANTA_SUBUSER=devuser" minio/minio gateway manta ``` @@ -15,7 +16,8 @@ docker run -p 9000:9000 --name manta-s3 \ ``` export MINIO_ACCESS_KEY=joyentaccountname export MINIO_SECRET_KEY=joyentkeyid -export MINIO_KEY_MATERIAL=~/.ssh/id_rsa +export MANTA_KEY_MATERIAL=~/.ssh/id_rsa +export MANTA_SUBUSER=devuser minio gateway manta ``` ## Test using Minio Browser diff --git a/vendor/github.com/joyent/triton-go/CHANGELOG.md b/vendor/github.com/joyent/triton-go/CHANGELOG.md index 7c0ad911a..c0d740998 100644 --- a/vendor/github.com/joyent/triton-go/CHANGELOG.md +++ b/vendor/github.com/joyent/triton-go/CHANGELOG.md @@ -1,5 +1,23 @@ ## Unreleased +## 0.5.2 (December 28) + +- Standardise the API SSH Signers input casing and naming + +## 0.5.1 (December 28) + +- Include leading '/' when working with SSH Agent signers + +## 0.5.0 (December 28) + +- Add support for RBAC in triton-go [#82] +This is a breaking change. No longer do we pass individual parameters to the SSH Signer funcs, but we now pass an input Struct. This will guard from from additional parameter changes in the future. +We also now add support for using `SDC_*` and `TRITON_*` env vars when working with the Default agent signer + +## 0.4.2 (December 22) + +- Fixing a panic when the user loses network connectivity when making a GET request to instance [#81] + ## 0.4.1 (December 15) - Clean up the handling of directory sanitization. Use abs paths everywhere [#79] diff --git a/vendor/github.com/joyent/triton-go/README.md b/vendor/github.com/joyent/triton-go/README.md index 399675709..5dbd5de0f 100644 --- a/vendor/github.com/joyent/triton-go/README.md +++ b/vendor/github.com/joyent/triton-go/README.md @@ -15,11 +15,17 @@ using a key stored with the local SSH Agent (using an [`SSHAgentSigner`][6]. To construct a Signer, use the `New*` range of methods in the `authentication` package. In the case of `authentication.NewSSHAgentSigner`, the parameters are the fingerprint of the key with which to sign, and the account name (normally -stored in the `SDC_ACCOUNT` environment variable). For example: +stored in the `TRITON_ACCOUNT` environment variable). There is also support for +passing in a username, this will allow you to use an account other than the main +Triton account. For example: -``` -const fingerprint := "a4:c6:f3:75:80:27:e0:03:a9:98:79:ef:c5:0a:06:11" -sshKeySigner, err := authentication.NewSSHAgentSigner(fingerprint, "AccountName") +```go +input := authentication.SSHAgentSignerInput{ + KeyID: "a4:c6:f3:75:80:27:e0:03:a9:98:79:ef:c5:0a:06:11", + AccountName: "AccountName", + Username: "Username", +} +sshKeySigner, err := authentication.NewSSHAgentSigner(input) if err != nil { log.Fatalf("NewSSHAgentSigner: %s", err) } @@ -36,17 +42,18 @@ their own seperate client. In order to initialize a package client, simply pass the global `triton.ClientConfig` struct into the client's constructor function. ```go - config := &triton.ClientConfig{ - TritonURL: os.Getenv("SDC_URL"), - MantaURL: os.Getenv("MANTA_URL"), - AccountName: accountName, - Signers: []authentication.Signer{sshKeySigner}, - } +config := &triton.ClientConfig{ + TritonURL: os.Getenv("TRITON_URL"), + MantaURL: os.Getenv("MANTA_URL"), + AccountName: accountName, + Username: os.Getenv("TRITON_USER"), + Signers: []authentication.Signer{sshKeySigner}, +} - c, err := compute.NewClient(config) - if err != nil { - log.Fatalf("compute.NewClient: %s", err) - } +c, err := compute.NewClient(config) +if err != nil { + log.Fatalf("compute.NewClient: %s", err) +} ``` Constructing `compute.Client` returns an interface which exposes `compute` API @@ -57,10 +64,10 @@ The same `triton.ClientConfig` will initialize the Manta `storage` client as well... ```go - c, err := storage.NewClient(config) - if err != nil { - log.Fatalf("storage.NewClient: %s", err) - } +c, err := storage.NewClient(config) +if err != nil { + log.Fatalf("storage.NewClient: %s", err) +} ``` ## Error Handling @@ -81,13 +88,14 @@ set: - `TRITON_TEST` - must be set to any value in order to indicate desire to create resources -- `SDC_URL` - the base endpoint for the Triton API -- `SDC_ACCOUNT` - the account name for the Triton API -- `SDC_KEY_ID` - the fingerprint of the SSH key identifying the key +- `TRITON_URL` - the base endpoint for the Triton API +- `TRITON_ACCOUNT` - the account name for the Triton API +- `TRITON_KEY_ID` - the fingerprint of the SSH key identifying the key -Additionally, you may set `SDC_KEY_MATERIAL` to the contents of an unencrypted +Additionally, you may set `TRITON_KEY_MATERIAL` to the contents of an unencrypted private key. If this is set, the PrivateKeySigner (see above) will be used - if -not the SSHAgentSigner will be used. +not the SSHAgentSigner will be used. You can also set `TRITON_USER` to run the tests +against an account other than the main Triton account ### Example Run @@ -96,9 +104,9 @@ The verbose output has been removed for brevity here. ``` $ HTTP_PROXY=http://localhost:8888 \ TRITON_TEST=1 \ - SDC_URL=https://us-sw-1.api.joyent.com \ - SDC_ACCOUNT=AccountName \ - SDC_KEY_ID=a4:c6:f3:75:80:27:e0:03:a9:98:79:ef:c5:0a:06:11 \ + TRITON_URL=https://us-sw-1.api.joyent.com \ + TRITON_ACCOUNT=AccountName \ + TRITON_KEY_ID=a4:c6:f3:75:80:27:e0:03:a9:98:79:ef:c5:0a:06:11 \ go test -v -run "TestAccKey" === RUN TestAccKey_Create --- PASS: TestAccKey_Create (12.46s) @@ -118,7 +126,7 @@ referencing your SSH key file use by your active `triton` CLI profile. ```sh $ eval "$(triton env us-sw-1)" -$ SDC_KEY_FILE=~/.ssh/triton-id_rsa go run examples/compute/instances.go +$ TRITON_KEY_FILE=~/.ssh/triton-id_rsa go run examples/compute/instances.go ``` The following is a complete example of how to initialize the `compute` package @@ -144,15 +152,21 @@ import ( ) func main() { - keyID := os.Getenv("SDC_KEY_ID") - accountName := os.Getenv("SDC_ACCOUNT") - keyMaterial := os.Getenv("SDC_KEY_MATERIAL") + keyID := os.Getenv("TRITON_KEY_ID") + accountName := os.Getenv("TRITON_ACCOUNT") + keyMaterial := os.Getenv("TRITON_KEY_MATERIAL") + userName := os.Getenv("TRITON_USER") var signer authentication.Signer var err error if keyMaterial == "" { - signer, err = authentication.NewSSHAgentSigner(keyID, accountName) + input := authentication.SSHAgentSignerInput{ + KeyID: keyID, + AccountName: accountName, + Username: userName, + } + signer, err = authentication.NewSSHAgentSigner(input) if err != nil { log.Fatalf("Error Creating SSH Agent Signer: {{err}}", err) } @@ -180,15 +194,22 @@ func main() { keyBytes = []byte(keyMaterial) } - signer, err = authentication.NewPrivateKeySigner(keyID, []byte(keyMaterial), accountName) + input := authentication.PrivateKeySignerInput{ + KeyID: keyID, + PrivateKeyMaterial: keyBytes, + AccountName: accountName, + Username: userName, + } + signer, err = authentication.NewPrivateKeySigner(input) if err != nil { log.Fatalf("Error Creating SSH Private Key Signer: {{err}}", err) } } config := &triton.ClientConfig{ - TritonURL: os.Getenv("SDC_URL"), + TritonURL: os.Getenv("TRITON_URL"), AccountName: accountName, + Username: userName, Signers: []authentication.Signer{signer}, } diff --git a/vendor/github.com/joyent/triton-go/authentication/private_key_signer.go b/vendor/github.com/joyent/triton-go/authentication/private_key_signer.go index 43bc286f0..35abff0f6 100644 --- a/vendor/github.com/joyent/triton-go/authentication/private_key_signer.go +++ b/vendor/github.com/joyent/triton-go/authentication/private_key_signer.go @@ -9,6 +9,7 @@ import ( "encoding/pem" "errors" "fmt" + "path" "strings" "github.com/hashicorp/errwrap" @@ -20,15 +21,23 @@ type PrivateKeySigner struct { keyFingerprint string algorithm string accountName string + userName string hashFunc crypto.Hash privateKey *rsa.PrivateKey } -func NewPrivateKeySigner(keyFingerprint string, privateKeyMaterial []byte, accountName string) (*PrivateKeySigner, error) { - keyFingerprintMD5 := strings.Replace(keyFingerprint, ":", "", -1) +type PrivateKeySignerInput struct { + KeyID string + PrivateKeyMaterial []byte + AccountName string + Username string +} - block, _ := pem.Decode(privateKeyMaterial) +func NewPrivateKeySigner(input PrivateKeySignerInput) (*PrivateKeySigner, error) { + keyFingerprintMD5 := strings.Replace(input.KeyID, ":", "", -1) + + block, _ := pem.Decode(input.PrivateKeyMaterial) if block == nil { return nil, errors.New("Error PEM-decoding private key material: nil block received") } @@ -51,13 +60,17 @@ func NewPrivateKeySigner(keyFingerprint string, privateKeyMaterial []byte, accou signer := &PrivateKeySigner{ formattedKeyFingerprint: displayKeyFingerprint, - keyFingerprint: keyFingerprint, - accountName: accountName, + keyFingerprint: input.KeyID, + accountName: input.AccountName, hashFunc: crypto.SHA1, privateKey: rsakey, } + if input.Username != "" { + signer.userName = input.Username + } + _, algorithm, err := signer.SignRaw("HelloWorld") if err != nil { return nil, fmt.Errorf("Cannot sign using ssh agent: %s", err) @@ -80,7 +93,13 @@ func (s *PrivateKeySigner) Sign(dateHeader string) (string, error) { } signedBase64 := base64.StdEncoding.EncodeToString(signed) - keyID := fmt.Sprintf("/%s/keys/%s", s.accountName, s.formattedKeyFingerprint) + var keyID string + if s.userName != "" { + + keyID = path.Join("/", s.accountName, "users", s.userName, "keys", s.formattedKeyFingerprint) + } else { + keyID = path.Join("/", s.accountName, "keys", s.formattedKeyFingerprint) + } return fmt.Sprintf(authorizationHeaderFormat, keyID, "rsa-sha1", headerName, signedBase64), nil } diff --git a/vendor/github.com/joyent/triton-go/authentication/ssh_agent_signer.go b/vendor/github.com/joyent/triton-go/authentication/ssh_agent_signer.go index 3da4a68e9..c068dae27 100644 --- a/vendor/github.com/joyent/triton-go/authentication/ssh_agent_signer.go +++ b/vendor/github.com/joyent/triton-go/authentication/ssh_agent_signer.go @@ -8,6 +8,7 @@ import ( "fmt" "net" "os" + "path" "strings" "github.com/hashicorp/errwrap" @@ -24,13 +25,20 @@ type SSHAgentSigner struct { keyFingerprint string algorithm string accountName string + userName string keyIdentifier string agent agent.Agent key ssh.PublicKey } -func NewSSHAgentSigner(keyFingerprint, accountName string) (*SSHAgentSigner, error) { +type SSHAgentSignerInput struct { + KeyID string + AccountName string + Username string +} + +func NewSSHAgentSigner(input SSHAgentSignerInput) (*SSHAgentSigner, error) { sshAgentAddress, agentOk := os.LookupEnv("SSH_AUTH_SOCK") if !agentOk { return nil, ErrUnsetEnvVar @@ -44,8 +52,8 @@ func NewSSHAgentSigner(keyFingerprint, accountName string) (*SSHAgentSigner, err ag := agent.NewClient(conn) signer := &SSHAgentSigner{ - keyFingerprint: keyFingerprint, - accountName: accountName, + keyFingerprint: input.KeyID, + accountName: input.AccountName, agent: ag, } @@ -55,7 +63,12 @@ func NewSSHAgentSigner(keyFingerprint, accountName string) (*SSHAgentSigner, err } signer.key = matchingKey signer.formattedKeyFingerprint = formatPublicKeyFingerprint(signer.key, true) - signer.keyIdentifier = fmt.Sprintf("/%s/keys/%s", signer.accountName, signer.formattedKeyFingerprint) + if input.Username != "" { + signer.userName = input.Username + signer.keyIdentifier = path.Join("/", signer.accountName, "users", input.Username, "keys", signer.formattedKeyFingerprint) + } else { + signer.keyIdentifier = path.Join("/", signer.accountName, "keys", signer.formattedKeyFingerprint) + } _, algorithm, err := signer.SignRaw("HelloWorld") if err != nil { diff --git a/vendor/github.com/joyent/triton-go/client/client.go b/vendor/github.com/joyent/triton-go/client/client.go index 2852542ed..cccf3a25d 100644 --- a/vendor/github.com/joyent/triton-go/client/client.go +++ b/vendor/github.com/joyent/triton-go/client/client.go @@ -21,7 +21,7 @@ import ( const nilContext = "nil context" var ( - ErrDefaultAuth = errors.New("default SSH agent authentication requires SDC_KEY_ID and SSH_AUTH_SOCK") + ErrDefaultAuth = errors.New("default SSH agent authentication requires SDC_KEY_ID / TRITON_KEY_ID and SSH_AUTH_SOCK") ErrAccountName = errors.New("missing account name for Triton/Manta") ErrMissingURL = errors.New("missing Triton and/or Manta URL") @@ -36,6 +36,7 @@ type Client struct { TritonURL url.URL MantaURL url.URL AccountName string + Username string } // New is used to construct a Client in order to make API @@ -81,7 +82,7 @@ func New(tritonURL string, mantaURL string, accountName string, signers ...authe } // Default to constructing an SSHAgentSigner if there are no other signers - // passed into NewClient and there's an SDC_KEY_ID and SSH_AUTH_SOCK + // passed into NewClient and there's an TRITON_KEY_ID and SSH_AUTH_SOCK // available in the user's environ(7). if len(newClient.Authorizers) == 0 { if err := newClient.DefaultAuth(); err != nil { @@ -92,21 +93,43 @@ func New(tritonURL string, mantaURL string, accountName string, signers ...authe return newClient, nil } +var envPrefixes = []string{"TRITON", "SDC"} + +// GetTritonEnv looks up environment variables using the preferred "TRITON" +// prefix, but falls back to the SDC prefix. For example, looking up "USER" +// will search for "TRITON_USER" followed by "SDC_USER". If the environment +// variable is not set, an empty string is returned. GetTritonEnv() is used to +// aid in the transition and deprecation of the SDC_* environment variables. +func GetTritonEnv(name string) string { + for _, prefix := range envPrefixes { + if val, found := os.LookupEnv(prefix + "_" + name); found { + return val + } + } + + return "" +} + // initDefaultAuth provides a default key signer for a client. This should only // be used internally if the client has no other key signer for authenticating // with Triton. We first look for both `SDC_KEY_ID` and `SSH_AUTH_SOCK` in the // user's environ(7). If so we default to the SSH agent key signer. func (c *Client) DefaultAuth() error { - if keyID, keyOk := os.LookupEnv("SDC_KEY_ID"); keyOk { - defaultSigner, err := authentication.NewSSHAgentSigner(keyID, c.AccountName) + tritonKeyId := GetTritonEnv("KEY_ID") + if tritonKeyId != "" { + input := authentication.SSHAgentSignerInput{ + KeyID: tritonKeyId, + AccountName: c.AccountName, + Username: c.Username, + } + defaultSigner, err := authentication.NewSSHAgentSigner(input) if err != nil { return errwrap.Wrapf("problem initializing NewSSHAgentSigner: {{err}}", err) } c.Authorizers = append(c.Authorizers, defaultSigner) - } else { - return ErrDefaultAuth } - return nil + + return ErrDefaultAuth } // InsecureSkipTLSVerify turns off TLS verification for the client connection. This diff --git a/vendor/github.com/joyent/triton-go/storage/objects.go b/vendor/github.com/joyent/triton-go/storage/objects.go index e9435e50d..2c40b2775 100644 --- a/vendor/github.com/joyent/triton-go/storage/objects.go +++ b/vendor/github.com/joyent/triton-go/storage/objects.go @@ -260,7 +260,6 @@ func (s *ObjectsClient) Put(ctx context.Context, input *PutObjectInput) error { absPath := absFileInput(s.client.AccountName, input.ObjectPath) if input.ForceInsert { - // IsDir() uses a path relative to the account absDirName := _AbsCleanPath(path.Dir(string(absPath))) exists, err := checkDirectoryTreeExists(*s, ctx, absDirName) if err != nil { diff --git a/vendor/github.com/joyent/triton-go/triton.go b/vendor/github.com/joyent/triton-go/triton.go index b5bacd255..f9202984e 100644 --- a/vendor/github.com/joyent/triton-go/triton.go +++ b/vendor/github.com/joyent/triton-go/triton.go @@ -14,5 +14,6 @@ type ClientConfig struct { TritonURL string MantaURL string AccountName string + Username string Signers []authentication.Signer } diff --git a/vendor/vendor.json b/vendor/vendor.json index efba54f13..e131df5a9 100644 --- a/vendor/vendor.json +++ b/vendor/vendor.json @@ -292,28 +292,28 @@ "revisionTime": "2016-01-12T19:33:35Z" }, { - "checksumSHA1": "NYs0qvjZwsMZAXMtg2HRiED2cb4=", + "checksumSHA1": "oINoQSRkPinChzwEHr3VatB9++Y=", "path": "github.com/joyent/triton-go", - "revision": "8365851ee7afcbb4cc1c7ba2e414b242ce0574f1", - "revisionTime": "2017-12-15T19:09:06Z" + "revision": "86ba9699869b6cd5ea3290faad7be659efc7d6ce", + "revisionTime": "2017-12-28T20:20:46Z" }, { - "checksumSHA1": "Cth7NCLH/HaeKh9ZMRpQtudTEQQ=", + "checksumSHA1": "d6pxw8DLxYehLr92fWZTLEWVws8=", "path": "github.com/joyent/triton-go/authentication", - "revision": "8365851ee7afcbb4cc1c7ba2e414b242ce0574f1", - "revisionTime": "2017-12-15T19:09:06Z" + "revision": "86ba9699869b6cd5ea3290faad7be659efc7d6ce", + "revisionTime": "2017-12-28T20:20:46Z" }, { - "checksumSHA1": "3ju04DVaxotpCKBF3Q/0vCSOlec=", + "checksumSHA1": "GCHfn8d1Mhswm7n7IRnT0n/w+dw=", "path": "github.com/joyent/triton-go/client", - "revision": "8365851ee7afcbb4cc1c7ba2e414b242ce0574f1", - "revisionTime": "2017-12-15T19:09:06Z" + "revision": "86ba9699869b6cd5ea3290faad7be659efc7d6ce", + "revisionTime": "2017-12-28T20:20:46Z" }, { - "checksumSHA1": "/WtyDZMgstGbBYtQ0f+ZfKMS4v8=", + "checksumSHA1": "PJe3Rs8H466xR8o5audO8oWk44Q=", "path": "github.com/joyent/triton-go/storage", - "revision": "8365851ee7afcbb4cc1c7ba2e414b242ce0574f1", - "revisionTime": "2017-12-15T19:09:06Z" + "revision": "86ba9699869b6cd5ea3290faad7be659efc7d6ce", + "revisionTime": "2017-12-28T20:20:46Z" }, { "path": "github.com/klauspost/cpuid",