func Credentials(req *Request) *credentials.Credentials { if req != nil { if access, ok := req.ResourceProperties["AccessId"].(string); ok && access != "" { if secret, ok := req.ResourceProperties["SecretAccessKey"].(string); ok && secret != "" { return credentials.NewStaticCredentials(access, secret, "") } } } if os.Getenv("AWS_ACCESS") != "" { return credentials.NewStaticCredentials(os.Getenv("AWS_ACCESS"), os.Getenv("AWS_SECRET"), "") } // return credentials.NewCredentials(&credentials.EC2RoleProvider{}) return credentials.NewEnvCredentials() }
func DockerLogin(ac docker.AuthConfiguration) (string, error) { if ac.Email == "" { ac.Email = "*****@*****.**" } // if ECR URL, try Username and Password as IAM keys to get auth token if match := regexpECR.FindStringSubmatch(ac.ServerAddress); len(match) > 1 { ECR := ecr.New(session.New(), &aws.Config{ Credentials: credentials.NewStaticCredentials(ac.Username, ac.Password, ""), Region: aws.String(match[2]), }) res, err := ECR.GetAuthorizationToken(&ecr.GetAuthorizationTokenInput{ RegistryIds: []*string{aws.String(match[1])}, }) if err != nil { return "", err } if len(res.AuthorizationData) < 1 { return "", fmt.Errorf("no authorization data") } endpoint := *res.AuthorizationData[0].ProxyEndpoint data, err := base64.StdEncoding.DecodeString(*res.AuthorizationData[0].AuthorizationToken) if err != nil { return "", err } parts := strings.SplitN(string(data), ":", 2) ac.Password = parts[1] ac.ServerAddress = endpoint[8:] ac.Username = parts[0] } args := []string{"login", "-e", ac.Email, "-u", ac.Username, "-p", ac.Password, ac.ServerAddress} out, err := exec.Command("docker", args...).CombinedOutput() // log args with password masked args[6] = "*****" cmd := fmt.Sprintf("docker %s", strings.Trim(fmt.Sprint(args), "[]")) if err != nil { fmt.Printf("ns=kernel cn=docker at=DockerLogin state=error step=exec.Command cmd=%q out=%q err=%q\n", cmd, out, err) } else { fmt.Printf("ns=kernel cn=docker at=DockerLogin state=success step=exec.Command cmd=%q\n", cmd) } return ac.ServerAddress, err }
func awsConfig() *aws.Config { config := &aws.Config{ Credentials: credentials.NewStaticCredentials(os.Getenv("AWS_ACCESS"), os.Getenv("AWS_SECRET"), ""), } if e := os.Getenv("AWS_ENDPOINT"); e != "" { config.Endpoint = aws.String(e) } if r := os.Getenv("AWS_REGION"); r != "" { config.Region = aws.String(r) } return config }
func awsConfig(region string, creds *AwsCredentials) *aws.Config { config := &aws.Config{ Region: aws.String(region), Credentials: credentials.NewStaticCredentials(creds.Access, creds.Secret, creds.Session), } if e := os.Getenv("AWS_ENDPOINT"); e != "" { config.Endpoint = aws.String(e) } if r := os.Getenv("AWS_REGION"); r != "" { config.Region = aws.String(r) } return config }
func TestResignRequestExpiredCreds(t *testing.T) { creds := credentials.NewStaticCredentials("AKID", "SECRET", "SESSION") svc := awstesting.NewClient(&aws.Config{Credentials: creds}) r := svc.NewRequest( &request.Operation{ Name: "BatchGetItem", HTTPMethod: "POST", HTTPPath: "/", }, nil, nil, ) Sign(r) querySig := r.HTTPRequest.Header.Get("Authorization") creds.Expire() Sign(r) assert.NotEqual(t, querySig, r.HTTPRequest.Header.Get("Authorization")) }
func buildSigner(serviceName string, region string, signTime time.Time, expireTime time.Duration, body string) signer { endpoint := "https://" + serviceName + "." + region + ".amazonaws.com" reader := strings.NewReader(body) req, _ := http.NewRequest("POST", endpoint, reader) req.URL.Opaque = "//example.org/bucket/key-._~,!@#$%^&*()" req.Header.Add("X-Amz-Target", "prefix.Operation") req.Header.Add("Content-Type", "application/x-amz-json-1.0") req.Header.Add("Content-Length", string(len(body))) req.Header.Add("X-Amz-Meta-Other-Header", "some-value=!@#$%^&* (+)") return signer{ Request: req, Time: signTime, ExpireTime: expireTime, Query: req.URL.Query(), Body: reader, ServiceName: serviceName, Region: region, Credentials: credentials.NewStaticCredentials("AKID", "SECRET", "SESSION"), } }
func TestIgnoreResignRequestWithValidCreds(t *testing.T) { svc := awstesting.NewClient(&aws.Config{ Credentials: credentials.NewStaticCredentials("AKID", "SECRET", "SESSION"), Region: aws.String("us-west-2"), }) r := svc.NewRequest( &request.Operation{ Name: "BatchGetItem", HTTPMethod: "POST", HTTPPath: "/", }, nil, nil, ) Sign(r) sig := r.HTTPRequest.Header.Get("Authorization") Sign(r) assert.Equal(t, sig, r.HTTPRequest.Header.Get("Authorization")) }
// test that the request is retried after the credentials are expired. func TestRequestRecoverExpiredCreds(t *testing.T) { reqNum := 0 reqs := []http.Response{ {StatusCode: 400, Body: body(`{"__type":"ExpiredTokenException","message":"expired token"}`)}, {StatusCode: 200, Body: body(`{"data":"valid"}`)}, } s := awstesting.NewClient(&aws.Config{MaxRetries: aws.Int(10), Credentials: credentials.NewStaticCredentials("AKID", "SECRET", "")}) s.Handlers.Validate.Clear() s.Handlers.Unmarshal.PushBack(unmarshal) s.Handlers.UnmarshalError.PushBack(unmarshalError) credExpiredBeforeRetry := false credExpiredAfterRetry := false s.Handlers.AfterRetry.PushBack(func(r *request.Request) { credExpiredAfterRetry = r.Config.Credentials.IsExpired() }) s.Handlers.Sign.Clear() s.Handlers.Sign.PushBack(func(r *request.Request) { r.Config.Credentials.Get() }) s.Handlers.Send.Clear() // mock sending s.Handlers.Send.PushBack(func(r *request.Request) { r.HTTPResponse = &reqs[reqNum] reqNum++ }) out := &testData{} r := s.NewRequest(&request.Operation{Name: "Operation"}, nil, out) err := r.Send() assert.Nil(t, err) assert.False(t, credExpiredBeforeRetry, "Expect valid creds before retry check") assert.True(t, credExpiredAfterRetry, "Expect expired creds after retry check") assert.False(t, s.Config.Credentials.IsExpired(), "Expect valid creds after cred expired recovery") assert.Equal(t, 1, int(r.RetryCount)) assert.Equal(t, "valid", out.Data) }
func cmdUninstall(c *cli.Context) { if !c.Bool("force") { apps, err := rackClient(c).GetApps() if err != nil { stdcli.Error(err) return } if len(apps) != 0 { stdcli.Error(fmt.Errorf("Please delete all apps before uninstalling.")) } } fmt.Println(Banner) creds, err := readCredentials(c) if err != nil { stdcli.Error(err) return } if creds == nil { stdcli.Error(fmt.Errorf("error reading credentials")) return } region := c.String("region") stackName := c.String("stack-name") fmt.Println("") fmt.Println("Uninstalling Convox...") distinctId := randomString(10) CloudFormation := cloudformation.New(&aws.Config{ Region: aws.String(region), Credentials: credentials.NewStaticCredentials(creds.Access, creds.Secret, creds.Session), }) res, err := CloudFormation.DescribeStacks(&cloudformation.DescribeStacksInput{ StackName: aws.String(stackName), }) if err != nil { sendMixpanelEvent(fmt.Sprintf("convox-uninstall-error"), err.Error()) if awsErr, ok := err.(awserr.Error); ok { if awsErr.Code() == "ValidationError" { stdcli.Error(fmt.Errorf("Stack %q does not exist.", stackName)) } } stdcli.Error(err) } stackId := *res.Stacks[0].StackId _, err = CloudFormation.DeleteStack(&cloudformation.DeleteStackInput{ StackName: aws.String(stackId), }) if err != nil { handleError("uninstall", distinctId, err) return } sendMixpanelEvent("convox-uninstall-start", "") _, err = waitForCompletion(stackId, CloudFormation, true) if err != nil { handleError("uninstall", distinctId, err) return } host := "" for _, o := range res.Stacks[0].Outputs { if *o.OutputKey == "Dashboard" { host = *o.OutputValue break } } if configuredHost, _ := currentHost(); configuredHost == host { removeHost() } removeLogin(host) fmt.Println("Successfully uninstalled.") sendMixpanelEvent("convox-uninstall-success", "") }
func cmdInstall(c *cli.Context) { region := c.String("region") if !lambdaRegions[region] { stdcli.Error(fmt.Errorf("Convox is not currently supported in %s", region)) } tenancy := "default" instanceType := c.String("instance-type") if c.Bool("dedicated") { tenancy = "dedicated" if strings.HasPrefix(instanceType, "t2") { stdcli.Error(fmt.Errorf("t2 instance types aren't supported in dedicated tenancy, please set --instance-type.")) } } fmt.Println(Banner) distinctId, err := currentId() creds, err := readCredentials(c) if err != nil { handleError("install", distinctId, err) return } if creds == nil { err = fmt.Errorf("error reading credentials") handleError("install", distinctId, err) return } reader := bufio.NewReader(os.Stdin) if email := c.String("email"); email != "" { distinctId = email updateId(distinctId) } else if terminal.IsTerminal(int(os.Stdin.Fd())) { fmt.Print("Email Address (optional, to receive project updates): ") email, err := reader.ReadString('\n') if err != nil { handleError("install", distinctId, err) return } if strings.TrimSpace(email) != "" { distinctId = email updateId(email) } } development := "No" if c.Bool("development") { isDevelopment = true development = "Yes" } encryption := "Yes" if c.Bool("disable-encryption") { encryption = "No" } ami := c.String("ami") key := c.String("key") stackName := c.String("stack-name") vpcCIDR := c.String("vpc-cidr") subnet0CIDR := c.String("subnet0-cidr") subnet1CIDR := c.String("subnet1-cidr") subnet2CIDR := c.String("subnet2-cidr") versions, err := version.All() if err != nil { handleError("install", distinctId, err) return } version, err := versions.Resolve(c.String("version")) if err != nil { handleError("install", distinctId, err) return } versionName := version.Version formationUrl := fmt.Sprintf(FormationUrl, versionName) instanceCount := fmt.Sprintf("%d", c.Int("instance-count")) fmt.Printf("Installing Convox (%s)...\n", versionName) if isDevelopment { fmt.Println("(Development Mode)") } password := randomString(30) CloudFormation := cloudformation.New(&aws.Config{ Region: aws.String(region), Credentials: credentials.NewStaticCredentials(creds.Access, creds.Secret, creds.Session), }) req := &cloudformation.CreateStackInput{ Capabilities: []*string{aws.String("CAPABILITY_IAM")}, Parameters: []*cloudformation.Parameter{ &cloudformation.Parameter{ParameterKey: aws.String("Ami"), ParameterValue: aws.String(ami)}, &cloudformation.Parameter{ParameterKey: aws.String("ClientId"), ParameterValue: aws.String(distinctId)}, &cloudformation.Parameter{ParameterKey: aws.String("Development"), ParameterValue: aws.String(development)}, &cloudformation.Parameter{ParameterKey: aws.String("Encryption"), ParameterValue: aws.String(encryption)}, &cloudformation.Parameter{ParameterKey: aws.String("InstanceCount"), ParameterValue: aws.String(instanceCount)}, &cloudformation.Parameter{ParameterKey: aws.String("InstanceType"), ParameterValue: aws.String(instanceType)}, &cloudformation.Parameter{ParameterKey: aws.String("Key"), ParameterValue: aws.String(key)}, &cloudformation.Parameter{ParameterKey: aws.String("Password"), ParameterValue: aws.String(password)}, &cloudformation.Parameter{ParameterKey: aws.String("Tenancy"), ParameterValue: aws.String(tenancy)}, &cloudformation.Parameter{ParameterKey: aws.String("Version"), ParameterValue: aws.String(versionName)}, &cloudformation.Parameter{ParameterKey: aws.String("Subnet0CIDR"), ParameterValue: aws.String(subnet0CIDR)}, &cloudformation.Parameter{ParameterKey: aws.String("Subnet1CIDR"), ParameterValue: aws.String(subnet1CIDR)}, &cloudformation.Parameter{ParameterKey: aws.String("Subnet2CIDR"), ParameterValue: aws.String(subnet2CIDR)}, &cloudformation.Parameter{ParameterKey: aws.String("VPCCIDR"), ParameterValue: aws.String(vpcCIDR)}, }, StackName: aws.String(stackName), TemplateURL: aws.String(formationUrl), } if tf := os.Getenv("TEMPLATE_FILE"); tf != "" { dat, err := ioutil.ReadFile(tf) if err != nil { handleError("install", distinctId, err) } req.TemplateURL = nil req.TemplateBody = aws.String(string(dat)) } res, err := CloudFormation.CreateStack(req) // NOTE: we start making lots of network requests here // so we're just going to return for testability if os.Getenv("AWS_REGION") == "test" { fmt.Println(*res.StackId) return } if err != nil { sendMixpanelEvent(fmt.Sprintf("convox-install-error"), err.Error()) if awsErr, ok := err.(awserr.Error); ok { if awsErr.Code() == "AlreadyExistsException" { stdcli.Error(fmt.Errorf("Stack %q already exists. Run `convox uninstall` then try again.", stackName)) } } stdcli.Error(err) } sendMixpanelEvent("convox-install-start", "") host, err := waitForCompletion(*res.StackId, CloudFormation, false) if err != nil { handleError("install", distinctId, err) return } fmt.Println("Waiting for load balancer...") waitForAvailability(fmt.Sprintf("http://%s/", host)) fmt.Println("Logging in...") addLogin(host, password) switchHost(host) fmt.Println("Success, try `convox apps`") sendMixpanelEvent("convox-install-success", "") }
package aws import ( "net/http" "reflect" "testing" "github.com/convox/rack/Godeps/_workspace/src/github.com/aws/aws-sdk-go/aws/credentials" ) var testCredentials = credentials.NewStaticCredentials("AKID", "SECRET", "SESSION") var copyTestConfig = Config{ Credentials: testCredentials, Endpoint: String("CopyTestEndpoint"), Region: String("COPY_TEST_AWS_REGION"), DisableSSL: Bool(true), HTTPClient: http.DefaultClient, LogLevel: LogLevel(LogDebug), Logger: NewDefaultLogger(), MaxRetries: Int(3), DisableParamValidation: Bool(true), DisableComputeChecksums: Bool(true), S3ForcePathStyle: Bool(true), } func TestCopy(t *testing.T) { want := copyTestConfig got := copyTestConfig.Copy() if !reflect.DeepEqual(*got, want) { t.Errorf("Copy() = %+v", got)