github.com/skyscape-cloud-services/terraform@v0.9.2-0.20170609144644-7ece028a1747/builtin/providers/aws/validators.go (about) 1 package aws 2 3 import ( 4 "fmt" 5 "net" 6 "net/url" 7 "regexp" 8 "strings" 9 "time" 10 11 "github.com/aws/aws-sdk-go/service/apigateway" 12 "github.com/aws/aws-sdk-go/service/s3" 13 "github.com/hashicorp/terraform/helper/schema" 14 ) 15 16 func validateRdsIdentifier(v interface{}, k string) (ws []string, errors []error) { 17 value := v.(string) 18 if !regexp.MustCompile(`^[0-9a-z-]+$`).MatchString(value) { 19 errors = append(errors, fmt.Errorf( 20 "only lowercase alphanumeric characters and hyphens allowed in %q", k)) 21 } 22 if !regexp.MustCompile(`^[a-z]`).MatchString(value) { 23 errors = append(errors, fmt.Errorf( 24 "first character of %q must be a letter", k)) 25 } 26 if regexp.MustCompile(`--`).MatchString(value) { 27 errors = append(errors, fmt.Errorf( 28 "%q cannot contain two consecutive hyphens", k)) 29 } 30 if regexp.MustCompile(`-$`).MatchString(value) { 31 errors = append(errors, fmt.Errorf( 32 "%q cannot end with a hyphen", k)) 33 } 34 return 35 } 36 37 func validateRdsIdentifierPrefix(v interface{}, k string) (ws []string, errors []error) { 38 value := v.(string) 39 if !regexp.MustCompile(`^[0-9a-z-]+$`).MatchString(value) { 40 errors = append(errors, fmt.Errorf( 41 "only lowercase alphanumeric characters and hyphens allowed in %q", k)) 42 } 43 if !regexp.MustCompile(`^[a-z]`).MatchString(value) { 44 errors = append(errors, fmt.Errorf( 45 "first character of %q must be a letter", k)) 46 } 47 if regexp.MustCompile(`--`).MatchString(value) { 48 errors = append(errors, fmt.Errorf( 49 "%q cannot contain two consecutive hyphens", k)) 50 } 51 return 52 } 53 54 func validateElastiCacheClusterId(v interface{}, k string) (ws []string, errors []error) { 55 value := v.(string) 56 if (len(value) < 1) || (len(value) > 20) { 57 errors = append(errors, fmt.Errorf( 58 "%q (%q) must contain from 1 to 20 alphanumeric characters or hyphens", k, value)) 59 } 60 if !regexp.MustCompile(`^[0-9a-z-]+$`).MatchString(value) { 61 errors = append(errors, fmt.Errorf( 62 "only lowercase alphanumeric characters and hyphens allowed in %q (%q)", k, value)) 63 } 64 if !regexp.MustCompile(`^[a-z]`).MatchString(value) { 65 errors = append(errors, fmt.Errorf( 66 "first character of %q (%q) must be a letter", k, value)) 67 } 68 if regexp.MustCompile(`--`).MatchString(value) { 69 errors = append(errors, fmt.Errorf( 70 "%q (%q) cannot contain two consecutive hyphens", k, value)) 71 } 72 if regexp.MustCompile(`-$`).MatchString(value) { 73 errors = append(errors, fmt.Errorf( 74 "%q (%q) cannot end with a hyphen", k, value)) 75 } 76 return 77 } 78 79 func validateASGScheduleTimestamp(v interface{}, k string) (ws []string, errors []error) { 80 value := v.(string) 81 _, err := time.Parse(awsAutoscalingScheduleTimeLayout, value) 82 if err != nil { 83 errors = append(errors, fmt.Errorf( 84 "%q cannot be parsed as iso8601 Timestamp Format", value)) 85 } 86 87 return 88 } 89 90 // validateTagFilters confirms the "value" component of a tag filter is one of 91 // AWS's three allowed types. 92 func validateTagFilters(v interface{}, k string) (ws []string, errors []error) { 93 value := v.(string) 94 if value != "KEY_ONLY" && value != "VALUE_ONLY" && value != "KEY_AND_VALUE" { 95 errors = append(errors, fmt.Errorf( 96 "%q must be one of \"KEY_ONLY\", \"VALUE_ONLY\", or \"KEY_AND_VALUE\"", k)) 97 } 98 return 99 } 100 101 func validateDbParamGroupName(v interface{}, k string) (ws []string, errors []error) { 102 value := v.(string) 103 if !regexp.MustCompile(`^[0-9a-z-]+$`).MatchString(value) { 104 errors = append(errors, fmt.Errorf( 105 "only lowercase alphanumeric characters and hyphens allowed in %q", k)) 106 } 107 if !regexp.MustCompile(`^[a-z]`).MatchString(value) { 108 errors = append(errors, fmt.Errorf( 109 "first character of %q must be a letter", k)) 110 } 111 if regexp.MustCompile(`--`).MatchString(value) { 112 errors = append(errors, fmt.Errorf( 113 "%q cannot contain two consecutive hyphens", k)) 114 } 115 if regexp.MustCompile(`-$`).MatchString(value) { 116 errors = append(errors, fmt.Errorf( 117 "%q cannot end with a hyphen", k)) 118 } 119 if len(value) > 255 { 120 errors = append(errors, fmt.Errorf( 121 "%q cannot be greater than 255 characters", k)) 122 } 123 return 124 } 125 126 func validateDbParamGroupNamePrefix(v interface{}, k string) (ws []string, errors []error) { 127 value := v.(string) 128 if !regexp.MustCompile(`^[0-9a-z-]+$`).MatchString(value) { 129 errors = append(errors, fmt.Errorf( 130 "only lowercase alphanumeric characters and hyphens allowed in %q", k)) 131 } 132 if !regexp.MustCompile(`^[a-z]`).MatchString(value) { 133 errors = append(errors, fmt.Errorf( 134 "first character of %q must be a letter", k)) 135 } 136 if regexp.MustCompile(`--`).MatchString(value) { 137 errors = append(errors, fmt.Errorf( 138 "%q cannot contain two consecutive hyphens", k)) 139 } 140 if len(value) > 255 { 141 errors = append(errors, fmt.Errorf( 142 "%q cannot be greater than 226 characters", k)) 143 } 144 return 145 } 146 147 func validateStreamViewType(v interface{}, k string) (ws []string, errors []error) { 148 value := v.(string) 149 viewTypes := map[string]bool{ 150 "KEYS_ONLY": true, 151 "NEW_IMAGE": true, 152 "OLD_IMAGE": true, 153 "NEW_AND_OLD_IMAGES": true, 154 } 155 156 if !viewTypes[value] { 157 errors = append(errors, fmt.Errorf("%q must be a valid DynamoDB StreamViewType", k)) 158 } 159 return 160 } 161 162 func validateElbName(v interface{}, k string) (ws []string, errors []error) { 163 value := v.(string) 164 if len(value) == 0 { 165 return // short-circuit 166 } 167 if len(value) > 32 { 168 errors = append(errors, fmt.Errorf( 169 "%q cannot be longer than 32 characters: %q", k, value)) 170 } 171 if !regexp.MustCompile(`^[0-9A-Za-z-]+$`).MatchString(value) { 172 errors = append(errors, fmt.Errorf( 173 "only alphanumeric characters and hyphens allowed in %q: %q", 174 k, value)) 175 } 176 if regexp.MustCompile(`^-`).MatchString(value) { 177 errors = append(errors, fmt.Errorf( 178 "%q cannot begin with a hyphen: %q", k, value)) 179 } 180 if regexp.MustCompile(`-$`).MatchString(value) { 181 errors = append(errors, fmt.Errorf( 182 "%q cannot end with a hyphen: %q", k, value)) 183 } 184 return 185 } 186 187 func validateElbNamePrefix(v interface{}, k string) (ws []string, errors []error) { 188 value := v.(string) 189 if !regexp.MustCompile(`^[0-9A-Za-z-]+$`).MatchString(value) { 190 errors = append(errors, fmt.Errorf( 191 "only alphanumeric characters and hyphens allowed in %q: %q", 192 k, value)) 193 } 194 if len(value) > 6 { 195 errors = append(errors, fmt.Errorf( 196 "%q cannot be longer than 6 characters: %q", k, value)) 197 } 198 if regexp.MustCompile(`^-`).MatchString(value) { 199 errors = append(errors, fmt.Errorf( 200 "%q cannot begin with a hyphen: %q", k, value)) 201 } 202 return 203 } 204 205 func validateEcrRepositoryName(v interface{}, k string) (ws []string, errors []error) { 206 value := v.(string) 207 if len(value) < 2 { 208 errors = append(errors, fmt.Errorf( 209 "%q must be at least 2 characters long: %q", k, value)) 210 } 211 if len(value) > 256 { 212 errors = append(errors, fmt.Errorf( 213 "%q cannot be longer than 256 characters: %q", k, value)) 214 } 215 216 // http://docs.aws.amazon.com/AmazonECR/latest/APIReference/API_CreateRepository.html 217 pattern := `^(?:[a-z0-9]+(?:[._-][a-z0-9]+)*/)*[a-z0-9]+(?:[._-][a-z0-9]+)*$` 218 if !regexp.MustCompile(pattern).MatchString(value) { 219 errors = append(errors, fmt.Errorf( 220 "%q doesn't comply with restrictions (%q): %q", 221 k, pattern, value)) 222 } 223 224 return 225 } 226 227 func validateCloudWatchEventRuleName(v interface{}, k string) (ws []string, errors []error) { 228 value := v.(string) 229 if len(value) > 64 { 230 errors = append(errors, fmt.Errorf( 231 "%q cannot be longer than 64 characters: %q", k, value)) 232 } 233 234 // http://docs.aws.amazon.com/AmazonCloudWatchEvents/latest/APIReference/API_PutRule.html 235 pattern := `^[\.\-_A-Za-z0-9]+$` 236 if !regexp.MustCompile(pattern).MatchString(value) { 237 errors = append(errors, fmt.Errorf( 238 "%q doesn't comply with restrictions (%q): %q", 239 k, pattern, value)) 240 } 241 242 return 243 } 244 245 func validateMaxLength(length int) schema.SchemaValidateFunc { 246 return func(v interface{}, k string) (ws []string, errors []error) { 247 value := v.(string) 248 if len(value) > length { 249 errors = append(errors, fmt.Errorf( 250 "%q cannot be longer than %d characters: %q", k, length, value)) 251 } 252 return 253 } 254 } 255 256 func validateIntegerInRange(min, max int) schema.SchemaValidateFunc { 257 return func(v interface{}, k string) (ws []string, errors []error) { 258 value := v.(int) 259 if value < min { 260 errors = append(errors, fmt.Errorf( 261 "%q cannot be lower than %d: %d", k, min, value)) 262 } 263 if value > max { 264 errors = append(errors, fmt.Errorf( 265 "%q cannot be higher than %d: %d", k, max, value)) 266 } 267 return 268 } 269 } 270 271 func validateCloudWatchEventTargetId(v interface{}, k string) (ws []string, errors []error) { 272 value := v.(string) 273 if len(value) > 64 { 274 errors = append(errors, fmt.Errorf( 275 "%q cannot be longer than 64 characters: %q", k, value)) 276 } 277 278 // http://docs.aws.amazon.com/AmazonCloudWatchEvents/latest/APIReference/API_Target.html 279 pattern := `^[\.\-_A-Za-z0-9]+$` 280 if !regexp.MustCompile(pattern).MatchString(value) { 281 errors = append(errors, fmt.Errorf( 282 "%q doesn't comply with restrictions (%q): %q", 283 k, pattern, value)) 284 } 285 286 return 287 } 288 289 func validateLambdaFunctionName(v interface{}, k string) (ws []string, errors []error) { 290 value := v.(string) 291 if len(value) > 140 { 292 errors = append(errors, fmt.Errorf( 293 "%q cannot be longer than 140 characters: %q", k, value)) 294 } 295 // http://docs.aws.amazon.com/lambda/latest/dg/API_AddPermission.html 296 pattern := `^(arn:[\w-]+:lambda:)?([a-z]{2}-[a-z]+-\d{1}:)?(\d{12}:)?(function:)?([a-zA-Z0-9-_]+)(:(\$LATEST|[a-zA-Z0-9-_]+))?$` 297 if !regexp.MustCompile(pattern).MatchString(value) { 298 errors = append(errors, fmt.Errorf( 299 "%q doesn't comply with restrictions (%q): %q", 300 k, pattern, value)) 301 } 302 303 return 304 } 305 306 func validateLambdaQualifier(v interface{}, k string) (ws []string, errors []error) { 307 value := v.(string) 308 if len(value) > 128 { 309 errors = append(errors, fmt.Errorf( 310 "%q cannot be longer than 128 characters: %q", k, value)) 311 } 312 // http://docs.aws.amazon.com/lambda/latest/dg/API_AddPermission.html 313 pattern := `^[a-zA-Z0-9$_-]+$` 314 if !regexp.MustCompile(pattern).MatchString(value) { 315 errors = append(errors, fmt.Errorf( 316 "%q doesn't comply with restrictions (%q): %q", 317 k, pattern, value)) 318 } 319 320 return 321 } 322 323 func validateLambdaPermissionAction(v interface{}, k string) (ws []string, errors []error) { 324 value := v.(string) 325 326 // http://docs.aws.amazon.com/lambda/latest/dg/API_AddPermission.html 327 pattern := `^(lambda:[*]|lambda:[a-zA-Z]+|[*])$` 328 if !regexp.MustCompile(pattern).MatchString(value) { 329 errors = append(errors, fmt.Errorf( 330 "%q doesn't comply with restrictions (%q): %q", 331 k, pattern, value)) 332 } 333 334 return 335 } 336 337 func validateAwsAccountId(v interface{}, k string) (ws []string, errors []error) { 338 value := v.(string) 339 340 // http://docs.aws.amazon.com/lambda/latest/dg/API_AddPermission.html 341 pattern := `^\d{12}$` 342 if !regexp.MustCompile(pattern).MatchString(value) { 343 errors = append(errors, fmt.Errorf( 344 "%q doesn't look like AWS Account ID (exactly 12 digits): %q", 345 k, value)) 346 } 347 348 return 349 } 350 351 func validateArn(v interface{}, k string) (ws []string, errors []error) { 352 value := v.(string) 353 354 if value == "" { 355 return 356 } 357 358 // http://docs.aws.amazon.com/lambda/latest/dg/API_AddPermission.html 359 pattern := `^arn:[\w-]+:([a-zA-Z0-9\-])+:([a-z]{2}-(gov-)?[a-z]+-\d{1})?:(\d{12})?:(.*)$` 360 if !regexp.MustCompile(pattern).MatchString(value) { 361 errors = append(errors, fmt.Errorf( 362 "%q doesn't look like a valid ARN (%q): %q", 363 k, pattern, value)) 364 } 365 366 return 367 } 368 369 func validatePolicyStatementId(v interface{}, k string) (ws []string, errors []error) { 370 value := v.(string) 371 372 if len(value) > 100 { 373 errors = append(errors, fmt.Errorf( 374 "%q cannot be longer than 100 characters: %q", k, value)) 375 } 376 377 // http://docs.aws.amazon.com/lambda/latest/dg/API_AddPermission.html 378 pattern := `^[a-zA-Z0-9-_]+$` 379 if !regexp.MustCompile(pattern).MatchString(value) { 380 errors = append(errors, fmt.Errorf( 381 "%q doesn't look like a valid statement ID (%q): %q", 382 k, pattern, value)) 383 } 384 385 return 386 } 387 388 // validateCIDRNetworkAddress ensures that the string value is a valid CIDR that 389 // represents a network address - it adds an error otherwise 390 func validateCIDRNetworkAddress(v interface{}, k string) (ws []string, errors []error) { 391 value := v.(string) 392 _, ipnet, err := net.ParseCIDR(value) 393 if err != nil { 394 errors = append(errors, fmt.Errorf( 395 "%q must contain a valid CIDR, got error parsing: %s", k, err)) 396 return 397 } 398 399 if ipnet == nil || value != ipnet.String() { 400 errors = append(errors, fmt.Errorf( 401 "%q must contain a valid network CIDR, got %q", k, value)) 402 } 403 404 return 405 } 406 407 func validateHTTPMethod(v interface{}, k string) (ws []string, errors []error) { 408 value := v.(string) 409 410 validMethods := map[string]bool{ 411 "ANY": true, 412 "DELETE": true, 413 "GET": true, 414 "HEAD": true, 415 "OPTIONS": true, 416 "PATCH": true, 417 "POST": true, 418 "PUT": true, 419 } 420 421 if _, ok := validMethods[value]; !ok { 422 errors = append(errors, fmt.Errorf( 423 "%q contains an invalid method %q. Valid methods are either %q, %q, %q, %q, %q, %q, %q, or %q.", 424 k, value, "ANY", "DELETE", "GET", "HEAD", "OPTIONS", "PATCH", "POST", "PUT")) 425 } 426 return 427 } 428 429 func validateLogMetricFilterName(v interface{}, k string) (ws []string, errors []error) { 430 value := v.(string) 431 432 if len(value) > 512 { 433 errors = append(errors, fmt.Errorf( 434 "%q cannot be longer than 512 characters: %q", k, value)) 435 } 436 437 // http://docs.aws.amazon.com/AmazonCloudWatchLogs/latest/APIReference/API_PutMetricFilter.html 438 pattern := `^[^:*]+$` 439 if !regexp.MustCompile(pattern).MatchString(value) { 440 errors = append(errors, fmt.Errorf( 441 "%q isn't a valid log metric name (must not contain colon nor asterisk): %q", 442 k, value)) 443 } 444 445 return 446 } 447 448 func validateLogMetricFilterTransformationName(v interface{}, k string) (ws []string, errors []error) { 449 value := v.(string) 450 451 if len(value) > 255 { 452 errors = append(errors, fmt.Errorf( 453 "%q cannot be longer than 255 characters: %q", k, value)) 454 } 455 456 // http://docs.aws.amazon.com/AmazonCloudWatchLogs/latest/APIReference/API_MetricTransformation.html 457 pattern := `^[^:*$]*$` 458 if !regexp.MustCompile(pattern).MatchString(value) { 459 errors = append(errors, fmt.Errorf( 460 "%q isn't a valid log metric transformation name (must not contain"+ 461 " colon, asterisk nor dollar sign): %q", 462 k, value)) 463 } 464 465 return 466 } 467 468 func validateLogGroupName(v interface{}, k string) (ws []string, errors []error) { 469 value := v.(string) 470 471 if len(value) > 512 { 472 errors = append(errors, fmt.Errorf( 473 "%q cannot be longer than 512 characters: %q", k, value)) 474 } 475 476 // http://docs.aws.amazon.com/AmazonCloudWatchLogs/latest/APIReference/API_CreateLogGroup.html 477 pattern := `^[\.\-_/#A-Za-z0-9]+$` 478 if !regexp.MustCompile(pattern).MatchString(value) { 479 errors = append(errors, fmt.Errorf( 480 "%q isn't a valid log group name (alphanumeric characters, underscores,"+ 481 " hyphens, slashes, hash signs and dots are allowed): %q", 482 k, value)) 483 } 484 485 return 486 } 487 488 func validateLogGroupNamePrefix(v interface{}, k string) (ws []string, errors []error) { 489 value := v.(string) 490 491 if len(value) > 483 { 492 errors = append(errors, fmt.Errorf( 493 "%q cannot be longer than 483 characters: %q", k, value)) 494 } 495 496 // http://docs.aws.amazon.com/AmazonCloudWatchLogs/latest/APIReference/API_CreateLogGroup.html 497 pattern := `^[\.\-_/#A-Za-z0-9]+$` 498 if !regexp.MustCompile(pattern).MatchString(value) { 499 errors = append(errors, fmt.Errorf( 500 "%q isn't a valid log group name (alphanumeric characters, underscores,"+ 501 " hyphens, slashes, hash signs and dots are allowed): %q", 502 k, value)) 503 } 504 505 return 506 } 507 508 func validateS3BucketLifecycleTimestamp(v interface{}, k string) (ws []string, errors []error) { 509 value := v.(string) 510 _, err := time.Parse(time.RFC3339, fmt.Sprintf("%sT00:00:00Z", value)) 511 if err != nil { 512 errors = append(errors, fmt.Errorf( 513 "%q cannot be parsed as RFC3339 Timestamp Format", value)) 514 } 515 516 return 517 } 518 519 func validateS3BucketLifecycleStorageClass(v interface{}, k string) (ws []string, errors []error) { 520 value := v.(string) 521 if value != s3.TransitionStorageClassStandardIa && value != s3.TransitionStorageClassGlacier { 522 errors = append(errors, fmt.Errorf( 523 "%q must be one of '%q', '%q'", k, s3.TransitionStorageClassStandardIa, s3.TransitionStorageClassGlacier)) 524 } 525 526 return 527 } 528 529 func validateS3BucketReplicationRuleId(v interface{}, k string) (ws []string, errors []error) { 530 value := v.(string) 531 if len(value) > 255 { 532 errors = append(errors, fmt.Errorf( 533 "%q cannot be longer than 255 characters: %q", k, value)) 534 } 535 536 return 537 } 538 539 func validateS3BucketReplicationRulePrefix(v interface{}, k string) (ws []string, errors []error) { 540 value := v.(string) 541 if len(value) > 1024 { 542 errors = append(errors, fmt.Errorf( 543 "%q cannot be longer than 1024 characters: %q", k, value)) 544 } 545 546 return 547 } 548 549 func validateS3BucketReplicationDestinationStorageClass(v interface{}, k string) (ws []string, errors []error) { 550 value := v.(string) 551 if value != s3.StorageClassStandard && value != s3.StorageClassStandardIa && value != s3.StorageClassReducedRedundancy { 552 errors = append(errors, fmt.Errorf( 553 "%q must be one of '%q', '%q' or '%q'", k, s3.StorageClassStandard, s3.StorageClassStandardIa, s3.StorageClassReducedRedundancy)) 554 } 555 556 return 557 } 558 559 func validateS3BucketReplicationRuleStatus(v interface{}, k string) (ws []string, errors []error) { 560 value := v.(string) 561 if value != s3.ReplicationRuleStatusEnabled && value != s3.ReplicationRuleStatusDisabled { 562 errors = append(errors, fmt.Errorf( 563 "%q must be one of '%q' or '%q'", k, s3.ReplicationRuleStatusEnabled, s3.ReplicationRuleStatusDisabled)) 564 } 565 566 return 567 } 568 569 func validateS3BucketLifecycleRuleId(v interface{}, k string) (ws []string, errors []error) { 570 value := v.(string) 571 if len(value) > 255 { 572 errors = append(errors, fmt.Errorf( 573 "%q cannot exceed 255 characters", k)) 574 } 575 return 576 } 577 578 func validateDbEventSubscriptionName(v interface{}, k string) (ws []string, errors []error) { 579 value := v.(string) 580 if !regexp.MustCompile(`^[0-9A-Za-z-]+$`).MatchString(value) { 581 errors = append(errors, fmt.Errorf( 582 "only alphanumeric characters and hyphens allowed in %q", k)) 583 } 584 if len(value) > 255 { 585 errors = append(errors, fmt.Errorf( 586 "%q cannot be longer than 255 characters", k)) 587 } 588 return 589 } 590 591 func validateApiGatewayIntegrationPassthroughBehavior(v interface{}, k string) (ws []string, errors []error) { 592 value := v.(string) 593 if value != "WHEN_NO_MATCH" && value != "WHEN_NO_TEMPLATES" && value != "NEVER" { 594 errors = append(errors, fmt.Errorf( 595 "%q must be one of 'WHEN_NO_MATCH', 'WHEN_NO_TEMPLATES', 'NEVER'", k)) 596 } 597 return 598 } 599 600 func validateJsonString(v interface{}, k string) (ws []string, errors []error) { 601 if _, err := normalizeJsonString(v); err != nil { 602 errors = append(errors, fmt.Errorf("%q contains an invalid JSON: %s", k, err)) 603 } 604 return 605 } 606 607 func validateIAMPolicyJson(v interface{}, k string) (ws []string, errors []error) { 608 // IAM Policy documents need to be valid JSON, and pass legacy parsing 609 value := v.(string) 610 if len(value) < 1 { 611 errors = append(errors, fmt.Errorf("%q contains an invalid JSON policy", k)) 612 return 613 } 614 if value[:1] != "{" { 615 errors = append(errors, fmt.Errorf("%q contains an invalid JSON policy", k)) 616 return 617 } 618 if _, err := normalizeJsonString(v); err != nil { 619 errors = append(errors, fmt.Errorf("%q contains an invalid JSON: %s", k, err)) 620 } 621 return 622 } 623 624 func validateCloudFormationTemplate(v interface{}, k string) (ws []string, errors []error) { 625 if looksLikeJsonString(v) { 626 if _, err := normalizeJsonString(v); err != nil { 627 errors = append(errors, fmt.Errorf("%q contains an invalid JSON: %s", k, err)) 628 } 629 } else { 630 if _, err := checkYamlString(v); err != nil { 631 errors = append(errors, fmt.Errorf("%q contains an invalid YAML: %s", k, err)) 632 } 633 } 634 return 635 } 636 637 func validateApiGatewayIntegrationType(v interface{}, k string) (ws []string, errors []error) { 638 value := v.(string) 639 640 validTypes := map[string]bool{ 641 "AWS": true, 642 "AWS_PROXY": true, 643 "HTTP": true, 644 "HTTP_PROXY": true, 645 "MOCK": true, 646 } 647 648 if _, ok := validTypes[value]; !ok { 649 errors = append(errors, fmt.Errorf( 650 "%q contains an invalid integration type %q. Valid types are either %q, %q, %q, %q, or %q.", 651 k, value, "AWS", "AWS_PROXY", "HTTP", "HTTP_PROXY", "MOCK")) 652 } 653 return 654 } 655 656 func validateApiGatewayIntegrationContentHandling(v interface{}, k string) (ws []string, errors []error) { 657 value := v.(string) 658 659 validTypes := map[string]bool{ 660 "CONVERT_TO_BINARY": true, 661 "CONVERT_TO_TEXT": true, 662 } 663 664 if _, ok := validTypes[value]; !ok { 665 errors = append(errors, fmt.Errorf( 666 "%q contains an invalid integration type %q. Valid types are either %q or %q.", 667 k, value, "CONVERT_TO_BINARY", "CONVERT_TO_TEXT")) 668 } 669 return 670 } 671 672 func validateSQSQueueName(v interface{}, k string) (errors []error) { 673 value := v.(string) 674 if len(value) > 80 { 675 errors = append(errors, fmt.Errorf("%q cannot be longer than 80 characters", k)) 676 } 677 678 if !regexp.MustCompile(`^[0-9A-Za-z-_]+$`).MatchString(value) { 679 errors = append(errors, fmt.Errorf("only alphanumeric characters and hyphens allowed in %q", k)) 680 } 681 return 682 } 683 684 func validateSQSFifoQueueName(v interface{}, k string) (errors []error) { 685 value := v.(string) 686 687 if len(value) > 80 { 688 errors = append(errors, fmt.Errorf("%q cannot be longer than 80 characters", k)) 689 } 690 691 if !regexp.MustCompile(`^[0-9A-Za-z-_.]+$`).MatchString(value) { 692 errors = append(errors, fmt.Errorf("only alphanumeric characters and hyphens allowed in %q", k)) 693 } 694 695 if regexp.MustCompile(`^[^a-zA-Z0-9-_]`).MatchString(value) { 696 errors = append(errors, fmt.Errorf("FIFO queue name must start with one of these characters [a-zA-Z0-9-_]: %v", value)) 697 } 698 699 if !regexp.MustCompile(`\.fifo$`).MatchString(value) { 700 errors = append(errors, fmt.Errorf("FIFO queue name should ends with \".fifo\": %v", value)) 701 } 702 703 return 704 } 705 706 func validateSNSSubscriptionProtocol(v interface{}, k string) (ws []string, errors []error) { 707 value := strings.ToLower(v.(string)) 708 forbidden := []string{"email", "sms"} 709 for _, f := range forbidden { 710 if strings.Contains(value, f) { 711 errors = append( 712 errors, 713 fmt.Errorf("Unsupported protocol (%s) for SNS Topic", value), 714 ) 715 } 716 } 717 return 718 } 719 720 func validateSecurityRuleType(v interface{}, k string) (ws []string, errors []error) { 721 value := strings.ToLower(v.(string)) 722 723 validTypes := map[string]bool{ 724 "ingress": true, 725 "egress": true, 726 } 727 728 if _, ok := validTypes[value]; !ok { 729 errors = append(errors, fmt.Errorf( 730 "%q contains an invalid Security Group Rule type %q. Valid types are either %q or %q.", 731 k, value, "ingress", "egress")) 732 } 733 return 734 } 735 736 func validateOnceAWeekWindowFormat(v interface{}, k string) (ws []string, errors []error) { 737 // valid time format is "ddd:hh24:mi" 738 validTimeFormat := "(sun|mon|tue|wed|thu|fri|sat):([0-1][0-9]|2[0-3]):([0-5][0-9])" 739 validTimeFormatConsolidated := "^(" + validTimeFormat + "-" + validTimeFormat + "|)$" 740 741 value := strings.ToLower(v.(string)) 742 if !regexp.MustCompile(validTimeFormatConsolidated).MatchString(value) { 743 errors = append(errors, fmt.Errorf( 744 "%q must satisfy the format of \"ddd:hh24:mi-ddd:hh24:mi\".", k)) 745 } 746 return 747 } 748 749 func validateOnceADayWindowFormat(v interface{}, k string) (ws []string, errors []error) { 750 // valid time format is "hh24:mi" 751 validTimeFormat := "([0-1][0-9]|2[0-3]):([0-5][0-9])" 752 validTimeFormatConsolidated := "^(" + validTimeFormat + "-" + validTimeFormat + "|)$" 753 754 value := v.(string) 755 if !regexp.MustCompile(validTimeFormatConsolidated).MatchString(value) { 756 errors = append(errors, fmt.Errorf( 757 "%q must satisfy the format of \"hh24:mi-hh24:mi\".", k)) 758 } 759 return 760 } 761 762 func validateRoute53RecordType(v interface{}, k string) (ws []string, errors []error) { 763 // Valid Record types 764 // SOA, A, TXT, NS, CNAME, MX, NAPTR, PTR, SRV, SPF, AAAA 765 validTypes := map[string]struct{}{ 766 "SOA": {}, 767 "A": {}, 768 "TXT": {}, 769 "NS": {}, 770 "CNAME": {}, 771 "MX": {}, 772 "NAPTR": {}, 773 "PTR": {}, 774 "SRV": {}, 775 "SPF": {}, 776 "AAAA": {}, 777 } 778 779 value := v.(string) 780 if _, ok := validTypes[value]; !ok { 781 errors = append(errors, fmt.Errorf( 782 "%q must be one of [SOA, A, TXT, NS, CNAME, MX, NAPTR, PTR, SRV, SPF, AAAA]", k)) 783 } 784 return 785 } 786 787 // Validates that ECS Placement Constraints are set correctly 788 // Takes type, and expression as strings 789 func validateAwsEcsPlacementConstraint(constType, constExpr string) error { 790 switch constType { 791 case "distinctInstance": 792 // Expression can be nil for distinctInstance 793 return nil 794 case "memberOf": 795 if constExpr == "" { 796 return fmt.Errorf("Expression cannot be nil for 'memberOf' type") 797 } 798 default: 799 return fmt.Errorf("Unknown type provided: %q", constType) 800 } 801 return nil 802 } 803 804 // Validates that an Ecs placement strategy is set correctly 805 // Takes type, and field as strings 806 func validateAwsEcsPlacementStrategy(stratType, stratField string) error { 807 switch stratType { 808 case "random": 809 // random does not need the field attribute set, could error, but it isn't read at the API level 810 return nil 811 case "spread": 812 // For the spread placement strategy, valid values are instanceId 813 // (or host, which has the same effect), or any platform or custom attribute 814 // that is applied to a container instance 815 // stratField is already cased to a string 816 return nil 817 case "binpack": 818 if stratField != "cpu" && stratField != "memory" { 819 return fmt.Errorf("Binpack type requires the field attribute to be either 'cpu' or 'memory'. Got: %s", 820 stratField) 821 } 822 default: 823 return fmt.Errorf("Unknown type %s. Must be one of 'random', 'spread', or 'binpack'.", stratType) 824 } 825 return nil 826 } 827 828 func validateAwsEmrEbsVolumeType(v interface{}, k string) (ws []string, errors []error) { 829 validTypes := map[string]struct{}{ 830 "gp2": {}, 831 "io1": {}, 832 "standard": {}, 833 } 834 835 value := v.(string) 836 837 if _, ok := validTypes[value]; !ok { 838 errors = append(errors, fmt.Errorf( 839 "%q must be one of ['gp2', 'io1', 'standard']", k)) 840 } 841 return 842 } 843 844 func validateSfnActivityName(v interface{}, k string) (ws []string, errors []error) { 845 value := v.(string) 846 if len(value) > 80 { 847 errors = append(errors, fmt.Errorf("%q cannot be longer than 80 characters", k)) 848 } 849 850 return 851 } 852 853 func validateSfnStateMachineDefinition(v interface{}, k string) (ws []string, errors []error) { 854 value := v.(string) 855 if len(value) > 1048576 { 856 errors = append(errors, fmt.Errorf("%q cannot be longer than 1048576 characters", k)) 857 } 858 return 859 } 860 861 func validateSfnStateMachineName(v interface{}, k string) (ws []string, errors []error) { 862 value := v.(string) 863 if len(value) > 80 { 864 errors = append(errors, fmt.Errorf("%q cannot be longer than 80 characters", k)) 865 } 866 867 if !regexp.MustCompile(`^[a-zA-Z0-9-_]+$`).MatchString(value) { 868 errors = append(errors, fmt.Errorf( 869 "%q must be composed with only these characters [a-zA-Z0-9-_]: %v", k, value)) 870 } 871 return 872 } 873 874 func validateDmsCertificateId(v interface{}, k string) (ws []string, es []error) { 875 val := v.(string) 876 877 if len(val) > 255 { 878 es = append(es, fmt.Errorf("%q must not be longer than 255 characters", k)) 879 } 880 if !regexp.MustCompile("^[a-zA-Z][a-zA-Z0-9-]+$").MatchString(val) { 881 es = append(es, fmt.Errorf("%q must start with a letter, only contain alphanumeric characters and hyphens", k)) 882 } 883 if strings.Contains(val, "--") { 884 es = append(es, fmt.Errorf("%q must not contain consecutive hyphens", k)) 885 } 886 if strings.HasSuffix(val, "-") { 887 es = append(es, fmt.Errorf("%q must not end in a hyphen", k)) 888 } 889 890 return 891 } 892 893 func validateDmsEndpointId(v interface{}, k string) (ws []string, es []error) { 894 val := v.(string) 895 896 if len(val) > 255 { 897 es = append(es, fmt.Errorf("%q must not be longer than 255 characters", k)) 898 } 899 if !regexp.MustCompile("^[a-zA-Z][a-zA-Z0-9-]+$").MatchString(val) { 900 es = append(es, fmt.Errorf("%q must start with a letter, only contain alphanumeric characters and hyphens", k)) 901 } 902 if strings.Contains(val, "--") { 903 es = append(es, fmt.Errorf("%q must not contain consecutive hyphens", k)) 904 } 905 if strings.HasSuffix(val, "-") { 906 es = append(es, fmt.Errorf("%q must not end in a hyphen", k)) 907 } 908 909 return 910 } 911 912 func validateDmsReplicationInstanceId(v interface{}, k string) (ws []string, es []error) { 913 val := v.(string) 914 915 if len(val) > 63 { 916 es = append(es, fmt.Errorf("%q must not be longer than 63 characters", k)) 917 } 918 if !regexp.MustCompile("^[a-zA-Z][a-zA-Z0-9-]+$").MatchString(val) { 919 es = append(es, fmt.Errorf("%q must start with a letter, only contain alphanumeric characters and hyphens", k)) 920 } 921 if strings.Contains(val, "--") { 922 es = append(es, fmt.Errorf("%q must not contain consecutive hyphens", k)) 923 } 924 if strings.HasSuffix(val, "-") { 925 es = append(es, fmt.Errorf("%q must not end in a hyphen", k)) 926 } 927 928 return 929 } 930 931 func validateDmsReplicationSubnetGroupId(v interface{}, k string) (ws []string, es []error) { 932 val := v.(string) 933 934 if val == "default" { 935 es = append(es, fmt.Errorf("%q must not be default", k)) 936 } 937 if len(val) > 255 { 938 es = append(es, fmt.Errorf("%q must not be longer than 255 characters", k)) 939 } 940 if !regexp.MustCompile(`^[a-zA-Z0-9. _-]+$`).MatchString(val) { 941 es = append(es, fmt.Errorf("%q must only contain alphanumeric characters, periods, spaces, underscores and hyphens", k)) 942 } 943 944 return 945 } 946 947 func validateDmsReplicationTaskId(v interface{}, k string) (ws []string, es []error) { 948 val := v.(string) 949 950 if len(val) > 255 { 951 es = append(es, fmt.Errorf("%q must not be longer than 255 characters", k)) 952 } 953 if !regexp.MustCompile("^[a-zA-Z][a-zA-Z0-9-]+$").MatchString(val) { 954 es = append(es, fmt.Errorf("%q must start with a letter, only contain alphanumeric characters and hyphens", k)) 955 } 956 if strings.Contains(val, "--") { 957 es = append(es, fmt.Errorf("%q must not contain consecutive hyphens", k)) 958 } 959 if strings.HasSuffix(val, "-") { 960 es = append(es, fmt.Errorf("%q must not end in a hyphen", k)) 961 } 962 963 return 964 } 965 966 func validateAppautoscalingScalableDimension(v interface{}, k string) (ws []string, errors []error) { 967 value := v.(string) 968 dimensions := map[string]bool{ 969 "ecs:service:DesiredCount": true, 970 "ec2:spot-fleet-request:TargetCapacity": true, 971 "elasticmapreduce:instancegroup:InstanceCount": true, 972 } 973 974 if !dimensions[value] { 975 errors = append(errors, fmt.Errorf("%q must be a valid scalable dimension value: %q", k, value)) 976 } 977 return 978 } 979 980 func validateAppautoscalingServiceNamespace(v interface{}, k string) (ws []string, errors []error) { 981 value := v.(string) 982 namespaces := map[string]bool{ 983 "ecs": true, 984 "ec2": true, 985 "elasticmapreduce": true, 986 } 987 988 if !namespaces[value] { 989 errors = append(errors, fmt.Errorf("%q must be a valid service namespace value: %q", k, value)) 990 } 991 return 992 } 993 994 func validateConfigRuleSourceOwner(v interface{}, k string) (ws []string, errors []error) { 995 validOwners := []string{ 996 "CUSTOM_LAMBDA", 997 "AWS", 998 } 999 owner := v.(string) 1000 for _, o := range validOwners { 1001 if owner == o { 1002 return 1003 } 1004 } 1005 errors = append(errors, fmt.Errorf( 1006 "%q contains an invalid owner %q. Valid owners are %q.", 1007 k, owner, validOwners)) 1008 return 1009 } 1010 1011 func validateConfigExecutionFrequency(v interface{}, k string) (ws []string, errors []error) { 1012 validFrequencies := []string{ 1013 "One_Hour", 1014 "Three_Hours", 1015 "Six_Hours", 1016 "Twelve_Hours", 1017 "TwentyFour_Hours", 1018 } 1019 frequency := v.(string) 1020 for _, f := range validFrequencies { 1021 if frequency == f { 1022 return 1023 } 1024 } 1025 errors = append(errors, fmt.Errorf( 1026 "%q contains an invalid frequency %q. Valid frequencies are %q.", 1027 k, frequency, validFrequencies)) 1028 return 1029 } 1030 1031 func validateAccountAlias(v interface{}, k string) (ws []string, es []error) { 1032 val := v.(string) 1033 1034 if (len(val) < 3) || (len(val) > 63) { 1035 es = append(es, fmt.Errorf("%q must contain from 3 to 63 alphanumeric characters or hyphens", k)) 1036 } 1037 if !regexp.MustCompile("^[a-z0-9][a-z0-9-]+$").MatchString(val) { 1038 es = append(es, fmt.Errorf("%q must start with an alphanumeric character and only contain lowercase alphanumeric characters and hyphens", k)) 1039 } 1040 if strings.Contains(val, "--") { 1041 es = append(es, fmt.Errorf("%q must not contain consecutive hyphens", k)) 1042 } 1043 if strings.HasSuffix(val, "-") { 1044 es = append(es, fmt.Errorf("%q must not end in a hyphen", k)) 1045 } 1046 return 1047 } 1048 1049 func validateApiGatewayApiKeyValue(v interface{}, k string) (ws []string, errors []error) { 1050 value := v.(string) 1051 if len(value) < 30 { 1052 errors = append(errors, fmt.Errorf( 1053 "%q must be at least 30 characters long", k)) 1054 } 1055 if len(value) > 128 { 1056 errors = append(errors, fmt.Errorf( 1057 "%q cannot be longer than 128 characters", k)) 1058 } 1059 return 1060 } 1061 1062 func validateIamRolePolicyName(v interface{}, k string) (ws []string, errors []error) { 1063 // https://github.com/boto/botocore/blob/2485f5c/botocore/data/iam/2010-05-08/service-2.json#L8291-L8296 1064 value := v.(string) 1065 if len(value) > 128 { 1066 errors = append(errors, fmt.Errorf( 1067 "%q cannot be longer than 128 characters", k)) 1068 } 1069 if !regexp.MustCompile("^[\\w+=,.@-]+$").MatchString(value) { 1070 errors = append(errors, fmt.Errorf("%q must match [\\w+=,.@-]", k)) 1071 } 1072 return 1073 } 1074 1075 func validateIamRolePolicyNamePrefix(v interface{}, k string) (ws []string, errors []error) { 1076 value := v.(string) 1077 if len(value) > 100 { 1078 errors = append(errors, fmt.Errorf( 1079 "%q cannot be longer than 100 characters", k)) 1080 } 1081 if !regexp.MustCompile("^[\\w+=,.@-]+$").MatchString(value) { 1082 errors = append(errors, fmt.Errorf("%q must match [\\w+=,.@-]", k)) 1083 } 1084 return 1085 } 1086 1087 func validateApiGatewayUsagePlanQuotaSettingsPeriod(v interface{}, k string) (ws []string, errors []error) { 1088 validPeriods := []string{ 1089 apigateway.QuotaPeriodTypeDay, 1090 apigateway.QuotaPeriodTypeWeek, 1091 apigateway.QuotaPeriodTypeMonth, 1092 } 1093 period := v.(string) 1094 for _, f := range validPeriods { 1095 if period == f { 1096 return 1097 } 1098 } 1099 errors = append(errors, fmt.Errorf( 1100 "%q contains an invalid period %q. Valid period are %q.", 1101 k, period, validPeriods)) 1102 return 1103 } 1104 1105 func validateApiGatewayUsagePlanQuotaSettings(v map[string]interface{}) (errors []error) { 1106 period := v["period"].(string) 1107 offset := v["offset"].(int) 1108 1109 if period == apigateway.QuotaPeriodTypeDay && offset != 0 { 1110 errors = append(errors, fmt.Errorf("Usage Plan quota offset must be zero in the DAY period")) 1111 } 1112 1113 if period == apigateway.QuotaPeriodTypeWeek && (offset < 0 || offset > 6) { 1114 errors = append(errors, fmt.Errorf("Usage Plan quota offset must be between 0 and 6 inclusive in the WEEK period")) 1115 } 1116 1117 if period == apigateway.QuotaPeriodTypeMonth && (offset < 0 || offset > 27) { 1118 errors = append(errors, fmt.Errorf("Usage Plan quota offset must be between 0 and 27 inclusive in the MONTH period")) 1119 } 1120 1121 return 1122 } 1123 1124 func validateDbSubnetGroupName(v interface{}, k string) (ws []string, errors []error) { 1125 value := v.(string) 1126 if !regexp.MustCompile(`^[ .0-9a-z-_]+$`).MatchString(value) { 1127 errors = append(errors, fmt.Errorf( 1128 "only lowercase alphanumeric characters, hyphens, underscores, periods, and spaces allowed in %q", k)) 1129 } 1130 if len(value) > 255 { 1131 errors = append(errors, fmt.Errorf( 1132 "%q cannot be longer than 255 characters", k)) 1133 } 1134 if regexp.MustCompile(`(?i)^default$`).MatchString(value) { 1135 errors = append(errors, fmt.Errorf( 1136 "%q is not allowed as %q", "Default", k)) 1137 } 1138 return 1139 } 1140 1141 func validateDbSubnetGroupNamePrefix(v interface{}, k string) (ws []string, errors []error) { 1142 value := v.(string) 1143 if !regexp.MustCompile(`^[ .0-9a-z-_]+$`).MatchString(value) { 1144 errors = append(errors, fmt.Errorf( 1145 "only lowercase alphanumeric characters, hyphens, underscores, periods, and spaces allowed in %q", k)) 1146 } 1147 if len(value) > 229 { 1148 errors = append(errors, fmt.Errorf( 1149 "%q cannot be longer than 229 characters", k)) 1150 } 1151 return 1152 } 1153 1154 func validateDbOptionGroupName(v interface{}, k string) (ws []string, errors []error) { 1155 value := v.(string) 1156 if !regexp.MustCompile(`^[a-z]`).MatchString(value) { 1157 errors = append(errors, fmt.Errorf( 1158 "first character of %q must be a letter", k)) 1159 } 1160 if !regexp.MustCompile(`^[0-9a-z-]+$`).MatchString(value) { 1161 errors = append(errors, fmt.Errorf( 1162 "only lowercase alphanumeric characters and hyphens allowed in %q", k)) 1163 } 1164 if regexp.MustCompile(`--`).MatchString(value) { 1165 errors = append(errors, fmt.Errorf( 1166 "%q cannot contain two consecutive hyphens", k)) 1167 } 1168 if regexp.MustCompile(`-$`).MatchString(value) { 1169 errors = append(errors, fmt.Errorf( 1170 "%q cannot end with a hyphen", k)) 1171 } 1172 if len(value) > 255 { 1173 errors = append(errors, fmt.Errorf( 1174 "%q cannot be greater than 255 characters", k)) 1175 } 1176 return 1177 } 1178 1179 func validateDbOptionGroupNamePrefix(v interface{}, k string) (ws []string, errors []error) { 1180 value := v.(string) 1181 if !regexp.MustCompile(`^[a-z]`).MatchString(value) { 1182 errors = append(errors, fmt.Errorf( 1183 "first character of %q must be a letter", k)) 1184 } 1185 if !regexp.MustCompile(`^[0-9a-z-]+$`).MatchString(value) { 1186 errors = append(errors, fmt.Errorf( 1187 "only alphanumeric characters and hyphens allowed in %q", k)) 1188 } 1189 if regexp.MustCompile(`--`).MatchString(value) { 1190 errors = append(errors, fmt.Errorf( 1191 "%q cannot contain two consecutive hyphens", k)) 1192 } 1193 if len(value) > 229 { 1194 errors = append(errors, fmt.Errorf( 1195 "%q cannot be greater than 229 characters", k)) 1196 } 1197 return 1198 } 1199 1200 func validateAwsAlbTargetGroupName(v interface{}, k string) (ws []string, errors []error) { 1201 name := v.(string) 1202 if len(name) > 32 { 1203 errors = append(errors, fmt.Errorf("%q (%q) cannot be longer than '32' characters", k, name)) 1204 } 1205 return 1206 } 1207 1208 func validateAwsAlbTargetGroupNamePrefix(v interface{}, k string) (ws []string, errors []error) { 1209 name := v.(string) 1210 if len(name) > 32 { 1211 errors = append(errors, fmt.Errorf("%q (%q) cannot be longer than '6' characters", k, name)) 1212 } 1213 return 1214 } 1215 1216 func validateOpenIdURL(v interface{}, k string) (ws []string, errors []error) { 1217 value := v.(string) 1218 u, err := url.Parse(value) 1219 if err != nil { 1220 errors = append(errors, fmt.Errorf("%q has to be a valid URL", k)) 1221 return 1222 } 1223 if u.Scheme != "https" { 1224 errors = append(errors, fmt.Errorf("%q has to use HTTPS scheme (i.e. begin with https://)", k)) 1225 } 1226 if len(u.Query()) > 0 { 1227 errors = append(errors, fmt.Errorf("%q cannot contain query parameters per the OIDC standard", k)) 1228 } 1229 return 1230 } 1231 1232 func validateAwsKmsName(v interface{}, k string) (ws []string, es []error) { 1233 value := v.(string) 1234 if !regexp.MustCompile(`^(alias\/)[a-zA-Z0-9:/_-]+$`).MatchString(value) { 1235 es = append(es, fmt.Errorf( 1236 "%q must begin with 'alias/' and be comprised of only [a-zA-Z0-9:/_-]", k)) 1237 } 1238 return 1239 } 1240 1241 func validateCognitoIdentityPoolName(v interface{}, k string) (ws []string, errors []error) { 1242 val := v.(string) 1243 if !regexp.MustCompile("^[\\w _]+$").MatchString(val) { 1244 errors = append(errors, fmt.Errorf("%q must contain only alphanumeric caracters and spaces", k)) 1245 } 1246 1247 return 1248 } 1249 1250 func validateCognitoProviderDeveloperName(v interface{}, k string) (ws []string, errors []error) { 1251 value := v.(string) 1252 if len(value) > 100 { 1253 errors = append(errors, fmt.Errorf("%q cannot be longer than 100 caracters", k)) 1254 } 1255 1256 if !regexp.MustCompile("^[\\w._-]+$").MatchString(value) { 1257 errors = append(errors, fmt.Errorf("%q must contain only alphanumeric caracters, dots, underscores and hyphens", k)) 1258 } 1259 1260 return 1261 } 1262 1263 func validateCognitoSupportedLoginProviders(v interface{}, k string) (ws []string, errors []error) { 1264 value := v.(string) 1265 if len(value) < 1 { 1266 errors = append(errors, fmt.Errorf("%q cannot be less than 1 character", k)) 1267 } 1268 1269 if len(value) > 128 { 1270 errors = append(errors, fmt.Errorf("%q cannot be longer than 128 caracters", k)) 1271 } 1272 1273 if !regexp.MustCompile("^[\\w.;_/-]+$").MatchString(value) { 1274 errors = append(errors, fmt.Errorf("%q must contain only alphanumeric caracters, dots, semicolons, underscores, slashes and hyphens", k)) 1275 } 1276 1277 return 1278 } 1279 1280 func validateCognitoIdentityProvidersClientId(v interface{}, k string) (ws []string, errors []error) { 1281 value := v.(string) 1282 if len(value) < 1 { 1283 errors = append(errors, fmt.Errorf("%q cannot be less than 1 character", k)) 1284 } 1285 1286 if len(value) > 128 { 1287 errors = append(errors, fmt.Errorf("%q cannot be longer than 128 caracters", k)) 1288 } 1289 1290 if !regexp.MustCompile("^[\\w_]+$").MatchString(value) { 1291 errors = append(errors, fmt.Errorf("%q must contain only alphanumeric caracters and underscores", k)) 1292 } 1293 1294 return 1295 } 1296 1297 func validateCognitoIdentityProvidersProviderName(v interface{}, k string) (ws []string, errors []error) { 1298 value := v.(string) 1299 if len(value) < 1 { 1300 errors = append(errors, fmt.Errorf("%q cannot be less than 1 character", k)) 1301 } 1302 1303 if len(value) > 128 { 1304 errors = append(errors, fmt.Errorf("%q cannot be longer than 128 caracters", k)) 1305 } 1306 1307 if !regexp.MustCompile("^[\\w._:/-]+$").MatchString(value) { 1308 errors = append(errors, fmt.Errorf("%q must contain only alphanumeric caracters, dots, underscores, colons, slashes and hyphens", k)) 1309 } 1310 1311 return 1312 } 1313 1314 func validateWafMetricName(v interface{}, k string) (ws []string, errors []error) { 1315 value := v.(string) 1316 if !regexp.MustCompile(`^[0-9A-Za-z]+$`).MatchString(value) { 1317 errors = append(errors, fmt.Errorf( 1318 "Only alphanumeric characters allowed in %q: %q", 1319 k, value)) 1320 } 1321 return 1322 } 1323 1324 func validateIamRoleDescription(v interface{}, k string) (ws []string, errors []error) { 1325 value := v.(string) 1326 1327 if len(value) > 1000 { 1328 errors = append(errors, fmt.Errorf("%q cannot be longer than 1000 caracters", k)) 1329 } 1330 1331 if !regexp.MustCompile(`[\p{L}\p{M}\p{Z}\p{S}\p{N}\p{P}]*`).MatchString(value) { 1332 errors = append(errors, fmt.Errorf( 1333 "Only alphanumeric & accented characters allowed in %q: %q (Must satisfy regular expression pattern: [\\p{L}\\p{M}\\p{Z}\\p{S}\\p{N}\\p{P}]*)", 1334 k, value)) 1335 } 1336 return 1337 } 1338 1339 func validateSsmParameterType(v interface{}, k string) (ws []string, errors []error) { 1340 value := v.(string) 1341 types := map[string]bool{ 1342 "String": true, 1343 "StringList": true, 1344 "SecureString": true, 1345 } 1346 1347 if !types[value] { 1348 errors = append(errors, fmt.Errorf("Parameter type %s is invalid. Valid types are String, StringList or SecureString", value)) 1349 } 1350 return 1351 }