From 8159731c916ede87d770b17eb8ac8626e0095c01 Mon Sep 17 00:00:00 2001 From: Jake Champlin Date: Mon, 23 Jan 2017 11:30:28 -0500 Subject: [PATCH 1/3] provider/aws: Allow ARN identifier to be set Allows users from govcloud and other regions (aws-cn) to now use the following resources correctly: ``` - data "aws_billing_service_account" - data "aws_elb_service_account" - resource "aws_cloudfront_origin_access_identity" - resource "aws_ecs_service" - resource "aws_iam_saml_provider" - resource "aws_lambda_permission" - resource "aws_sns_topic_policy" ``` --- ...data_source_aws_billing_service_account.go | 6 +++-- ...source_aws_billing_service_account_test.go | 2 +- .../data_source_aws_elb_service_account.go | 6 ++--- ...ata_source_aws_elb_service_account_test.go | 4 +-- ...e_aws_cloudfront_origin_access_identity.go | 15 ++++++----- ..._cloudfront_origin_access_identity_test.go | 4 +-- .../providers/aws/resource_aws_ecs_service.go | 6 ++--- .../aws/resource_aws_iam_saml_provider.go | 14 +++++----- .../resource_aws_iam_saml_provider_test.go | 4 +-- .../aws/resource_aws_lambda_permission.go | 18 ++++++------- .../resource_aws_lambda_permission_test.go | 26 ++++++++++++++----- .../aws/resource_aws_sns_topic_policy.go | 7 ++--- .../aws/resource_aws_sns_topic_policy_test.go | 2 +- builtin/providers/aws/validators.go | 4 +-- builtin/providers/aws/validators_test.go | 2 ++ 15 files changed, 69 insertions(+), 51 deletions(-) diff --git a/builtin/providers/aws/data_source_aws_billing_service_account.go b/builtin/providers/aws/data_source_aws_billing_service_account.go index f5bfb8387..23ec40843 100644 --- a/builtin/providers/aws/data_source_aws_billing_service_account.go +++ b/builtin/providers/aws/data_source_aws_billing_service_account.go @@ -1,6 +1,8 @@ package aws import ( + "fmt" + "github.com/hashicorp/terraform/helper/schema" ) @@ -12,7 +14,7 @@ func dataSourceAwsBillingServiceAccount() *schema.Resource { Read: dataSourceAwsBillingServiceAccountRead, Schema: map[string]*schema.Schema{ - "arn": &schema.Schema{ + "arn": { Type: schema.TypeString, Computed: true, }, @@ -23,7 +25,7 @@ func dataSourceAwsBillingServiceAccount() *schema.Resource { func dataSourceAwsBillingServiceAccountRead(d *schema.ResourceData, meta interface{}) error { d.SetId(billingAccountId) - d.Set("arn", "arn:aws:iam::"+billingAccountId+":root") + d.Set("arn", fmt.Sprintf("arn:%s:iam::%s:root", meta.(*AWSClient).partition, billingAccountId)) return nil } diff --git a/builtin/providers/aws/data_source_aws_billing_service_account_test.go b/builtin/providers/aws/data_source_aws_billing_service_account_test.go index adfee84f8..53f9c2df8 100644 --- a/builtin/providers/aws/data_source_aws_billing_service_account_test.go +++ b/builtin/providers/aws/data_source_aws_billing_service_account_test.go @@ -11,7 +11,7 @@ func TestAccAWSBillingServiceAccount_basic(t *testing.T) { PreCheck: func() { testAccPreCheck(t) }, Providers: testAccProviders, Steps: []resource.TestStep{ - resource.TestStep{ + { Config: testAccCheckAwsBillingServiceAccountConfig, Check: resource.ComposeTestCheckFunc( resource.TestCheckResourceAttr("data.aws_billing_service_account.main", "id", "386209384616"), diff --git a/builtin/providers/aws/data_source_aws_elb_service_account.go b/builtin/providers/aws/data_source_aws_elb_service_account.go index 0b103e9ca..a3d6cdd71 100644 --- a/builtin/providers/aws/data_source_aws_elb_service_account.go +++ b/builtin/providers/aws/data_source_aws_elb_service_account.go @@ -31,11 +31,11 @@ func dataSourceAwsElbServiceAccount() *schema.Resource { Read: dataSourceAwsElbServiceAccountRead, Schema: map[string]*schema.Schema{ - "region": &schema.Schema{ + "region": { Type: schema.TypeString, Optional: true, }, - "arn": &schema.Schema{ + "arn": { Type: schema.TypeString, Computed: true, }, @@ -52,7 +52,7 @@ func dataSourceAwsElbServiceAccountRead(d *schema.ResourceData, meta interface{} if accid, ok := elbAccountIdPerRegionMap[region]; ok { d.SetId(accid) - d.Set("arn", "arn:aws:iam::"+accid+":root") + d.Set("arn", fmt.Sprintf("arn:%s:iam::%s:root", meta.(*AWSClient).partition, accid)) return nil } diff --git a/builtin/providers/aws/data_source_aws_elb_service_account_test.go b/builtin/providers/aws/data_source_aws_elb_service_account_test.go index ef62e2b1d..551d7df46 100644 --- a/builtin/providers/aws/data_source_aws_elb_service_account_test.go +++ b/builtin/providers/aws/data_source_aws_elb_service_account_test.go @@ -11,14 +11,14 @@ func TestAccAWSElbServiceAccount_basic(t *testing.T) { PreCheck: func() { testAccPreCheck(t) }, Providers: testAccProviders, Steps: []resource.TestStep{ - resource.TestStep{ + { Config: testAccCheckAwsElbServiceAccountConfig, Check: resource.ComposeTestCheckFunc( resource.TestCheckResourceAttr("data.aws_elb_service_account.main", "id", "797873946194"), resource.TestCheckResourceAttr("data.aws_elb_service_account.main", "arn", "arn:aws:iam::797873946194:root"), ), }, - resource.TestStep{ + { Config: testAccCheckAwsElbServiceAccountExplicitRegionConfig, Check: resource.ComposeTestCheckFunc( resource.TestCheckResourceAttr("data.aws_elb_service_account.regional", "id", "156460612806"), diff --git a/builtin/providers/aws/resource_aws_cloudfront_origin_access_identity.go b/builtin/providers/aws/resource_aws_cloudfront_origin_access_identity.go index 094203b4d..2c4053741 100644 --- a/builtin/providers/aws/resource_aws_cloudfront_origin_access_identity.go +++ b/builtin/providers/aws/resource_aws_cloudfront_origin_access_identity.go @@ -20,28 +20,28 @@ func resourceAwsCloudFrontOriginAccessIdentity() *schema.Resource { }, Schema: map[string]*schema.Schema{ - "comment": &schema.Schema{ + "comment": { Type: schema.TypeString, Optional: true, Default: "", }, - "caller_reference": &schema.Schema{ + "caller_reference": { Type: schema.TypeString, Computed: true, }, - "cloudfront_access_identity_path": &schema.Schema{ + "cloudfront_access_identity_path": { Type: schema.TypeString, Computed: true, }, - "etag": &schema.Schema{ + "etag": { Type: schema.TypeString, Computed: true, }, - "iam_arn": &schema.Schema{ + "iam_arn": { Type: schema.TypeString, Computed: true, }, - "s3_canonical_user_id": &schema.Schema{ + "s3_canonical_user_id": { Type: schema.TypeString, Computed: true, }, @@ -81,7 +81,8 @@ func resourceAwsCloudFrontOriginAccessIdentityRead(d *schema.ResourceData, meta d.Set("etag", resp.ETag) d.Set("s3_canonical_user_id", resp.CloudFrontOriginAccessIdentity.S3CanonicalUserId) d.Set("cloudfront_access_identity_path", fmt.Sprintf("origin-access-identity/cloudfront/%s", *resp.CloudFrontOriginAccessIdentity.Id)) - d.Set("iam_arn", fmt.Sprintf("arn:aws:iam::cloudfront:user/CloudFront Origin Access Identity %s", *resp.CloudFrontOriginAccessIdentity.Id)) + d.Set("iam_arn", fmt.Sprintf("arn:%s:iam::cloudfront:user/CloudFront Origin Access Identity %s", + meta.(*AWSClient).partition, *resp.CloudFrontOriginAccessIdentity.Id)) return nil } diff --git a/builtin/providers/aws/resource_aws_cloudfront_origin_access_identity_test.go b/builtin/providers/aws/resource_aws_cloudfront_origin_access_identity_test.go index 518dda977..4377f264e 100644 --- a/builtin/providers/aws/resource_aws_cloudfront_origin_access_identity_test.go +++ b/builtin/providers/aws/resource_aws_cloudfront_origin_access_identity_test.go @@ -17,7 +17,7 @@ func TestAccAWSCloudFrontOriginAccessIdentity_basic(t *testing.T) { Providers: testAccProviders, CheckDestroy: testAccCheckCloudFrontOriginAccessIdentityDestroy, Steps: []resource.TestStep{ - resource.TestStep{ + { Config: testAccAWSCloudFrontOriginAccessIdentityConfig, Check: resource.ComposeTestCheckFunc( testAccCheckCloudFrontOriginAccessIdentityExistence("aws_cloudfront_origin_access_identity.origin_access_identity"), @@ -46,7 +46,7 @@ func TestAccAWSCloudFrontOriginAccessIdentity_noComment(t *testing.T) { Providers: testAccProviders, CheckDestroy: testAccCheckCloudFrontOriginAccessIdentityDestroy, Steps: []resource.TestStep{ - resource.TestStep{ + { Config: testAccAWSCloudFrontOriginAccessIdentityNoCommentConfig, Check: resource.ComposeTestCheckFunc( testAccCheckCloudFrontOriginAccessIdentityExistence("aws_cloudfront_origin_access_identity.origin_access_identity"), diff --git a/builtin/providers/aws/resource_aws_ecs_service.go b/builtin/providers/aws/resource_aws_ecs_service.go index 143d5fdb9..cac5888d8 100644 --- a/builtin/providers/aws/resource_aws_ecs_service.go +++ b/builtin/providers/aws/resource_aws_ecs_service.go @@ -282,7 +282,7 @@ func resourceAwsEcsServiceRead(d *schema.ResourceData, meta interface{}) error { d.Set("name", service.ServiceName) // Save task definition in the same format - if strings.HasPrefix(d.Get("task_definition").(string), "arn:aws:ecs:") { + if regexp.MustCompile(`^arn:[\w-]+:ecs:`).MatchString(d.Get("task_definition").(string)) { d.Set("task_definition", service.TaskDefinition) } else { taskDefinition := buildFamilyAndRevisionFromARN(*service.TaskDefinition) @@ -292,7 +292,7 @@ func resourceAwsEcsServiceRead(d *schema.ResourceData, meta interface{}) error { d.Set("desired_count", service.DesiredCount) // Save cluster in the same format - if strings.HasPrefix(d.Get("cluster").(string), "arn:aws:ecs:") { + if regexp.MustCompile(`^arn:[\w-]+:ecs:`).MatchString(d.Get("cluster").(string)) { d.Set("cluster", service.ClusterArn) } else { clusterARN := getNameFromARN(*service.ClusterArn) @@ -301,7 +301,7 @@ func resourceAwsEcsServiceRead(d *schema.ResourceData, meta interface{}) error { // Save IAM role in the same format if service.RoleArn != nil { - if strings.HasPrefix(d.Get("iam_role").(string), "arn:aws:iam:") { + if regexp.MustCompile(`^arn:[\w-]+:iam:`).MatchString(d.Get("iam_role").(string)) { d.Set("iam_role", service.RoleArn) } else { roleARN := getNameFromARN(*service.RoleArn) diff --git a/builtin/providers/aws/resource_aws_iam_saml_provider.go b/builtin/providers/aws/resource_aws_iam_saml_provider.go index da85e54e9..f38e832d1 100644 --- a/builtin/providers/aws/resource_aws_iam_saml_provider.go +++ b/builtin/providers/aws/resource_aws_iam_saml_provider.go @@ -23,20 +23,20 @@ func resourceAwsIamSamlProvider() *schema.Resource { }, Schema: map[string]*schema.Schema{ - "arn": &schema.Schema{ + "arn": { Type: schema.TypeString, Computed: true, }, - "valid_until": &schema.Schema{ + "valid_until": { Type: schema.TypeString, Computed: true, }, - "name": &schema.Schema{ + "name": { Type: schema.TypeString, Required: true, ForceNew: true, }, - "saml_metadata_document": &schema.Schema{ + "saml_metadata_document": { Type: schema.TypeString, Required: true, }, @@ -75,7 +75,7 @@ func resourceAwsIamSamlProviderRead(d *schema.ResourceData, meta interface{}) er validUntil := out.ValidUntil.Format(time.RFC1123) d.Set("arn", d.Id()) - name, err := extractNameFromIAMSamlProviderArn(d.Id()) + name, err := extractNameFromIAMSamlProviderArn(d.Id(), meta.(*AWSClient).partition) if err != nil { return err } @@ -112,9 +112,9 @@ func resourceAwsIamSamlProviderDelete(d *schema.ResourceData, meta interface{}) return err } -func extractNameFromIAMSamlProviderArn(arn string) (string, error) { +func extractNameFromIAMSamlProviderArn(arn, partition string) (string, error) { // arn:aws:iam::123456789012:saml-provider/tf-salesforce-test - r := regexp.MustCompile("^arn:aws:iam::[0-9]{12}:saml-provider/(.+)$") + r := regexp.MustCompile(fmt.Sprintf("^arn:%s:iam::[0-9]{12}:saml-provider/(.+)$", partition)) submatches := r.FindStringSubmatch(arn) if len(submatches) != 2 { return "", fmt.Errorf("Unable to extract name from a given ARN: %q", arn) diff --git a/builtin/providers/aws/resource_aws_iam_saml_provider_test.go b/builtin/providers/aws/resource_aws_iam_saml_provider_test.go index 4118a062a..150bb6eef 100644 --- a/builtin/providers/aws/resource_aws_iam_saml_provider_test.go +++ b/builtin/providers/aws/resource_aws_iam_saml_provider_test.go @@ -17,13 +17,13 @@ func TestAccAWSIAMSamlProvider_basic(t *testing.T) { Providers: testAccProviders, CheckDestroy: testAccCheckIAMSamlProviderDestroy, Steps: []resource.TestStep{ - resource.TestStep{ + { Config: testAccIAMSamlProviderConfig, Check: resource.ComposeTestCheckFunc( testAccCheckIAMSamlProvider("aws_iam_saml_provider.salesforce"), ), }, - resource.TestStep{ + { Config: testAccIAMSamlProviderConfigUpdate, Check: resource.ComposeTestCheckFunc( testAccCheckIAMSamlProvider("aws_iam_saml_provider.salesforce"), diff --git a/builtin/providers/aws/resource_aws_lambda_permission.go b/builtin/providers/aws/resource_aws_lambda_permission.go index f2b9a3941..625c149f9 100644 --- a/builtin/providers/aws/resource_aws_lambda_permission.go +++ b/builtin/providers/aws/resource_aws_lambda_permission.go @@ -15,7 +15,7 @@ import ( "github.com/hashicorp/terraform/helper/schema" ) -var LambdaFunctionRegexp = `^(arn:aws:lambda:)?([a-z]{2}-[a-z]+-\d{1}:)?(\d{12}:)?(function:)?([a-zA-Z0-9-_]+)(:(\$LATEST|[a-zA-Z0-9-_]+))?$` +var LambdaFunctionRegexp = `^(arn:[\w-]+:lambda:)?([a-z]{2}-[a-z]+-\d{1}:)?(\d{12}:)?(function:)?([a-zA-Z0-9-_]+)(:(\$LATEST|[a-zA-Z0-9-_]+))?$` func resourceAwsLambdaPermission() *schema.Resource { return &schema.Resource{ @@ -24,42 +24,42 @@ func resourceAwsLambdaPermission() *schema.Resource { Delete: resourceAwsLambdaPermissionDelete, Schema: map[string]*schema.Schema{ - "action": &schema.Schema{ + "action": { Type: schema.TypeString, Required: true, ForceNew: true, ValidateFunc: validateLambdaPermissionAction, }, - "function_name": &schema.Schema{ + "function_name": { Type: schema.TypeString, Required: true, ForceNew: true, ValidateFunc: validateLambdaFunctionName, }, - "principal": &schema.Schema{ + "principal": { Type: schema.TypeString, Required: true, ForceNew: true, }, - "qualifier": &schema.Schema{ + "qualifier": { Type: schema.TypeString, Optional: true, ForceNew: true, ValidateFunc: validateLambdaQualifier, }, - "source_account": &schema.Schema{ + "source_account": { Type: schema.TypeString, Optional: true, ForceNew: true, ValidateFunc: validateAwsAccountId, }, - "source_arn": &schema.Schema{ + "source_arn": { Type: schema.TypeString, Optional: true, ForceNew: true, ValidateFunc: validateArn, }, - "statement_id": &schema.Schema{ + "statement_id": { Type: schema.TypeString, Required: true, ForceNew: true, @@ -216,7 +216,7 @@ func resourceAwsLambdaPermissionRead(d *schema.ResourceData, meta interface{}) e } // Save Lambda function name in the same format - if strings.HasPrefix(d.Get("function_name").(string), "arn:aws:lambda:") { + if regexp.MustCompile(`^arn:[\w-]+:lambda:`).MatchString(d.Get("function_name").(string)) { // Strip qualifier off trimmedArn := strings.TrimSuffix(statement.Resource, ":"+qualifier) d.Set("function_name", trimmedArn) diff --git a/builtin/providers/aws/resource_aws_lambda_permission_test.go b/builtin/providers/aws/resource_aws_lambda_permission_test.go index b3860d665..f443959e7 100644 --- a/builtin/providers/aws/resource_aws_lambda_permission_test.go +++ b/builtin/providers/aws/resource_aws_lambda_permission_test.go @@ -63,6 +63,18 @@ func TestLambdaPermissionGetQualifierFromLambdaAliasOrVersionArn_alias(t *testin } } +func TestLambdaPermissionGetQualifierFromLambdaAliasOrVersionArn_govcloud(t *testing.T) { + arnWithAlias := "arn:aws-us-gov:lambda:us-west-2:187636751137:function:lambda_function_name:testalias" + expectedQualifier := "testalias" + qualifier, err := getQualifierFromLambdaAliasOrVersionArn(arnWithAlias) + if err != nil { + t.Fatalf("Expected no error when getting qualifier: %s", err) + } + if qualifier != expectedQualifier { + t.Fatalf("Expected qualifier to match (%q != %q)", qualifier, expectedQualifier) + } +} + func TestLambdaPermissionGetQualifierFromLambdaAliasOrVersionArn_version(t *testing.T) { arnWithVersion := "arn:aws:lambda:us-west-2:187636751137:function:lambda_function_name:223" expectedQualifier := "223" @@ -141,7 +153,7 @@ func TestAccAWSLambdaPermission_basic(t *testing.T) { Providers: testAccProviders, CheckDestroy: testAccCheckAWSLambdaPermissionDestroy, Steps: []resource.TestStep{ - resource.TestStep{ + { Config: testAccAWSLambdaPermissionConfig, Check: resource.ComposeTestCheckFunc( testAccCheckLambdaPermissionExists("aws_lambda_permission.allow_cloudwatch", &statement), @@ -165,7 +177,7 @@ func TestAccAWSLambdaPermission_withRawFunctionName(t *testing.T) { Providers: testAccProviders, CheckDestroy: testAccCheckAWSLambdaPermissionDestroy, Steps: []resource.TestStep{ - resource.TestStep{ + { Config: testAccAWSLambdaPermissionConfig_withRawFunctionName, Check: resource.ComposeTestCheckFunc( testAccCheckLambdaPermissionExists("aws_lambda_permission.with_raw_func_name", &statement), @@ -188,7 +200,7 @@ func TestAccAWSLambdaPermission_withQualifier(t *testing.T) { Providers: testAccProviders, CheckDestroy: testAccCheckAWSLambdaPermissionDestroy, Steps: []resource.TestStep{ - resource.TestStep{ + { Config: testAccAWSLambdaPermissionConfig_withQualifier, Check: resource.ComposeTestCheckFunc( testAccCheckLambdaPermissionExists("aws_lambda_permission.with_qualifier", &statement), @@ -217,7 +229,7 @@ func TestAccAWSLambdaPermission_multiplePerms(t *testing.T) { Providers: testAccProviders, CheckDestroy: testAccCheckAWSLambdaPermissionDestroy, Steps: []resource.TestStep{ - resource.TestStep{ + { Config: testAccAWSLambdaPermissionConfig_multiplePerms, Check: resource.ComposeTestCheckFunc( // 1st @@ -236,7 +248,7 @@ func TestAccAWSLambdaPermission_multiplePerms(t *testing.T) { regexp.MustCompile(":function:lambda_function_name_perm_multiperms$")), ), }, - resource.TestStep{ + { Config: testAccAWSLambdaPermissionConfig_multiplePermsModified, Check: resource.ComposeTestCheckFunc( // 1st @@ -277,7 +289,7 @@ func TestAccAWSLambdaPermission_withS3(t *testing.T) { Providers: testAccProviders, CheckDestroy: testAccCheckAWSLambdaPermissionDestroy, Steps: []resource.TestStep{ - resource.TestStep{ + { Config: fmt.Sprintf(testAccAWSLambdaPermissionConfig_withS3_tpl, rInt), Check: resource.ComposeTestCheckFunc( testAccCheckLambdaPermissionExists("aws_lambda_permission.with_s3", &statement), @@ -303,7 +315,7 @@ func TestAccAWSLambdaPermission_withSNS(t *testing.T) { Providers: testAccProviders, CheckDestroy: testAccCheckAWSLambdaPermissionDestroy, Steps: []resource.TestStep{ - resource.TestStep{ + { Config: testAccAWSLambdaPermissionConfig_withSNS, Check: resource.ComposeTestCheckFunc( testAccCheckLambdaPermissionExists("aws_lambda_permission.with_sns", &statement), diff --git a/builtin/providers/aws/resource_aws_sns_topic_policy.go b/builtin/providers/aws/resource_aws_sns_topic_policy.go index 1a831e453..288a9a449 100644 --- a/builtin/providers/aws/resource_aws_sns_topic_policy.go +++ b/builtin/providers/aws/resource_aws_sns_topic_policy.go @@ -102,7 +102,7 @@ func resourceAwsSnsTopicPolicyRead(d *schema.ResourceData, meta interface{}) err } func resourceAwsSnsTopicPolicyDelete(d *schema.ResourceData, meta interface{}) error { - accountId, err := getAccountIdFromSnsTopicArn(d.Id()) + accountId, err := getAccountIdFromSnsTopicArn(d.Id(), meta.(*AWSClient).partition) if err != nil { return err } @@ -134,9 +134,10 @@ func resourceAwsSnsTopicPolicyDelete(d *schema.ResourceData, meta interface{}) e return nil } -func getAccountIdFromSnsTopicArn(arn string) (string, error) { +func getAccountIdFromSnsTopicArn(arn, partition string) (string, error) { // arn:aws:sns:us-west-2:123456789012:test-new - re := regexp.MustCompile("^arn:aws:sns:[^:]+:([0-9]{12}):.+") + // arn:aws-us-gov:sns:us-west-2:123456789012:test-new + re := regexp.MustCompile(fmt.Sprintf("^arn:%s:sns:[^:]+:([0-9]{12}):.+", partition)) matches := re.FindStringSubmatch(arn) if len(matches) != 2 { return "", fmt.Errorf("Unable to get account ID from ARN (%q)", arn) diff --git a/builtin/providers/aws/resource_aws_sns_topic_policy_test.go b/builtin/providers/aws/resource_aws_sns_topic_policy_test.go index e911f97c3..4aae9645b 100644 --- a/builtin/providers/aws/resource_aws_sns_topic_policy_test.go +++ b/builtin/providers/aws/resource_aws_sns_topic_policy_test.go @@ -13,7 +13,7 @@ func TestAccAWSSNSTopicPolicy_basic(t *testing.T) { Providers: testAccProviders, CheckDestroy: testAccCheckAWSSNSTopicDestroy, Steps: []resource.TestStep{ - resource.TestStep{ + { Config: testAccAWSSNSTopicConfig_withPolicy, Check: resource.ComposeTestCheckFunc( testAccCheckAWSSNSTopicExists("aws_sns_topic.test"), diff --git a/builtin/providers/aws/validators.go b/builtin/providers/aws/validators.go index 0cc5f0817..499a9ee2b 100644 --- a/builtin/providers/aws/validators.go +++ b/builtin/providers/aws/validators.go @@ -234,7 +234,7 @@ func validateLambdaFunctionName(v interface{}, k string) (ws []string, errors [] "%q cannot be longer than 140 characters: %q", k, value)) } // http://docs.aws.amazon.com/lambda/latest/dg/API_AddPermission.html - pattern := `^(arn:aws:lambda:)?([a-z]{2}-[a-z]+-\d{1}:)?(\d{12}:)?(function:)?([a-zA-Z0-9-_]+)(:(\$LATEST|[a-zA-Z0-9-_]+))?$` + pattern := `^(arn:[\w-]+:lambda:)?([a-z]{2}-[a-z]+-\d{1}:)?(\d{12}:)?(function:)?([a-zA-Z0-9-_]+)(:(\$LATEST|[a-zA-Z0-9-_]+))?$` if !regexp.MustCompile(pattern).MatchString(value) { errors = append(errors, fmt.Errorf( "%q doesn't comply with restrictions (%q): %q", @@ -297,7 +297,7 @@ func validateArn(v interface{}, k string) (ws []string, errors []error) { } // http://docs.aws.amazon.com/lambda/latest/dg/API_AddPermission.html - pattern := `^arn:aws:([a-zA-Z0-9\-])+:([a-z]{2}-[a-z]+-\d{1})?:(\d{12})?:(.*)$` + pattern := `^arn:[\w-]+:([a-zA-Z0-9\-])+:([a-z]{2}-[a-z]+-\d{1})?:(\d{12})?:(.*)$` if !regexp.MustCompile(pattern).MatchString(value) { errors = append(errors, fmt.Errorf( "%q doesn't look like a valid ARN (%q): %q", diff --git a/builtin/providers/aws/validators_test.go b/builtin/providers/aws/validators_test.go index 309cca23a..e16391c15 100644 --- a/builtin/providers/aws/validators_test.go +++ b/builtin/providers/aws/validators_test.go @@ -78,6 +78,7 @@ func TestValidateCloudWatchEventRuleName(t *testing.T) { func TestValidateLambdaFunctionName(t *testing.T) { validNames := []string{ "arn:aws:lambda:us-west-2:123456789012:function:ThumbNail", + "arn:aws-us-gov:lambda:us-west-2:123456789012:function:ThumbNail", "FunctionName", "function-name", } @@ -203,6 +204,7 @@ func TestValidateArn(t *testing.T) { "arn:aws:events:us-east-1:319201112229:rule/rule_name", // CloudWatch Rule "arn:aws:lambda:eu-west-1:319201112229:function:myCustomFunction", // Lambda function "arn:aws:lambda:eu-west-1:319201112229:function:myCustomFunction:Qualifier", // Lambda func qualifier + "arn:aws-us-gov:s3:::corp_bucket/object.png", // GovCloud ARN } for _, v := range validNames { _, errors := validateArn(v, "arn") From 763cfcdb1fc9eaa15e142825a2dac5cdb4531eb6 Mon Sep 17 00:00:00 2001 From: Jake Champlin Date: Mon, 23 Jan 2017 12:02:53 -0500 Subject: [PATCH 2/3] Use strings.HasPrefix instead of regexp for ecs_service --- builtin/providers/aws/resource_aws_ecs_service.go | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/builtin/providers/aws/resource_aws_ecs_service.go b/builtin/providers/aws/resource_aws_ecs_service.go index cac5888d8..a177eacf4 100644 --- a/builtin/providers/aws/resource_aws_ecs_service.go +++ b/builtin/providers/aws/resource_aws_ecs_service.go @@ -282,7 +282,7 @@ func resourceAwsEcsServiceRead(d *schema.ResourceData, meta interface{}) error { d.Set("name", service.ServiceName) // Save task definition in the same format - if regexp.MustCompile(`^arn:[\w-]+:ecs:`).MatchString(d.Get("task_definition").(string)) { + if strings.HasPrefix(d.Get("task_definition").(string), "arn:"+meta.(*AWSClient).partition+":ecs:") { d.Set("task_definition", service.TaskDefinition) } else { taskDefinition := buildFamilyAndRevisionFromARN(*service.TaskDefinition) @@ -292,7 +292,7 @@ func resourceAwsEcsServiceRead(d *schema.ResourceData, meta interface{}) error { d.Set("desired_count", service.DesiredCount) // Save cluster in the same format - if regexp.MustCompile(`^arn:[\w-]+:ecs:`).MatchString(d.Get("cluster").(string)) { + if strings.HasPrefix(d.Get("cluster").(string), "arn:"+meta.(*AWSClient).partition+":ecs:") { d.Set("cluster", service.ClusterArn) } else { clusterARN := getNameFromARN(*service.ClusterArn) @@ -301,7 +301,7 @@ func resourceAwsEcsServiceRead(d *schema.ResourceData, meta interface{}) error { // Save IAM role in the same format if service.RoleArn != nil { - if regexp.MustCompile(`^arn:[\w-]+:iam:`).MatchString(d.Get("iam_role").(string)) { + if strings.HasPrefix(d.Get("iam_role").(string), "arn:"+meta.(*AWSClient).partition+":iam:") { d.Set("iam_role", service.RoleArn) } else { roleARN := getNameFromARN(*service.RoleArn) From 8580f58063d02c81fbd24038b8701384fcbb7562 Mon Sep 17 00:00:00 2001 From: Jake Champlin Date: Mon, 23 Jan 2017 12:34:56 -0500 Subject: [PATCH 3/3] Use strings.HasPrefix instead of regexp for lambda_permission --- builtin/providers/aws/resource_aws_lambda_permission.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/builtin/providers/aws/resource_aws_lambda_permission.go b/builtin/providers/aws/resource_aws_lambda_permission.go index 625c149f9..dd21bf4eb 100644 --- a/builtin/providers/aws/resource_aws_lambda_permission.go +++ b/builtin/providers/aws/resource_aws_lambda_permission.go @@ -216,7 +216,7 @@ func resourceAwsLambdaPermissionRead(d *schema.ResourceData, meta interface{}) e } // Save Lambda function name in the same format - if regexp.MustCompile(`^arn:[\w-]+:lambda:`).MatchString(d.Get("function_name").(string)) { + if strings.HasPrefix(d.Get("function_name").(string), "arn:"+meta.(*AWSClient).partition+":lambda:") { // Strip qualifier off trimmedArn := strings.TrimSuffix(statement.Resource, ":"+qualifier) d.Set("function_name", trimmedArn)