Skip to content

Commit

Permalink
add IAM credential handling for running in ECS
Browse files Browse the repository at this point in the history
workaround terraform not using ECS task role for S3 backend

hashicorp/terraform-provider-aws#259
hashicorp/terraform-provider-terraform#15
  • Loading branch information
Patrick Otto committed Nov 17, 2017
1 parent 55c536c commit df443f8
Show file tree
Hide file tree
Showing 3 changed files with 85 additions and 0 deletions.
18 changes: 18 additions & 0 deletions server/events/command_handler.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ package events

import (
"fmt"
"os"

"github.com/google/go-github/github"
"github.com/hootsuite/atlantis/server/events/models"
Expand Down Expand Up @@ -132,6 +133,23 @@ func (c *CommandHandler) run(ctx *CommandContext) {
}
defer c.EnvLocker.Unlock(ctx.BaseRepo.FullName, ctx.Command.Environment, ctx.Pull.Num)

// check if we're running in ECS and try to fetch IAM credentials for task's role
credentialsRelativeUri := os.Getenv("AWS_CONTAINER_CREDENTIALS_RELATIVE_URI")
if credentialsRelativeUri != "" {
err := handleEcsCredentials(credentialsRelativeUri)
if err != nil {
ctx.Log.Warn("failed to fetch ECS credentials")
return
}
}

defer func() {
err := os.RemoveAll("/home/atlantis/.aws")
if err != nil {
ctx.Log.Err("failed to remove /home/atlantis/.aws/credentials")
}
}()

var cr CommandResponse
switch ctx.Command.Name {
case Plan:
Expand Down
65 changes: 65 additions & 0 deletions server/events/ecs.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,65 @@
package events

import (
"encoding/json"
"fmt"
"io/ioutil"
"net/http"
"os"
"strings"
"time"
)

type EcsCredentials struct {
AccessKeyId string
Expiration string
RoleArn string
SecretAccessKey string
Token string
}

func handleEcsCredentials(relative_uri string) error {
httpClient := &http.Client{Timeout: 5 * time.Second}
url := fmt.Sprintf("http://169.254.170.2%s", relative_uri)
r, err := httpClient.Get(url)
if err != nil {
return err
}
defer r.Body.Close()

credentials := &EcsCredentials{}
err = json.NewDecoder(r.Body).Decode(credentials)
if err != nil {
return err
}

err = writeAwsCredentials(credentials)
if err != nil {
return err
}

return nil
}

func writeAwsCredentials(credentials *EcsCredentials) error {
template := []string{
"[default]",
fmt.Sprintf("aws_access_key_id=%s", credentials.AccessKeyId),
fmt.Sprintf("aws_secret_access_key=%s", credentials.SecretAccessKey),
fmt.Sprintf("aws_session_token=%s", credentials.Token),
}

templateRendered := strings.Join(template, "\n")

err := os.MkdirAll("/home/atlantis/.aws", os.FileMode(0700))
if err != nil {
return err
}

werr := ioutil.WriteFile("/home/atlantis/.aws/credentials", []byte(templateRendered), 0644)
if werr != nil {
return err
}

return nil
}
2 changes: 2 additions & 0 deletions server/events/terraform/terraform_client.go
Original file line number Diff line number Diff line change
Expand Up @@ -103,6 +103,7 @@ func (c *Client) RunCommandWithVersion(log *logging.SimpleLogger, path string, a
// applied to the init command.
func (c *Client) RunInitAndEnv(log *logging.SimpleLogger, path string, env string, extraInitArgs []string, version *version.Version) ([]string, error) {
var outputs []string

// run terraform init
output, err := c.RunCommandWithVersion(log, path, append([]string{"init", "-no-color"}, extraInitArgs...), version, env)
outputs = append(outputs, output)
Expand All @@ -122,5 +123,6 @@ func (c *Client) RunInitAndEnv(log *logging.SimpleLogger, path string, env strin
return outputs, err
}
}

return outputs, nil
}

0 comments on commit df443f8

Please sign in to comment.