Created
December 21, 2018 15:21
-
-
Save a-h/b83249884e6e66ced90a5a777dac22a1 to your computer and use it in GitHub Desktop.
Circle CI AWS Credentials Cycling
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
package main | |
import ( | |
"bytes" | |
"encoding/json" | |
"flag" | |
"fmt" | |
"io/ioutil" | |
"log" | |
"net/http" | |
"net/url" | |
"github.com/aws/aws-sdk-go/aws" | |
"github.com/aws/aws-sdk-go/aws/session" | |
"github.com/aws/aws-sdk-go/service/iam" | |
) | |
var circleAPITokenFlag = flag.String("circle-api-token", "", "The Circle CI token from https://circleci.com/account/api") | |
type project string | |
type username string | |
var projectToUsername = map[project]username{ | |
project("github_organisation_or_username/project"): username("aws_iam_username"), | |
project("infinityworks/website"): username("website-ci"), | |
} | |
func main() { | |
flag.Parse() | |
if *circleAPITokenFlag == "" { | |
log.Fatal("missing -circle-api-token flag") | |
} | |
conf := aws.NewConfig().WithRegion("eu-west-2") | |
sess := session.Must(session.NewSession(conf)) | |
svc := iam.New(sess) | |
for p, u := range projectToUsername { | |
log.Printf("%s/%s: starting\n", p, u) | |
// List existing keys for user. | |
keysToRemove, err := svc.ListAccessKeys(&iam.ListAccessKeysInput{ | |
UserName: aws.String(string(u)), | |
}) | |
if err != nil { | |
log.Fatalf("%s/%s: error listing access keys: %v", p, u, err) | |
} | |
// Delete the old ones to make space. | |
for _, k := range keysToRemove.AccessKeyMetadata { | |
_, err = svc.DeleteAccessKey(&iam.DeleteAccessKeyInput{ | |
UserName: aws.String(string(u)), | |
AccessKeyId: k.AccessKeyId, | |
}) | |
if err != nil { | |
log.Printf("%s/%s: error deleting access key %s: %v", p, u, *k.AccessKeyId, err) | |
} | |
} | |
// Create a new one. | |
newKey, err := svc.CreateAccessKey(&iam.CreateAccessKeyInput{ | |
UserName: aws.String(string(u)), | |
}) | |
if err != nil { | |
log.Fatalf("%s/%s: error creating new access key: %v", p, u, err) | |
} | |
// Apply it to Circle CI. | |
err = updateCircleCIAWSCredentials(p, *circleAPITokenFlag, newKey.AccessKey) | |
if err != nil { | |
log.Fatalf("%s/%s: error updating Circle CI: %v", p, u, err) | |
} | |
} | |
log.Println("done") | |
} | |
func updateCircleCIAWSCredentials(p project, token string, key *iam.AccessKey) (err error) { | |
err = environmentPost(p, token, env{ | |
Name: "AWS_ACCESS_KEY_ID", | |
Value: *key.AccessKeyId, | |
}) | |
if err != nil { | |
return | |
} | |
err = environmentPost(p, token, env{ | |
Name: "AWS_SECRET_ACCESS_KEY", | |
Value: *key.SecretAccessKey, | |
}) | |
return | |
} | |
func environmentPost(p project, token string, e env) error { | |
u := fmt.Sprintf("https://circleci.com/api/v1.1/project/github/%s/envvar?circle-token=%s", | |
url.PathEscape(string(p)), | |
url.QueryEscape(token)) | |
buf, err := json.Marshal(e) | |
if err != nil { | |
return err | |
} | |
resp, err := http.Post(u, "application/json", bytes.NewReader(buf)) | |
if resp.StatusCode >= 300 { | |
bdy, _ := ioutil.ReadAll(resp.Body) | |
return fmt.Errorf("circleci returned status %d: %s", resp.StatusCode, string(bdy)) | |
} | |
return nil | |
} | |
type env struct { | |
Name string `json:"name"` | |
Value string `json:"value"` | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment