Skip to content

Commit

Permalink
Assume AWS role when provided in AWS config
Browse files Browse the repository at this point in the history
  • Loading branch information
tleguijt authored and mvantellingen committed Oct 19, 2020
1 parent 538e285 commit 010aa22
Show file tree
Hide file tree
Showing 4 changed files with 105 additions and 2 deletions.
2 changes: 2 additions & 0 deletions go.sum
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@ github.com/aws/aws-sdk-go v1.15.78/go.mod h1:E3/ieXAlvM0XWO57iftYVDLLvQ824smPP3A
github.com/aws/aws-sdk-go v1.25.3/go.mod h1:KmX6BPdI08NWTb3/sm4ZGu5ShLoqVDhKgpiN924inxo=
github.com/aws/aws-sdk-go v1.25.49 h1:j5R2Ey+g8qaiy2NJ9iH+KWzDWS4SjXRCjhc22EeQVE4=
github.com/aws/aws-sdk-go v1.25.49/go.mod h1:KmX6BPdI08NWTb3/sm4ZGu5ShLoqVDhKgpiN924inxo=
github.com/aws/aws-sdk-go v1.35.9 h1:b1HiUpdkFLJyoOQ7zas36YHzjNHH0ivHx/G5lWBeg+U=
github.com/bgentry/go-netrc v0.0.0-20140422174119-9fd32a8b3d3d h1:xDfNPAt8lFiC1UJrqV3uuy861HCTo708pDMbjHHdCas=
github.com/bgentry/go-netrc v0.0.0-20140422174119-9fd32a8b3d3d/go.mod h1:6QX/PXZ00z/TKoufEY6K/a0k6AhaJrQKdFe6OfVXsa4=
github.com/bgentry/speakeasy v0.1.0 h1:ByYyxL9InA1OWqxJqqp2A5pYHUrCiAL6K3J+LKSsQkY=
Expand Down Expand Up @@ -101,6 +102,7 @@ github.com/hashicorp/terraform-config-inspect v0.0.0-20191115094559-17f92b0546e8
github.com/hashicorp/terraform-config-inspect v0.0.0-20191115094559-17f92b0546e8/go.mod h1:p+ivJws3dpqbp1iP84+npOyAmTTOLMgCzrXd3GSdn/A=
github.com/hashicorp/terraform-plugin-sdk v1.4.0 h1:b1LluARpES0Gq78oF4a9of3eS0iXM5JTwlt604vGvBY=
github.com/hashicorp/terraform-plugin-sdk v1.4.0/go.mod h1:H5QLx/uhwfxBZ59Bc5SqT19M4i+fYt7LZjHTpbLZiAg=
github.com/hashicorp/terraform-plugin-sdk v1.16.0 h1:NrkXMRjHErUPPTHQkZ6JIn6bByiJzGnlJzH1rVdNEuE=
github.com/hashicorp/terraform-svchost v0.0.0-20191011084731-65d371908596 h1:hjyO2JsNZUKT1ym+FAdlBEkGPevazYsmVgIMw7dVELg=
github.com/hashicorp/terraform-svchost v0.0.0-20191011084731-65d371908596/go.mod h1:kNDNcF7sN4DocDLBkQYz73HGKwN1ANB1blq4lIYLYvg=
github.com/hashicorp/yamux v0.0.0-20180604194846-3520598351bb/go.mod h1:+NfK9FKeTrX5uv1uIXGdwYDTeHna2qgaIlx54MXqjAM=
Expand Down
34 changes: 34 additions & 0 deletions serverless/aws.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
package serverless

import (
"fmt"
"regexp"

"github.com/aws/aws-sdk-go/aws/credentials"
"github.com/aws/aws-sdk-go/aws/credentials/stscreds"
"github.com/aws/aws-sdk-go/aws/session"
)

