Skip to content

Commit

Permalink
Add support for credential_process
Browse files Browse the repository at this point in the history
Fixes minio#1485

Signed-off-by: Alberto Murillo <[email protected]>
  • Loading branch information
Alberto Murillo committed May 4, 2021
1 parent bcf3477 commit bb99684
Show file tree
Hide file tree
Showing 4 changed files with 77 additions and 1 deletion.
7 changes: 7 additions & 0 deletions pkg/credentials/credentials.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
{
"Version": 1,
"SessionToken": "token",
"AccessKeyId": "accessKey",
"SecretAccessKey": "secret",
"Expiration": "9999-04-27T16:02:25.000Z"
}
3 changes: 3 additions & 0 deletions pkg/credentials/credentials.sample
Original file line number Diff line number Diff line change
Expand Up @@ -10,3 +10,6 @@ aws_secret_access_key = secret
[with_colon]
aws_access_key_id: accessKey
aws_secret_access_key: secret

[with_process]
credential_process = /bin/cat credentials.json
47 changes: 46 additions & 1 deletion pkg/credentials/file_aws_credentials.go
Original file line number Diff line number Diff line change
Expand Up @@ -18,18 +18,33 @@
package credentials

import (
"encoding/json"
"os"
"os/exec"
"path/filepath"
"strings"
"time"

homedir "github.com/mitchellh/go-homedir"
ini "gopkg.in/ini.v1"
)

// A externalProcessCredentials stores the output of a credential_process
type externalProcessCredentials struct {
Version int
SessionToken string
AccessKeyId string
SecretAccessKey string
Expiration time.Time
}

// A FileAWSCredentials retrieves credentials from the current user's home
// directory, and keeps track if those credentials are expired.
//
// Profile ini file example: $HOME/.aws/credentials
type FileAWSCredentials struct {
Expiry

// Path to the shared credentials file.
//
// If empty will look for "AWS_SHARED_CREDENTIALS_FILE" env variable. If the
Expand Down Expand Up @@ -90,6 +105,31 @@ func (p *FileAWSCredentials) Retrieve() (Value, error) {
// Default to empty string if not found.
token := iniProfile.Key("aws_session_token")

// If credential_process is defined, obtain credentials by executing
// the external process
credential_process := iniProfile.Key("credential_process").String()
if credential_process != "" {
args := strings.Fields(credential_process)
cmd := exec.Command(args[0], args[1:]...)
out, err := cmd.Output()
if err != nil {
return Value{}, err
}
var externalProcessCredentials externalProcessCredentials
err = json.Unmarshal([]byte(out), &externalProcessCredentials)
if err != nil {
return Value{}, err
}
p.retrieved = true
p.SetExpiration(externalProcessCredentials.Expiration, DefaultExpiryWindow)
return Value{
AccessKeyID: externalProcessCredentials.AccessKeyId,
SecretAccessKey: externalProcessCredentials.SecretAccessKey,
SessionToken: externalProcessCredentials.SessionToken,
SignerType: SignatureV4,
}, nil
}

p.retrieved = true
return Value{
AccessKeyID: id.String(),
Expand All @@ -101,7 +141,12 @@ func (p *FileAWSCredentials) Retrieve() (Value, error) {

// IsExpired returns if the shared credentials have expired.
func (p *FileAWSCredentials) IsExpired() bool {
return !p.retrieved
if p.expiration.IsZero() {
return !p.retrieved
}

now := time.Now()
return now.After(p.expiration)
}

// loadProfiles loads from the file pointed to by shared credentials filename for profile.
Expand Down
21 changes: 21 additions & 0 deletions pkg/credentials/file_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -120,6 +120,27 @@ func TestFileAWS(t *testing.T) {
if !creds.IsExpired() {
t.Error("Should be expired if not loaded")
}

os.Clearenv()

creds = NewFileAWSCredentials("credentials.sample", "with_process")
credValues, err = creds.Get()
if err != nil {
t.Fatal(err)
}

if credValues.AccessKeyID != "accessKey" {
t.Errorf("Expected 'accessKey', got %s'", credValues.AccessKeyID)
}
if credValues.SecretAccessKey != "secret" {
t.Errorf("Expected 'secret', got %s'", credValues.SecretAccessKey)
}
if credValues.SessionToken != "token" {
t.Errorf("Expected 'token', got %s'", credValues.SessionToken)
}
if creds.IsExpired() {
t.Error("Should not be expired")
}
}

func TestFileMinioClient(t *testing.T) {
Expand Down

0 comments on commit bb99684

Please sign in to comment.