summaryrefslogtreecommitdiff
path: root/pkg/credentials
diff options
context:
space:
mode:
Diffstat (limited to 'pkg/credentials')
-rw-r--r--pkg/credentials/file_minio_client.go18
-rw-r--r--pkg/credentials/iam_aws.go54
-rw-r--r--pkg/credentials/iam_aws_test.go46
3 files changed, 103 insertions, 15 deletions
diff --git a/pkg/credentials/file_minio_client.go b/pkg/credentials/file_minio_client.go
index c282c2a..6a6827e 100644
--- a/pkg/credentials/file_minio_client.go
+++ b/pkg/credentials/file_minio_client.go
@@ -62,13 +62,17 @@ func NewFileMinioClient(filename string, alias string) *Credentials {
// users home directory.
func (p *FileMinioClient) Retrieve() (Value, error) {
if p.filename == "" {
- homeDir, err := homedir.Dir()
- if err != nil {
- return Value{}, err
- }
- p.filename = filepath.Join(homeDir, ".mc", "config.json")
- if runtime.GOOS == "windows" {
- p.filename = filepath.Join(homeDir, "mc", "config.json")
+ if value, ok := os.LookupEnv("MINIO_SHARED_CREDENTIALS_FILE"); ok {
+ p.filename = value
+ } else {
+ homeDir, err := homedir.Dir()
+ if err != nil {
+ return Value{}, err
+ }
+ p.filename = filepath.Join(homeDir, ".mc", "config.json")
+ if runtime.GOOS == "windows" {
+ p.filename = filepath.Join(homeDir, "mc", "config.json")
+ }
}
}
diff --git a/pkg/credentials/iam_aws.go b/pkg/credentials/iam_aws.go
index 637df74..6845c9a 100644
--- a/pkg/credentials/iam_aws.go
+++ b/pkg/credentials/iam_aws.go
@@ -21,8 +21,10 @@ import (
"bufio"
"encoding/json"
"errors"
+ "fmt"
"net/http"
"net/url"
+ "os"
"path"
"time"
)
@@ -50,16 +52,25 @@ type IAM struct {
// http://docs.aws.amazon.com/AWSEC2/latest/UserGuide/iam-roles-for-amazon-ec2.html
const (
defaultIAMRoleEndpoint = "http://169.254.169.254"
+ defaultECSRoleEndpoint = "http://169.254.170.2"
defaultIAMSecurityCredsPath = "/latest/meta-data/iam/security-credentials"
)
+// https://docs.aws.amazon.com/AmazonECS/latest/developerguide/task-iam-roles.html
+func getEndpoint(endpoint string) (string, bool) {
+ if endpoint != "" {
+ return endpoint, os.Getenv("AWS_CONTAINER_CREDENTIALS_RELATIVE_URI") != ""
+ }
+ if ecsURI := os.Getenv("AWS_CONTAINER_CREDENTIALS_RELATIVE_URI"); ecsURI != "" {
+ return fmt.Sprintf("%s%s", defaultECSRoleEndpoint, ecsURI), true
+ }
+ return defaultIAMRoleEndpoint, false
+}
+
// NewIAM returns a pointer to a new Credentials object wrapping
// the IAM. Takes a ConfigProvider to create a EC2Metadata client.
// The ConfigProvider is satisfied by the session.Session type.
func NewIAM(endpoint string) *Credentials {
- if endpoint == "" {
- endpoint = defaultIAMRoleEndpoint
- }
p := &IAM{
Client: &http.Client{
Transport: http.DefaultTransport,
@@ -73,11 +84,17 @@ func NewIAM(endpoint string) *Credentials {
// Error will be returned if the request fails, or unable to extract
// the desired
func (m *IAM) Retrieve() (Value, error) {
- roleCreds, err := getCredentials(m.Client, m.endpoint)
+ endpoint, isEcsTask := getEndpoint(m.endpoint)
+ var roleCreds ec2RoleCredRespBody
+ var err error
+ if isEcsTask {
+ roleCreds, err = getEcsTaskCredentials(m.Client, endpoint)
+ } else {
+ roleCreds, err = getCredentials(m.Client, endpoint)
+ }
if err != nil {
return Value{}, err
}
-
// Expiry window is set to 10secs.
m.SetExpiration(roleCreds.Expiration, DefaultExpiryWindow)
@@ -111,9 +128,6 @@ type ec2RoleCredRespBody struct {
// be sent to fetch the rolling access credentials.
// http://docs.aws.amazon.com/AWSEC2/latest/UserGuide/iam-roles-for-amazon-ec2.html
func getIAMRoleURL(endpoint string) (*url.URL, error) {
- if endpoint == "" {
- endpoint = defaultIAMRoleEndpoint
- }
u, err := url.Parse(endpoint)
if err != nil {
return nil, err
@@ -153,12 +167,36 @@ func listRoleNames(client *http.Client, u *url.URL) ([]string, error) {
return credsList, nil
}
+func getEcsTaskCredentials(client *http.Client, endpoint string) (ec2RoleCredRespBody, error) {
+ req, err := http.NewRequest("GET", endpoint, nil)
+ if err != nil {
+ return ec2RoleCredRespBody{}, err
+ }
+
+ resp, err := client.Do(req)
+ if err != nil {
+ return ec2RoleCredRespBody{}, err
+ }
+ defer resp.Body.Close()
+ if resp.StatusCode != http.StatusOK {
+ return ec2RoleCredRespBody{}, errors.New(resp.Status)
+ }
+
+ respCreds := ec2RoleCredRespBody{}
+ if err := json.NewDecoder(resp.Body).Decode(&respCreds); err != nil {
+ return ec2RoleCredRespBody{}, err
+ }
+
+ return respCreds, nil
+}
+
// getCredentials - obtains the credentials from the IAM role name associated with
// the current EC2 service.
//
// If the credentials cannot be found, or there is an error
// reading the response an error will be returned.
func getCredentials(client *http.Client, endpoint string) (ec2RoleCredRespBody, error) {
+
// http://docs.aws.amazon.com/AWSEC2/latest/UserGuide/iam-roles-for-amazon-ec2.html
u, err := getIAMRoleURL(endpoint)
if err != nil {
diff --git a/pkg/credentials/iam_aws_test.go b/pkg/credentials/iam_aws_test.go
index 86ea66b..4dbbb0a 100644
--- a/pkg/credentials/iam_aws_test.go
+++ b/pkg/credentials/iam_aws_test.go
@@ -21,6 +21,7 @@ import (
"fmt"
"net/http"
"net/http/httptest"
+ "os"
"testing"
"time"
)
@@ -41,6 +42,13 @@ const credsFailRespTmpl = `{
"LastUpdated": "2009-11-23T0:00:00Z"
}`
+const credsRespEcsTaskTmpl = `{
+ "AccessKeyId" : "accessKey",
+ "SecretAccessKey" : "secret",
+ "Token" : "token",
+ "Expiration" : "%s"
+}`
+
func initTestFailServer() *httptest.Server {
server := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
http.Error(w, "Not allowed", http.StatusBadRequest)
@@ -73,6 +81,14 @@ func initTestServer(expireOn string, failAssume bool) *httptest.Server {
return server
}
+func initEcsTaskTestServer(expireOn string) *httptest.Server {
+ server := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
+ fmt.Fprintf(w, credsRespEcsTaskTmpl, expireOn)
+ }))
+
+ return server
+}
+
func TestIAMMalformedEndpoint(t *testing.T) {
creds := NewIAM("%%%%")
_, err := creds.Get()
@@ -195,3 +211,33 @@ func TestIAMIsExpired(t *testing.T) {
t.Error("Expected creds to be expired when curren time has changed")
}
}
+
+func TestEcsTask(t *testing.T) {
+ server := initEcsTaskTestServer("2014-12-16T01:51:37Z")
+ defer server.Close()
+ p := &IAM{
+ Client: http.DefaultClient,
+ endpoint: server.URL,
+ }
+ os.Setenv("AWS_CONTAINER_CREDENTIALS_RELATIVE_URI", "/v2/credentials?id=task_credential_id")
+ creds, err := p.Retrieve()
+ os.Unsetenv("AWS_CONTAINER_CREDENTIALS_RELATIVE_URI")
+ if err != nil {
+ t.Errorf("Unexpected failure %s", err)
+ }
+ if "accessKey" != creds.AccessKeyID {
+ t.Errorf("Expected \"accessKey\", got %s", creds.AccessKeyID)
+ }
+
+ if "secret" != creds.SecretAccessKey {
+ t.Errorf("Expected \"secret\", got %s", creds.SecretAccessKey)
+ }
+
+ if "token" != creds.SessionToken {
+ t.Errorf("Expected \"token\", got %s", creds.SessionToken)
+ }
+
+ if !p.IsExpired() {
+ t.Error("Expected creds to be expired.")
+ }
+}