Skip to content

Commit 02697a6

Browse files
AWS registration: Add support to set rtvd regions (#181)
1 parent 0ccbb6f commit 02697a6

File tree

10 files changed

+934
-119
lines changed

10 files changed

+934
-119
lines changed

docs/resources/cloud_aws_account.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -151,6 +151,7 @@ Optional:
151151
- `log_ingestion_s3_bucket_name` (String) S3 bucket name for CloudTrail log ingestion when log_ingestion_method is 's3'. Required when using S3 method
152152
- `log_ingestion_s3_bucket_prefix` (String) Optional S3 bucket prefix (a prefix used for filter log files with the prefix present in their key) for CloudTrail logs when log_ingestion_method is 's3'
153153
- `log_ingestion_sns_topic_arn` (String) SNS topic ARN for S3 CloudTrail log notifications when log_ingestion_method is 's3'. Required when using S3 method
154+
- `regions` (List of String) List of AWS regions for Real-Time Visibility and Detection. If not specified, defaults to all regions
154155
- `use_existing_cloudtrail` (Boolean) Set to true if a CloudTrail already exists
155156

156157

go.mod

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,9 @@
11
module github.com/crowdstrike/terraform-provider-crowdstrike
22

3-
go 1.24.0
3+
go 1.24.3
44

55
require (
6+
github.com/go-viper/mapstructure/v2 v2.4.0
67
github.com/crowdstrike/gofalcon v0.18.1-0.20251207000815-986a0b139e80
78
github.com/google/go-cmp v0.6.0
89
github.com/hashicorp/go-version v1.7.0

go.sum

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -80,6 +80,8 @@ github.com/go-openapi/validate v0.24.0 h1:LdfDKwNbpB6Vn40xhTdNZAnfLECL81w+VX3Bum
8080
github.com/go-openapi/validate v0.24.0/go.mod h1:iyeX1sEufmv3nPbBdX3ieNviWnOZaJ1+zquzJEf2BAQ=
8181
github.com/go-test/deep v1.0.3 h1:ZrJSEWsXzPOxaZnFteGEfooLba+ju3FYIbOrS+rQd68=
8282
github.com/go-test/deep v1.0.3/go.mod h1:wGDj63lr65AM2AQyKZd/NYHGb0R+1RLqB8NKt3aSFNA=
83+
github.com/go-viper/mapstructure/v2 v2.4.0 h1:EBsztssimR/CONLSZZ04E8qAkxNYq4Qp9LvH92wZUgs=
84+
github.com/go-viper/mapstructure/v2 v2.4.0/go.mod h1:oJDH3BJKyqBA2TXFhDsKDGDTlndYOZ6rGS0BRZIxGhM=
8385
github.com/golang/groupcache v0.0.0-20210331224755-41bb18bfe9da h1:oI5xCqsCo564l8iNU+DwB5epxmsaqB+rhGL0m5jtYqE=
8486
github.com/golang/groupcache v0.0.0-20210331224755-41bb18bfe9da/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc=
8587
github.com/golang/protobuf v1.1.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=

internal/fcs/aws_regions.go

Lines changed: 129 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,129 @@
1+
package fcs
2+
3+
import (
4+
"context"
5+
"fmt"
6+
"regexp"
7+
8+
"github.com/hashicorp/terraform-plugin-framework/schema/validator"
9+
"github.com/hashicorp/terraform-plugin-framework/types"
10+
)
11+
12+
// AWS region regex patterns based on AWS SDK validation logic.
13+
var (
14+
// Commercial regions: (us|eu|ap|sa|ca|me|af|il|mx)-direction-number.
15+
CommercialRegionRegex = regexp.MustCompile(`^(us|eu|ap|sa|ca|me|af|il|mx)-\w+-[1-9]\d*$`)
16+
17+
// GovCloud regions: us-gov-direction-number.
18+
GovCloudRegionRegex = regexp.MustCompile(`^us-gov-\w+-[1-9]\d*$`)
19+
20+
// China regions: cn-direction-number.
21+
ChinaRegionRegex = regexp.MustCompile(`^cn-\w+-[1-9]\d*$`)
22+
23+
// ISO regions: us-iso/isob/isoe/isof-direction-number.
24+
ISORegionRegex = regexp.MustCompile(`^us-iso[bf]?-\w+-[1-9]\d*$`)
25+
26+
// European Sovereign Cloud: eusc-de-direction-number.
27+
EUSCRegionRegex = regexp.MustCompile(`^eusc-de-\w+-[1-9]\d*$`)
28+
)
29+
30+
// IsValidAWSRegion validates if a region string matches AWS region patterns.
31+
func IsValidAWSRegion(region string) bool {
32+
return CommercialRegionRegex.MatchString(region) ||
33+
GovCloudRegionRegex.MatchString(region) ||
34+
ChinaRegionRegex.MatchString(region) ||
35+
ISORegionRegex.MatchString(region) ||
36+
EUSCRegionRegex.MatchString(region)
37+
}
38+
39+
// AWSRegionValidator returns a validator that checks if strings match AWS region patterns.
40+
func AWSRegionValidator() validator.String {
41+
return &awsRegionValidator{}
42+
}
43+
44+
type awsRegionValidator struct{}
45+
46+
func (v *awsRegionValidator) Description(ctx context.Context) string {
47+
return "must be a valid AWS region (e.g., us-east-1, eu-west-1, us-gov-west-1)"
48+
}
49+
50+
func (v *awsRegionValidator) MarkdownDescription(ctx context.Context) string {
51+
return "must be a valid AWS region (e.g., `us-east-1`, `eu-west-1`, `us-gov-west-1`)"
52+
}
53+
54+
func (v *awsRegionValidator) ValidateString(ctx context.Context, req validator.StringRequest, resp *validator.StringResponse) {
55+
if req.ConfigValue.IsNull() || req.ConfigValue.IsUnknown() {
56+
return
57+
}
58+
59+
region := req.ConfigValue.ValueString()
60+
61+
if !IsValidAWSRegion(region) {
62+
resp.Diagnostics.AddAttributeError(
63+
req.Path,
64+
"Invalid AWS Region",
65+
fmt.Sprintf("'%s' is not a valid AWS region format. Must match AWS region naming conventions for commercial, GovCloud, China, ISO, or EUSC regions.", region),
66+
)
67+
}
68+
}
69+
70+
// AWSRegionsOrAllListValidator returns a validator that ensures the list contains either:
71+
// - A single element with value "all"
72+
// - One or more valid AWS regions.
73+
func AWSRegionsOrAllListValidator() validator.List {
74+
return &awsRegionsOrAllListValidator{}
75+
}
76+
77+
type awsRegionsOrAllListValidator struct{}
78+
79+
func (v *awsRegionsOrAllListValidator) Description(ctx context.Context) string {
80+
return "must be either a single element 'all' or a list of valid AWS regions"
81+
}
82+
83+
func (v *awsRegionsOrAllListValidator) MarkdownDescription(ctx context.Context) string {
84+
return "must be either a single element `all` or a list of valid AWS regions"
85+
}
86+
87+
func (v *awsRegionsOrAllListValidator) ValidateList(ctx context.Context, req validator.ListRequest, resp *validator.ListResponse) {
88+
if req.ConfigValue.IsNull() || req.ConfigValue.IsUnknown() {
89+
return
90+
}
91+
92+
var elements []types.String
93+
diags := req.ConfigValue.ElementsAs(ctx, &elements, false)
94+
if diags.HasError() {
95+
resp.Diagnostics.Append(diags...)
96+
return
97+
}
98+
99+
if len(elements) == 0 {
100+
return
101+
}
102+
103+
for i, element := range elements {
104+
if element.IsNull() || element.IsUnknown() {
105+
continue
106+
}
107+
108+
region := element.ValueString()
109+
if region == "all" {
110+
if len(elements) == 1 {
111+
return
112+
}
113+
resp.Diagnostics.AddAttributeError(
114+
req.Path,
115+
"Invalid Region Configuration",
116+
"When using 'all', it must be the only element in the list. Cannot mix 'all' with specific regions.",
117+
)
118+
return
119+
}
120+
121+
if !IsValidAWSRegion(region) {
122+
resp.Diagnostics.AddAttributeError(
123+
req.Path.AtListIndex(i),
124+
"Invalid AWS Region",
125+
fmt.Sprintf("'%s' is not a valid AWS region format. Must match AWS region naming conventions.", region),
126+
)
127+
}
128+
}
129+
}

0 commit comments

Comments
 (0)