provider/aws: Add S3 Bucket name validation
Adds region specific S3 bucket name validation. Currently all regions except for us-east-1 force a dns-compliant naming convention. Thus we cannot utilize the standard `SchemaValidateFunc` interface to validate an S3 bucket name. This change creates a helper function outside of the schema validation interface so we can validate S3 bucket names for both naming conventions. At a later date, when the us-east-1 region is updated to conform to a dns-compliant naming scheme, we can refactor the `validateS3BucketName` function to fit the `SchemaValidateFunc` interface.
This commit is contained in:
parent
ba41375fd9
commit
b9d4a54341
|
@ -6,6 +6,8 @@ import (
|
||||||
"fmt"
|
"fmt"
|
||||||
"log"
|
"log"
|
||||||
"net/url"
|
"net/url"
|
||||||
|
"regexp"
|
||||||
|
"strings"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
"github.com/aws/aws-sdk-go/aws"
|
"github.com/aws/aws-sdk-go/aws"
|
||||||
|
@ -408,6 +410,10 @@ func resourceAwsS3BucketCreate(d *schema.ResourceData, meta interface{}) error {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if err := validateS3BucketName(bucket, awsRegion); err != nil {
|
||||||
|
return fmt.Errorf("Error validating S3 bucket name: %s", err)
|
||||||
|
}
|
||||||
|
|
||||||
err := resource.Retry(5*time.Minute, func() *resource.RetryError {
|
err := resource.Retry(5*time.Minute, func() *resource.RetryError {
|
||||||
log.Printf("[DEBUG] Trying to create new S3 bucket: %q", bucket)
|
log.Printf("[DEBUG] Trying to create new S3 bucket: %q", bucket)
|
||||||
_, err := s3conn.CreateBucket(req)
|
_, err := s3conn.CreateBucket(req)
|
||||||
|
@ -1728,6 +1734,40 @@ func validateS3BucketRequestPayerType(v interface{}, k string) (ws []string, err
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// validateS3BucketName validates any S3 bucket name that is not inside the us-east-1 region.
|
||||||
|
// Buckets outside of this region have to be DNS-compliant. After the same restrictions are
|
||||||
|
// applied to buckets in the us-east-1 region, this function can be refactored as a SchemaValidateFunc
|
||||||
|
func validateS3BucketName(value string, region string) error {
|
||||||
|
if region != "us-east-1" {
|
||||||
|
if (len(value) < 3) || (len(value) > 63) {
|
||||||
|
return fmt.Errorf("%q must contain from 3 to 63 characters", value)
|
||||||
|
}
|
||||||
|
if !regexp.MustCompile(`^[0-9a-z-.]+$`).MatchString(value) {
|
||||||
|
return fmt.Errorf("only lowercase alphanumeric characters and hyphens allowed in %q", value)
|
||||||
|
}
|
||||||
|
if regexp.MustCompile(`^(?:[0-9]{1,3}\.){3}[0-9]{1,3}$`).MatchString(value) {
|
||||||
|
return fmt.Errorf("%q must not be formatted as an IP address", value)
|
||||||
|
}
|
||||||
|
if strings.HasPrefix(value, `.`) {
|
||||||
|
return fmt.Errorf("%q cannot start with a period", value)
|
||||||
|
}
|
||||||
|
if strings.HasSuffix(value, `.`) {
|
||||||
|
return fmt.Errorf("%q cannot end with a period", value)
|
||||||
|
}
|
||||||
|
if strings.Contains(value, `..`) {
|
||||||
|
return fmt.Errorf("%q can be only one period between labels", value)
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
if len(value) > 255 {
|
||||||
|
return fmt.Errorf("%q must contain less than 256 characters", value)
|
||||||
|
}
|
||||||
|
if !regexp.MustCompile(`^[0-9a-zA-Z-._]+$`).MatchString(value) {
|
||||||
|
return fmt.Errorf("only alphanumeric characters, hyphens, periods, and underscores allowed in %q", value)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
func expirationHash(v interface{}) int {
|
func expirationHash(v interface{}) int {
|
||||||
var buf bytes.Buffer
|
var buf bytes.Buffer
|
||||||
m := v.(map[string]interface{})
|
m := v.(map[string]interface{})
|
||||||
|
|
|
@ -12,6 +12,8 @@ import (
|
||||||
"github.com/hashicorp/terraform/helper/resource"
|
"github.com/hashicorp/terraform/helper/resource"
|
||||||
"github.com/hashicorp/terraform/terraform"
|
"github.com/hashicorp/terraform/terraform"
|
||||||
|
|
||||||
|
"strings"
|
||||||
|
|
||||||
"github.com/aws/aws-sdk-go/aws"
|
"github.com/aws/aws-sdk-go/aws"
|
||||||
"github.com/aws/aws-sdk-go/aws/awserr"
|
"github.com/aws/aws-sdk-go/aws/awserr"
|
||||||
"github.com/aws/aws-sdk-go/service/s3"
|
"github.com/aws/aws-sdk-go/service/s3"
|
||||||
|
@ -690,6 +692,68 @@ func TestAccAWSS3Bucket_ReplicationExpectVersioningValidationError(t *testing.T)
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func TestAWSS3BucketName(t *testing.T) {
|
||||||
|
validDnsNames := []string{
|
||||||
|
"foobar",
|
||||||
|
"foo.bar",
|
||||||
|
"foo.bar.baz",
|
||||||
|
"1234",
|
||||||
|
"foo-bar",
|
||||||
|
strings.Repeat("x", 63),
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, v := range validDnsNames {
|
||||||
|
if err := validateS3BucketName(v, "us-west-2"); err != nil {
|
||||||
|
t.Fatalf("%q should be a valid S3 bucket name", v)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
invalidDnsNames := []string{
|
||||||
|
"foo..bar",
|
||||||
|
"Foo.Bar",
|
||||||
|
"192.168.0.1",
|
||||||
|
"127.0.0.1",
|
||||||
|
".foo",
|
||||||
|
"bar.",
|
||||||
|
"foo_bar",
|
||||||
|
strings.Repeat("x", 64),
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, v := range invalidDnsNames {
|
||||||
|
if err := validateS3BucketName(v, "us-west-2"); err == nil {
|
||||||
|
t.Fatalf("%q should not be a valid S3 bucket name", v)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
validEastNames := []string{
|
||||||
|
"foobar",
|
||||||
|
"foo_bar",
|
||||||
|
"127.0.0.1",
|
||||||
|
"foo..bar",
|
||||||
|
"foo_bar_baz",
|
||||||
|
"foo.bar.baz",
|
||||||
|
"Foo.Bar",
|
||||||
|
strings.Repeat("x", 255),
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, v := range validEastNames {
|
||||||
|
if err := validateS3BucketName(v, "us-east-1"); err != nil {
|
||||||
|
t.Fatalf("%q should be a valid S3 bucket name", v)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
invalidEastNames := []string{
|
||||||
|
"foo;bar",
|
||||||
|
strings.Repeat("x", 256),
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, v := range invalidEastNames {
|
||||||
|
if err := validateS3BucketName(v, "us-east-1"); err == nil {
|
||||||
|
t.Fatalf("%q should not be a valid S3 bucket name", v)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
func testAccCheckAWSS3BucketDestroy(s *terraform.State) error {
|
func testAccCheckAWSS3BucketDestroy(s *terraform.State) error {
|
||||||
return testAccCheckInstanceDestroyWithProvider(s, testAccProvider)
|
return testAccCheckInstanceDestroyWithProvider(s, testAccProvider)
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue