Skip to content

Commit

Permalink
Added IAM credentials.
Browse files Browse the repository at this point in the history
Closes aws#6. Closes aws#13.
  • Loading branch information
stripecodahale committed Dec 16, 2014
1 parent 754f5e9 commit a20ba02
Show file tree
Hide file tree
Showing 2 changed files with 116 additions and 0 deletions.
51 changes: 51 additions & 0 deletions aws/auth.go
Original file line number Diff line number Diff line change
@@ -1,7 +1,11 @@
package aws

import (
"encoding/json"
"net/http"
"os"
"sync"
"time"

"github.com/juju/errors"
)
Expand Down Expand Up @@ -65,6 +69,53 @@ func Creds(accessKeyID, secretAccessKey, securityToken string) CredentialsProvid
}
}

// IAMCreds returns a provider which pulls credentials from the local EC2
// instance's IAM roles.
func IAMCreds() CredentialsProvider {
return &iamProvider{}
}

type iamProvider struct {
creds Credentials
m sync.Mutex
expiration time.Time
}

var metadataCredentialsEndpoint = "http://169.254.169.254/latest/meta-data/iam/security-credentials/"

func (p *iamProvider) Credentials() (*Credentials, error) {
p.m.Lock()
defer p.m.Unlock()

if p.expiration.Before(currentTime()) {
var body struct {
Expiration time.Time
AccessKeyID string
SecretAccessKey string
Token string
}

resp, err := http.Get(metadataCredentialsEndpoint)
if err != nil {
return nil, err
}
defer resp.Body.Close()

if err := json.NewDecoder(resp.Body).Decode(&body); err != nil {
return nil, err
}

p.creds = Credentials{
AccessKeyID: body.AccessKeyID,
SecretAccessKey: body.SecretAccessKey,
SecurityToken: body.Token,
}
p.expiration = body.Expiration
}

return &p.creds, nil
}

type staticCredentialsProvider struct {
creds Credentials
}
Expand Down
65 changes: 65 additions & 0 deletions aws/auth_test.go
Original file line number Diff line number Diff line change
@@ -1,8 +1,12 @@
package aws

import (
"fmt"
"net/http"
"net/http/httptest"
"os"
"testing"
"time"
)

func TestEnvCreds(t *testing.T) {
Expand Down Expand Up @@ -77,3 +81,64 @@ func TestEnvCredsAlternateNames(t *testing.T) {
t.Errorf("Secret access key was %v, expected %v", v, want)
}
}

func TestIAMCreds(t *testing.T) {
server := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
fmt.Fprintln(w, `{
"AccessKeyId" : "accessKey",
"SecretAccessKey" : "secret",
"Token" : "token",
"Expiration" : "2014-12-16T01:51:37Z"
}`)
}))
defer server.Close()

defer func(s string) {
metadataCredentialsEndpoint = s
}(metadataCredentialsEndpoint)
metadataCredentialsEndpoint = server.URL

defer func() {
currentTime = time.Now
}()
currentTime = func() time.Time {
return time.Date(2014, 12, 15, 21, 26, 0, 0, time.UTC)
}

prov := IAMCreds()
t.Log(prov.Credentials())
}

func BenchmarkIAMCreds(b *testing.B) {
server := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
fmt.Fprintln(w, `{
"AccessKeyId" : "accessKey",
"SecretAccessKey" : "secret",
"Token" : "token",
"Expiration" : "2014-12-16T01:51:37Z"
}`)
}))
defer server.Close()

defer func(s string) {
metadataCredentialsEndpoint = s
}(metadataCredentialsEndpoint)
metadataCredentialsEndpoint = server.URL

defer func() {
currentTime = time.Now
}()
currentTime = func() time.Time {
return time.Date(2014, 12, 15, 21, 26, 0, 0, time.UTC)
}

b.ResetTimer()

prov := IAMCreds()

b.RunParallel(func(pb *testing.PB) {
for pb.Next() {
prov.Credentials()
}
})
}

0 comments on commit a20ba02

Please sign in to comment.