func loadAWSCredentials(resource getter) (*credentials.Credentials, error) {
configs := resource.Get("aws_config").([]interface{})
if len(configs) == 0 || configs[0] == nil {
return nil, nil
}
awsConfig := configs[0].(map[string]interface{})

accountId := awsConfig["account_id"].(string)
callerArn := awsConfig["caller_arn"].(string)

re := regexp.MustCompile(`.*assumed-role/([\w+=,.@-]+)/.*`)
var role string
if result := re.FindStringSubmatch(callerArn); result != nil {
role = result[1]
} else {
return nil, fmt.Errorf("Could not parse role name from callerArn %s", callerArn)
}

roleArn := fmt.Sprintf("arn:aws:iam::%s:role/%s", accountId, role)

sess := session.Must(session.NewSession())
return stscreds.NewCredentials(sess, roleArn), nil
}
31 changes: 29 additions & 2 deletions serverless/resource_deployment.go
Original file line number Diff line number Diff line change
Expand Up @@ -67,6 +67,27 @@ func resourceDeployment() *schema.Resource {
Optional: true,
Computed: true,
},
"aws_config": &schema.Schema{
Type: schema.TypeList,
Optional: true,
MaxItems: 1,
Elem: &schema.Resource{
Schema: map[string]*schema.Schema{
"account_id": {
Type: schema.TypeString,
Required: true,
},
"caller_arn": {
Type: schema.TypeString,
Required: true,
},
"caller_user": {
Type: schema.TypeString,
Required: true,
},
},
},
},
},

// Only trigger a deploy if either the Serverless config or Serverless zip archive has changed.
Expand Down Expand Up @@ -121,15 +142,21 @@ func resourceDeploymentRead(d *schema.ResourceData, m interface{}) error {
stage := d.Get("stage").(string)

sess := session.Must(session.NewSession())
cf := cloudformation.New(sess)
creds, awsErr := loadAWSCredentials(d)
if awsErr != nil {
return awsErr
}

cf := cloudformation.New(sess, &aws.Config{Credentials: creds})

_, err := cf.DescribeStacks(&cloudformation.DescribeStacksInput{
StackName: aws.String(strings.Join([]string{id, stage}, "-")),
})
if err != nil {
if aerr, ok := err.(awserr.Error); ok {
if aerr.Code() == "ValidationError" && strings.Contains(aerr.Message(), "does not exist") {
d.SetId("")
return nil
return err
}
}
return err
Expand Down
40 changes: 40 additions & 0 deletions serverless/serverless.go
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,9 @@ import (
"os/exec"
"path/filepath"
"runtime"
"strings"

"github.com/aws/aws-sdk-go/aws/credentials"
"golang.org/x/mod/sumdb/dirhash"
)

Expand Down Expand Up @@ -178,6 +180,14 @@ func NewServerless(resource getter) (*Serverless, error) {
args: args,
}

if awsCreds, err := loadAWSCredentials(resource); err != nil {
return nil, err
} else if awsCreds != nil {
if err := updateEnvWithCredentials(s, awsCreds); err != nil {
return nil, err
}
}

if err := s.loadServerlessConfig(); err != nil {
return nil, err
}
Expand All @@ -189,6 +199,36 @@ func NewServerless(resource getter) (*Serverless, error) {
return s, nil
}

func updateEnvWithCredentials(s *Serverless, creds *credentials.Credentials) error {
// Read credentials and populate env value so that
// serverless uses the correct credentials
credValue, err := creds.Get()
if err != nil {
return fmt.Errorf("Failed retreiving Assume role credentials:\n%w", err)
}

newEnv := []string{
fmt.Sprintf("AWS_ACCESS_KEY_ID=%s", credValue.AccessKeyID),
fmt.Sprintf("AWS_SECRET_ACCESS_KEY=%s", credValue.SecretAccessKey),
fmt.Sprintf("AWS_SESSION_TOKEN=%s", credValue.SessionToken),
}

for _, env := range s.env {
envPair := strings.SplitN(env, "=", 2)
key := envPair[0]
value := envPair[1]

if key == "AWS_ACCESS_KEY_ID" || key == "AWS_SECRET_ACCESS_KEY" || key == "AWS_SESSION_TOKEN" {
continue
}

newEnv = append(newEnv, fmt.Sprintf("%s=%s", key, value))
}

s.env = newEnv
return nil
}

func buildBinPath(configDir, binDir string) string {
var suffix string

Expand Down

0 comments on commit 010aa22

Please sign in to comment.