Skip to content

Commit

Permalink
Fix AWS Signature V4 using IAM role
Browse files Browse the repository at this point in the history
  • Loading branch information
lorepas authored and ostafen committed Aug 7, 2024
1 parent 8b5f651 commit 8f57d65
Show file tree
Hide file tree
Showing 2 changed files with 29 additions and 22 deletions.
2 changes: 1 addition & 1 deletion embedded/appendable/remoteapp/remote_app.go
Original file line number Diff line number Diff line change
Expand Up @@ -87,7 +87,7 @@ func Open(path string, remotePath string, storage remotestorage.Storage, opts *O
return nil, ErrIllegalArguments
}

log.Printf("Opening remote storage at %s%s", storage, remotePath)
log.Printf("Opening remote storage at %s", remotePath)

mainContext, mainCancelFunc := context.WithCancel(context.Background())

Expand Down
49 changes: 28 additions & 21 deletions embedded/remotestorage/s3/s3.go
Original file line number Diff line number Diff line change
Expand Up @@ -52,7 +52,8 @@ type Storage struct {
prefix string
location string
httpClient *http.Client

sessionToken string

awsInstanceMetadataURL string
awsCredsRefreshPeriod time.Duration
}
Expand Down Expand Up @@ -232,6 +233,11 @@ func (s *Storage) s3SignedRequestV4(

req.Header.Set("X-Amz-Date", timeISO8601)
req.Header.Set("X-Amz-Content-Sha256", contentSha256)

if s.S3RoleEnabled {
req.Header.Set("X-Amz-Security-Token", s.sessionToken)
}

if contentType != "" {
req.Header.Set("Content-Type", contentType)
}
Expand Down Expand Up @@ -777,7 +783,7 @@ func (s *Storage) getRoleCredentials() error {
}

var err error
s.accessKeyID, s.secretKey, err = s.requestCredentials()
s.accessKeyID, s.secretKey, s.sessionToken, err = s.requestCredentials()
if err != nil {
return err
}
Expand All @@ -787,39 +793,39 @@ func (s *Storage) getRoleCredentials() error {
for {
select {
case _ = <-s3CredentialsRefreshTicker.C:
accessKeyID, secretKey, err := s.requestCredentials()
accessKeyID, secretKey, sessionToken, err := s.requestCredentials()
if err != nil {
log.Printf("S3 role credentials lookup failed with an error: %v", err)
continue
}
s.accessKeyID, s.secretKey = accessKeyID, secretKey
s.accessKeyID, s.secretKey, s.sessionToken = accessKeyID, secretKey, sessionToken
}
}
}()

return nil
}

func (s *Storage) requestCredentials() (string, string, error) {
func (s *Storage) requestCredentials() (string, string, string, error) {
tokenReq, err := http.NewRequest("PUT", fmt.Sprintf("%s%s",
s.awsInstanceMetadataURL,
"/latest/api/token",
), nil)
if err != nil {
return "", "", errors.New("cannot form metadata token request")
return "", "", "", errors.New("cannot form metadata token request")
}

tokenReq.Header.Set("X-aws-ec2-metadata-token-ttl-seconds", "21600")

tokenResp, err := http.DefaultClient.Do(tokenReq)
if err != nil {
return "", "", errors.New("cannot get metadata token")
return "", "", "", errors.New("cannot get metadata token")
}
defer tokenResp.Body.Close()

token, err := ioutil.ReadAll(tokenResp.Body)
if err != nil {
return "", "", errors.New("cannot read metadata token")
return "", "", "", errors.New("cannot read metadata token")
}

role := s.s3Role
Expand All @@ -829,31 +835,31 @@ func (s *Storage) requestCredentials() (string, string, error) {
"/latest/meta-data/iam/info",
), nil)
if err != nil {
return "", "", errors.New("cannot form role name request")
return "", "", "", errors.New("cannot form role name request")
}

roleReq.Header.Set("X-aws-ec2-metadata-token", string(token))
roleResp, err := http.DefaultClient.Do(roleReq)
if err != nil {
return "", "", errors.New("cannot get role name")
return "", "", "", errors.New("cannot get role name")
}
defer roleResp.Body.Close()

creds, err := ioutil.ReadAll(roleResp.Body)
if err != nil {
return "", "", errors.New("cannot read role name")
return "", "", "", errors.New("cannot read role name")
}

var metadata struct {
InstanceProfileArn string `json:"InstanceProfileArn"`
}
if err := json.Unmarshal(creds, &metadata); err != nil {
return "", "", errors.New("cannot parse role name")
return "", "", "", errors.New("cannot parse role name")
}

match := arnRoleRegex.FindStringSubmatch(metadata.InstanceProfileArn)
if len(match) < 2 {
return "", "", ErrCredentialsCannotBeFound
return "", "", "", ErrCredentialsCannotBeFound
}

role = match[1]
Expand All @@ -865,30 +871,31 @@ func (s *Storage) requestCredentials() (string, string, error) {
role,
), nil)
if err != nil {
return "", "", errors.New("cannot form role credentials request")
return "", "", "", errors.New("cannot form role credentials request")
}

credsReq.Header.Set("X-aws-ec2-metadata-token", string(token))
credsResp, err := http.DefaultClient.Do(credsReq)
if err != nil {
return "", "", errors.New("cannot get role credentials")
return "", "", "", errors.New("cannot get role credentials")
}
defer credsResp.Body.Close()

creds, err := ioutil.ReadAll(credsReq.Body)
creds, err := ioutil.ReadAll(credsResp.Body)
if err != nil {
return "", "", errors.New("cannot read role credentials")
return "", "", "", errors.New("cannot read role credentials")
}

var credentials struct {
AccessKeyID string `json:"AccessKeyId"`
SecretAccessKey string `json:"SecretAccessKey"`
AccessKeyID string `json:"AccessKeyId"`
SecretAccessKey string `json:"SecretAccessKey"`
SessionToken string `json:"Token"`
}
if err := json.Unmarshal(creds, &credentials); err != nil {
return "", "", errors.New("cannot parse role credentials")
return "", "", "", errors.New("cannot parse role credentials")
}

return credentials.AccessKeyID, credentials.SecretAccessKey, nil
return credentials.AccessKeyID, credentials.SecretAccessKey, credentials.SessionToken, nil
}

var _ remotestorage.Storage = (*Storage)(nil)

0 comments on commit 8f57d65

Please sign in to comment.