func TestResignRequestExpiredCreds(t *testing.T) { creds := credentials.NewStaticCredentials("AKID", "SECRET", "SESSION") r := aws.NewRequest( aws.NewService(&aws.Config{Credentials: creds}), &aws.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 TestIgnoreResignRequestWithValidCreds(t *testing.T) { r := aws.NewRequest( aws.NewService(&aws.Config{ Credentials: credentials.NewStaticCredentials("AKID", "SECRET", "SESSION"), Region: "us-west-2", }), &aws.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")) }
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"), } }
// 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 := NewService(&Config{MaxRetries: 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) { credExpiredAfterRetry = r.Config.Credentials.IsExpired() }) s.Handlers.Sign.Clear() s.Handlers.Sign.PushBack(func(r *Request) { r.Config.Credentials.Get() }) s.Handlers.Send.Clear() // mock sending s.Handlers.Send.PushBack(func(r *Request) { r.HTTPResponse = &reqs[reqNum] reqNum++ }) out := &testData{} r := NewRequest(s, &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) { fmt.Println(` ___ ___ ___ __ __ ___ __ _ /'___\ / __'\ /' _ '\/\ \/\ \ / __'\/\ \/'\ /\ \__//\ \_\ \/\ \/\ \ \ \_/ |/\ \_\ \/> </ \ \____\ \____/\ \_\ \_\ \___/ \ \____//\_/\_\ \/____/\/___/ \/_/\/_/\/__/ \/___/ \//\/_/ `) fmt.Println("This uninstaller needs AWS credentials to uninstall the Convox platform from") fmt.Println("your AWS account. These credentials will only be used to communicate") fmt.Println("between this uninstaller running on your computer and the AWS API.") fmt.Println("") fmt.Println("We recommend that you create a new set of credentials exclusively for this") fmt.Println("uninstall process and then delete them once the uninstaller has completed.") fmt.Println("") fmt.Println("To generate a new set of AWS credentials go to:") fmt.Println("https://docs.convox.com/docs/creating-an-iam-user-and-credentials") fmt.Println("") reader := bufio.NewReader(os.Stdin) access := os.Getenv("AWS_ACCESS_KEY_ID") secret := os.Getenv("AWS_SECRET_ACCESS_KEY") region := c.String("region") if access == "" || secret == "" { var err error fmt.Print("AWS Access Key: ") access, err = reader.ReadString('\n') if err != nil { stdcli.Error(err) } fmt.Print("AWS Secret Access Key: ") secret, err = reader.ReadString('\n') if err != nil { stdcli.Error(err) } } stackName := c.String("stack-name") fmt.Println("") fmt.Println("Uninstalling Convox...") distinctId := randomString(10) access = strings.TrimSpace(access) secret = strings.TrimSpace(secret) CloudFormation := cloudformation.New(&aws.Config{ Region: region, Credentials: credentials.NewStaticCredentials(access, secret, ""), }) 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(` ___ ___ ___ __ __ ___ __ _ / ___\ / __ \ / _ \/\ \/\ \ / __ \/\ \/ \ /\ \__//\ \_\ \/\ \/\ \ \ \_/ |/\ \_\ \/> </ \ \____\ \____/\ \_\ \_\ \___/ \ \____//\_/\_\ \/____/\/___/ \/_/\/_/\/__/ \/___/ \//\/_/ `) fmt.Println("This installer needs AWS credentials to install the Convox platform into") fmt.Println("your AWS account. These credentials will only be used to communicate") fmt.Println("between this installer running on your computer and the AWS API.") fmt.Println("") fmt.Println("We recommend that you create a new set of credentials exclusively for this") fmt.Println("install process and then delete them once the installer has completed.") fmt.Println("") fmt.Println("To generate a new set of AWS credentials go to:") fmt.Println("https://docs.convox.com/docs/creating-an-iam-user-and-credentials") fmt.Println("") distinctId, err := currentId() if err != nil { handleError("install", distinctId, err) return } reader := bufio.NewReader(os.Stdin) access := os.Getenv("AWS_ACCESS_KEY_ID") secret := os.Getenv("AWS_SECRET_ACCESS_KEY") if access == "" || secret == "" { var err error fmt.Print("AWS Access Key ID: ") access, err = reader.ReadString('\n') if err != nil { stdcli.Error(err) } fmt.Print("AWS Secret Access Key: ") secret, err = reader.ReadString('\n') if err != nil { stdcli.Error(err) } fmt.Println("") } development := "No" if c.Bool("development") { development = "Yes" } key := c.String("key") stackName := c.String("stack-name") version := c.String("version") instanceCount := fmt.Sprintf("%d", c.Int("instance-count")) fmt.Println("Installing Convox...") access = strings.TrimSpace(access) secret = strings.TrimSpace(secret) password := randomString(30) CloudFormation := cloudformation.New(&aws.Config{ Region: region, Credentials: credentials.NewStaticCredentials(access, secret, ""), }) res, err := CloudFormation.CreateStack(&cloudformation.CreateStackInput{ Capabilities: []*string{aws.String("CAPABILITY_IAM")}, Parameters: []*cloudformation.Parameter{ &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("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(version)}, }, StackName: aws.String(stackName), TemplateURL: aws.String(FormationUrl), }) 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", "") }
func cmdUninstall(c *cli.Context) { if !c.Bool("force") { apps := getApps() if len(*apps) != 0 { stdcli.Error(fmt.Errorf("Please delete all apps before uninstalling.")) } } fmt.Println(` ___ ___ ___ __ __ ___ __ _ /'___\ / __'\ /' _ '\/\ \/\ \ / __'\/\ \/'\ /\ \__//\ \_\ \/\ \/\ \ \ \_/ |/\ \_\ \/> </ \ \____\ \____/\ \_\ \_\ \___/ \ \____//\_/\_\ \/____/\/___/ \/_/\/_/\/__/ \/___/ \//\/_/ `) fmt.Println("This uninstaller needs AWS credentials to uninstall the Convox platform from") fmt.Println("your AWS account. These credentials will only be used to communicate") fmt.Println("between this uninstaller running on your computer and the AWS API.") fmt.Println("") fmt.Println("We recommend that you create a new set of credentials exclusively for this") fmt.Println("uninstall process and then delete them once the uninstaller has completed.") fmt.Println("") fmt.Println("To generate a new set of AWS credentials go to:") fmt.Println("https://console.aws.amazon.com/iam/home#security_credential") fmt.Println("") reader := bufio.NewReader(os.Stdin) access := os.Getenv("AWS_ACCESS_KEY_ID") secret := os.Getenv("AWS_SECRET_ACCESS_KEY") if access == "" || secret == "" { var err error fmt.Print("AWS Access Key: ") access, err = reader.ReadString('\n') if err != nil { stdcli.Error(err) } fmt.Print("AWS Secret Access Key: ") secret, err = reader.ReadString('\n') if err != nil { stdcli.Error(err) } } stackName := os.Getenv("STACK_NAME") if stackName == "" { stackName = "convox" } fmt.Println("") fmt.Println("Uninstalling Convox...") distinctId := randomString(10) access = strings.TrimSpace(access) secret = strings.TrimSpace(secret) CloudFormation := cloudformation.New(&aws.Config{ Region: c.String("region"), Credentials: credentials.NewStaticCredentials(access, secret, ""), }) res, err := CloudFormation.DescribeStackResources(&cloudformation.DescribeStackResourcesInput{ StackName: aws.String(stackName), }) if err != nil { handleError("uninstall", distinctId, err) return } stackId := "" bucket := "" for _, r := range res.StackResources { stackId = *r.StackID if *r.LogicalResourceID == "RegistryBucket" { bucket = *r.PhysicalResourceID } } _, err = CloudFormation.DeleteStack(&cloudformation.DeleteStackInput{ StackName: aws.String(stackName), }) if err != nil { handleError("uninstall", distinctId, err) return } sendMixpanelEvent("convox-uninstall-start") fmt.Printf("Cleaning up registry...\n") S3 := s3.New(&aws.Config{ Region: c.String("region"), Credentials: credentials.NewStaticCredentials(access, secret, ""), }) req := &s3.ListObjectVersionsInput{ Bucket: aws.String(bucket), } sres, err := S3.ListObjectVersions(req) if err != nil { if awsErr, ok := err.(awserr.Error); ok { // Don't block uninstall NoSuchBucket if awsErr.Code() != "NoSuchBucket" { handleError("uninstall", distinctId, err) } } } for _, v := range sres.Versions { req := &s3.DeleteObjectInput{ Bucket: aws.String(bucket), Key: aws.String(*v.Key), VersionID: aws.String(*v.VersionID), } _, err := S3.DeleteObject(req) if err != nil { handleError("uninstall", distinctId, err) return } } host, err := waitForCompletion(stackId, CloudFormation, true) if err != nil { handleError("uninstall", distinctId, err) return } if configuredHost, _ := currentHost(); configuredHost == host { removeHost() } removeLogin(host) fmt.Println("Successfully uninstalled.") sendMixpanelEvent("convox-uninstall-success") }
func cmdInstall(c *cli.Context) { fmt.Println(` ___ ___ ___ __ __ ___ __ _ / ___\ / __ \ / _ \/\ \/\ \ / __ \/\ \/ \ /\ \__//\ \_\ \/\ \/\ \ \ \_/ |/\ \_\ \/> </ \ \____\ \____/\ \_\ \_\ \___/ \ \____//\_/\_\ \/____/\/___/ \/_/\/_/\/__/ \/___/ \//\/_/ `) fmt.Println("This installer needs AWS credentials to install the Convox platform into") fmt.Println("your AWS account. These credentials will only be used to communicate") fmt.Println("between this installer running on your computer and the AWS API.") fmt.Println("") fmt.Println("We recommend that you create a new set of credentials exclusively for this") fmt.Println("install process and then delete them once the installer has completed.") fmt.Println("") fmt.Println("To generate a new set of AWS credentials go to:") fmt.Println("https://console.aws.amazon.com/iam/home?region=us-east-1#security_credential") fmt.Println("") distinctId, err := currentId() if err != nil { handleError("install", distinctId, err) return } reader := bufio.NewReader(os.Stdin) access := os.Getenv("AWS_ACCESS_KEY_ID") secret := os.Getenv("AWS_SECRET_ACCESS_KEY") if access == "" || secret == "" { var err error fmt.Print("AWS Access Key ID: ") access, err = reader.ReadString('\n') if err != nil { stdcli.Error(err) } fmt.Print("AWS Secret Access Key: ") secret, err = reader.ReadString('\n') if err != nil { stdcli.Error(err) } fmt.Println("") } development := os.Getenv("DEVELOPMENT") if development != "Yes" { development = "No" } key := os.Getenv("KEY") stackName := os.Getenv("STACK_NAME") if stackName == "" { stackName = "convox" } version := os.Getenv("VERSION") if version == "" { version = "latest" } fmt.Println("Installing Convox...") access = strings.TrimSpace(access) secret = strings.TrimSpace(secret) password := randomString(30) CloudFormation := cloudformation.New(&aws.Config{ Region: "us-east-1", Credentials: credentials.NewStaticCredentials(access, secret, ""), }) res, err := CloudFormation.CreateStack(&cloudformation.CreateStackInput{ Capabilities: []*string{aws.String("CAPABILITY_IAM")}, Parameters: []*cloudformation.Parameter{ &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("InstanceCount"), ParameterValue: aws.String("3")}, &cloudformation.Parameter{ParameterKey: aws.String("InstanceType"), ParameterValue: aws.String("t2.small")}, &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("Version"), ParameterValue: aws.String(version)}, }, StackName: aws.String(stackName), TemplateURL: aws.String(FormationUrl), }) if err != nil { handleError("install", distinctId, err) return } 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") }