diff --git a/cicd/cloudformation/release.yaml b/cicd/cloudformation/release.yaml index 7930744b..8bd8a229 100644 --- a/cicd/cloudformation/release.yaml +++ b/cicd/cloudformation/release.yaml @@ -37,6 +37,10 @@ Parameters: Description: Resource ARN for the CodeStar Connection to use Type: String AllowedPattern: '[A-Za-z0-9:/-]+' + SecretsConfig: + Description: Output from the secrets.yaml stack + Type: String + AllowedPattern: '(arn:aws:secretsmanager:((us(-gov)?|ap|ca|cn|eu|sa)-(central|(north|south)?(east|west)?)-\d):[0-9]{8,12}:secret:[a-zA-Z0-9/_+=.@-]{1,512})(,(arn:aws:secretsmanager:((us(-gov)?|ap|ca|cn|eu|sa)-(central|(north|south)?(east|west)?)-\d):[0-9]{8,12}:secret:[a-zA-Z0-9/_+=.@-]{1,512})){3}((,arn:aws:secretsmanager:((us(-gov)?|ap|ca|cn|eu|sa)-(central|(north|south)?(east|west)?)-\d):[0-9]{8,12}:secret:[a-zA-Z0-9/_+=.@-]{1,512})|(,"")){4}(,arn:aws:kms:((us(-gov)?|ap|ca|cn|eu|sa)-(central|(north|south)?(east|west)?)-\d):[0-9]{12}:key/[a-zA-Z0-9/_+=.@-]{1,512})' Metadata: AWS::CloudFormation::Interface: @@ -60,22 +64,28 @@ Metadata: default: Connection id for the CodeStar Connection to use Parameters: - CodeStarConnection + - Label: + default: Secrets ARNs + Parameters: + - SecretsConfig ParameterLabels: CodeStarConnection: default: "arn:aws:codestar-connections:::connection/abcd1234-ab12-ab12--ab12-abcdef123456" ManagementAccount: - default: "123456789012" + default: "What is the account id of the Test Orgs, Management account?" + DelegatedAccount: + default: "What is the account id of the Test Orgs, Delegated admin account?" + NonDelegatedAccount: + default: "What is the account id of the Test Orgs, Non-delegated admin account?" ManagementBucket: default: "my-bucket" - DelegatedAccount: - default: "123456789012" DelegatedBucket: default: "my-bucket" - NonDelegatedAccount: - default: "123456789012" NonDelegatedBucket: default: "my-bucket" + SecretsConfig: + default: "TestConfig from the output of secrets.yaml" Resources: @@ -476,6 +486,24 @@ Resources: Value: !Sub "${ManagementAccount},${DelegatedAccount},${NonDelegatedAccount}" - Name: AppArn Value: !Sub "arn:aws:serverlessrepo:${AWS::Region}:${AWS::AccountId}:applications/SSOSync-Staging" + - Name: SecretSCIMEndpoint + Value: !Select [0, !Split [',', !Ref SecretsConfig]] + - Name: SecretSCIMAccessToken + Value: !Select [1, !Split [',', !Ref SecretsConfig]] + - Name: SecretRegion + Value: !Select [2, !Split [',', !Ref SecretsConfig]] + - Name: SecretIdentityStoreID + Value: !Select [3, !Split [',', !Ref SecretsConfig]] + - Name: SecretGoogleCredentials + Value: !Select [4, !Split [',', !Ref SecretsConfig]] + - Name: SecretGoogleAdminEmail + Value: !Select [5, !Split [',', !Ref SecretsConfig]] + - Name: SecretWIFClientLibraryConfig + Value: !Select [6, !Split [',', !Ref SecretsConfig]] + - Name: SecretWIFServiceAccountEmail + Value: !Select [7, !Split [',', !Ref SecretsConfig]] + - Name: KeyForSecrets + Value: !Select [8, !Split [',', !Ref SecretsConfig]] Artifacts: Name: SSOSync-Build Type: CODEPIPELINE diff --git a/cicd/cloudformation/secrets.yaml b/cicd/cloudformation/secrets.yaml index 88da0656..76e5af78 100644 --- a/cicd/cloudformation/secrets.yaml +++ b/cicd/cloudformation/secrets.yaml @@ -6,35 +6,65 @@ Description: (via privately shared app in the AWS Serverless Application Repository (SAR). Parameters: + ManagementAccount: + Description: AWS Account where staging build is automatically deployed and tested + Type: String + AllowedPattern: '[0-9]+' + + DelegatedAccount: + Description: AWS Account where staging build is automatically deployed and tested + Type: String + AllowedPattern: '[0-9]+' + + NonDelegatedAccount: + Description: AWS Account where staging build is automatically deployed and tested + Type: String + AllowedPattern: '[0-9]+' + GoogleAuthMethod: Type: String - AllowedValues: ["Google Credentials", "Workload Identity Federation", "Both"] + AllowedValues: + - Google Credentials + - Workload Identity Federation + - Both Default: "Google Credentials" + GoogleCredentials: Description: Google Workspaces Credentials File, to log into Google (content of credentials.json) Type: String + AllowedPattern: '(?!.*\s)|(\{(\s)*(".*")(\s)*:(\s)*(".*")(\s)*\})' NoEcho: true + GoogleAdminEmail: Description: Google Workspaces Admin email Type: String + AllowedPattern: '(?!.*\s)|(([a-zA-Z0-9.+=_-]{0,61})@[a-zA-Z0-9](?:[a-zA-Z0-9-]{0,61}[a-zA-Z0-9])?(?:\.[a-zA-Z0-9](?:[a-zA-Z0-9-]{0,61}[a-zA-Z0-9])?)*)' NoEcho: true + WIFServiceAccountEmail: Description: Workload Identity Federation, the email address of service account used to impersonate a user using Type: String + AllowedPattern: '(?!.*\s)|(([a-zA-Z0-9.+=_-]{0,61})@[a-zA-Z0-9](?:[a-zA-Z0-9-]{0,61}[a-zA-Z0-9])?(?:\.[a-zA-Z0-9](?:[a-zA-Z0-9-]{0,61}[a-zA-Z0-9])?)*)' NoEcho: true + WIFClientLibraryConfig: Description: Workload Identity Federation, the client library config file for the provider (AWS Account) (contents of clientLibraryConfig-provider.json) Type: String + AllowedPattern: '(?!.*\s)|(\{(\s)*(".*")(\s)*:(\s)*(".*")(\s)*\})' NoEcho: true + SCIMEndpointUrl: Description: AWS IAM Identity Center SCIM Endpoint Url Type: String - NoEcho: true AllowedPattern: "https://scim.(us(-gov)?|ap|ca|cn|eu|sa)-(central|(north|south)?(east|west)?)-([0-9]{1}).amazonaws.com/(.*)-([a-z0-9]{4})-([a-z0-9]{4})-([a-z0-9]{12})/scim/v2/" + NoEcho: true + SCIMEndpointAccessToken: Description: AWS IAM Identity Center SCIM AccessToken Type: String + AllowedPattern: '([0-9a-zA-Z/=+-\\]{500,600})' NoEcho: true + IdentityStoreId: Description: The Id of the Identity Store for the AWS IAM Identity Center instance see (settings page) Type: String @@ -44,6 +74,12 @@ Parameters: Metadata: AWS::CloudFormation::Interface: ParameterGroups: + - Label: + default: Test Environments + Parameters: + - ManagementAccount + - DelegatedAccount + - NonDelegatedAccount - Label: default: Google Authentication Method Parameters: @@ -66,6 +102,12 @@ Metadata: - IdentityStoreId ParameterLabels: + ManagementAccount: + default: "What is the account id of the Test Orgs, Management account?" + DelegatedAccount: + default: "What is the account id of the Test Orgs, Delegated admin account?" + NonDelegatedAccount: + default: "What is the account id of the Test Orgs, Non-delegated admin account?" GoogleAuthMethod: default: "Which Google Auth Methods do you want to test with?" GoogleCredentials: @@ -81,18 +123,45 @@ Metadata: SCIMEndpointAccessToken: default: "AWS SSO SCIM Access Token" IdentityStoreId: - default: "d-1234567abc" + default: "The Identity Store Id" Conditions: - GoogleCreds: !Or [!Equals [!Ref "GoogleAuthMethod", Google Credentials], !Equals [!Ref "GoogleAuthMethod", Both]] - WIFCreds: !Or [!Equals [!Ref "GoogleAuthMethod", Workload Identity Federation], !Equals [!Ref "GoogleAuthMethod", Both]] + CreateGoogle: !Or + - !Equals + - !Ref GoogleAuthMethod + - "Google Credentials" + - !Equals + - !Ref GoogleAuthMethod + - "Both" + CreateWIF: !Or + - !Equals + - !Ref GoogleAuthMethod + - "Workload Identity Federation" + - !Equals + - !Ref GoogleAuthMethod + - "Both" + GoogleCreds: !Equals + - !Ref GoogleAuthMethod + - "Google Credentials" + WIFCreds: !Equals + - !Ref GoogleAuthMethod + - "Workload Identity Federation" + BothCreds: !Equals + - !Ref GoogleAuthMethod + - "Both" Rules: # Fail when any assertion returns false # If they have selected Google Credentials then check they have provided valid data for GoogleCredentials GoogleCredentialsOnly: - RuleCondition: !Or [!Equals [!Ref "GoogleAuthMethod", Google Credentials], !Equals [!Ref "GoogleAuthMethod", Both]] + RuleCondition: !Or + - !Equals + - !Ref GoogleAuthMethod + - "Google Credentials" + - !Equals + - !Ref GoogleAuthMethod + - "Both" Assertions: - AssertDescription: You have selected Google Credentials, You need to provide a Google Admin email address. Assert: !Not @@ -106,7 +175,13 @@ Rules: - "" # If they have selected Workload Identity Federation, then check they have provide valid data for WIF WorkloadIdentityFederationOnly: - RuleCondition: !Or [!Equals [!Ref "GoogleAuthMethod", Workload Identity Federation], !Equals [!Ref "GoogleAuthMethod", Both]] + RuleCondition: !Or + - !Equals + - !Ref GoogleAuthMethod + - "Workload Identity Federation" + - !Equals + - !Ref GoogleAuthMethod + - "Both" Assertions: - AssertDescription: You have selected Workload Identity Federation, You need to provide a Google Service Account email address. Assert: !Not @@ -120,54 +195,343 @@ Rules: - "" Resources: - GoogleCredentialSecret: + KeyAlias: + Type: AWS::KMS::Alias + Properties: + AliasName: alias/SSOSync + TargetKeyId: !Ref KeyForSecrets + + KeyForSecrets: + Type: AWS::KMS::Key + Properties: + Description: Key for protecting SSOSync Secrets in cross-account deployment + Enabled: true + KeySpec: SYMMETRIC_DEFAULT + KeyUsage: ENCRYPT_DECRYPT + MultiRegion: false + PendingWindowInDays: 7 + KeyPolicy: + Version: 2012-10-17 + Id: key-default-1 + Statement: + - Sid: Enable IAM User Permissions + Effect: Allow + Principal: + AWS: !Sub arn:aws:iam::${AWS::AccountId}:root + Action: 'kms:*' + Resource: '*' + - Sid: DeployRole in Management account + Effect: Allow + Principal: + AWS: !Sub arn:aws:iam::${ManagementAccount}:root + Action: + - kms:Decrypt + - kms:DescribeKey + Resource: '*' + - Sid: DeployRole in Delegated Admin account + Effect: Allow + Principal: + AWS: !Sub arn:aws:iam::${DelegatedAccount}:root + Action: + - kms:Decrypt + - kms:DescribeKey + Resource: '*' + - Sid: DeployRole in Non Delegated Admin account + Effect: Allow + Principal: + AWS: !Sub arn:aws:iam::${NonDelegatedAccount}:root + Action: + - kms:Decrypt + - kms:DescribeKey + Resource: '*' + + SecretGoogleCredentials: Type: "AWS::SecretsManager::Secret" - Condition: GoogleCreds + Condition: CreateGoogle Properties: Name: TestGoogleCredentials SecretString: !Ref GoogleCredentials + KmsKeyId: !Ref KeyAlias - GoogleAdminEmailSecret: + SecretGoogleCredentialsPolicy: + Type: AWS::SecretsManager::ResourcePolicy + Condition: CreateGoogle + Properties: + SecretId: !Ref SecretGoogleCredentials + ResourcePolicy: + Version: 2012-10-17 + Statement: + - Effect: Allow + Principal: + AWS: !Sub arn:aws:iam::${ManagementAccount}:root + Action: + - secretsmanager:GetSecretValue + Resource: '*' + - Effect: Allow + Principal: + AWS: !Sub arn:aws:iam::${DelegatedAccount}:root + Action: + - secretsmanager:GetSecretValue + Resource: '*' + - Effect: Allow + Principal: + AWS: !Sub arn:aws:iam::${NonDelegatedAccount}:root + Action: + - secretsmanager:GetSecretValue + Resource: '*' + + SecretGoogleAdminEmail: Type: "AWS::SecretsManager::Secret" - Condition: GoogleCreds + Condition: CreateGoogle Properties: Name: TestGoogleAdminEmail SecretString: !Ref GoogleAdminEmail + KmsKeyId: !Ref KeyAlias + + SecretGoogleAdminEmailPolicy: + Type: AWS::SecretsManager::ResourcePolicy + Condition: CreateGoogle + Properties: + SecretId: !Ref SecretGoogleAdminEmail + ResourcePolicy: + Version: 2012-10-17 + Statement: + - Effect: Allow + Principal: + AWS: !Sub arn:aws:iam::${ManagementAccount}:root + Action: + - secretsmanager:GetSecretValue + Resource: '*' + - Effect: Allow + Principal: + AWS: !Sub arn:aws:iam::${DelegatedAccount}:root + Action: + - secretsmanager:GetSecretValue + Resource: '*' + - Effect: Allow + Principal: + AWS: !Sub arn:aws:iam::${NonDelegatedAccount}:root + Action: + - secretsmanager:GetSecretValue + Resource: '*' - WIFServiceAccountEmailSecret: + SecretWIFServiceAccountEmail: Type: "AWS::SecretsManager::Secret" - Condition: WIFCreds + Condition: CreateWIF Properties: Name: TestWIFServiceAccountEmail SecretString: !Ref WIFServiceAccountEmail + KmsKeyId: !Ref KeyAlias - WIFClientLibraryConfigSecret: + SecretWIFServiceAccountEmailPolicy: + Type: AWS::SecretsManager::ResourcePolicy + Condition: CreateWIF + Properties: + SecretId: !Ref SecretWIFServiceAccountEmail + ResourcePolicy: + Version: 2012-10-17 + Statement: + - Effect: Allow + Principal: + AWS: !Sub arn:aws:iam::${ManagementAccount}:root + Action: + - secretsmanager:GetSecretValue + Resource: '*' + - Effect: Allow + Principal: + AWS: !Sub arn:aws:iam::${DelegatedAccount}:root + Action: + - secretsmanager:GetSecretValue + Resource: '*' + - Effect: Allow + Principal: + AWS: !Sub arn:aws:iam::${NonDelegatedAccount}:root + Action: + - secretsmanager:GetSecretValue + Resource: '*' + + SecretWIFClientLibraryConfig: Type: "AWS::SecretsManager::Secret" - Condition: WIFCreds + Condition: CreateWIF Properties: Name: TestWIFClientLibraryConfigSecret SecretString: !Ref WIFClientLibraryConfig + KmsKeyId: !Ref KeyAlias - SSoSCIMUrlSecret: # This can be moved to custom provider + SecretWIFClientLibraryConfigPolicy: + Type: AWS::SecretsManager::ResourcePolicy + Condition: CreateWIF + Properties: + SecretId: !Ref SecretWIFClientLibraryConfig + ResourcePolicy: + Version: 2012-10-17 + Statement: + - Effect: Allow + Principal: + AWS: !Sub arn:aws:iam::${ManagementAccount}:root + Action: + - secretsmanager:GetSecretValue + Resource: '*' + - Effect: Allow + Principal: + AWS: !Sub arn:aws:iam::${DelegatedAccount}:root + Action: + - secretsmanager:GetSecretValue + Resource: '*' + - Effect: Allow + Principal: + AWS: !Sub arn:aws:iam::${NonDelegatedAccount}:root + Action: + - secretsmanager:GetSecretValue + Resource: '*' + + SecretSCIMEndpoint: # This can be moved to custom provider Type: "AWS::SecretsManager::Secret" Properties: Name: TestSCIMEndpointUrl SecretString: !Ref SCIMEndpointUrl + KmsKeyId: !Ref KeyAlias + + SecretSCIMEndpointPolicy: + Type: AWS::SecretsManager::ResourcePolicy + Properties: + SecretId: !Ref SecretSCIMEndpoint + ResourcePolicy: + Version: 2012-10-17 + Statement: + - Effect: Allow + Principal: + AWS: !Sub arn:aws:iam::${ManagementAccount}:root + Action: + - secretsmanager:GetSecretValue + Resource: '*' + - Effect: Allow + Principal: + AWS: !Sub arn:aws:iam::${DelegatedAccount}:root + Action: + - secretsmanager:GetSecretValue + Resource: '*' + - Effect: Allow + Principal: + AWS: !Sub arn:aws:iam::${NonDelegatedAccount}:root + Action: + - secretsmanager:GetSecretValue + Resource: '*' - SSoSSCIMAccessTokenSecret: # This can be moved to custom provider + SecretSCIMAccessToken: # This can be moved to custom provider Type: "AWS::SecretsManager::Secret" Properties: Name: TestSCIMAccessToken SecretString: !Ref SCIMEndpointAccessToken + KmsKeyId: !Ref KeyAlias + + SecretSCIMAccessTokenPolicy: + Type: AWS::SecretsManager::ResourcePolicy + Properties: + SecretId: !Ref SecretSCIMAccessToken + ResourcePolicy: + Version: 2012-10-17 + Statement: + - Effect: Allow + Principal: + AWS: !Sub arn:aws:iam::${ManagementAccount}:root + Action: + - secretsmanager:GetSecretValue + Resource: '*' + - Effect: Allow + Principal: + AWS: !Sub arn:aws:iam::${DelegatedAccount}:root + Action: + - secretsmanager:GetSecretValue + Resource: '*' + - Effect: Allow + Principal: + AWS: !Sub arn:aws:iam::${NonDelegatedAccount}:root + Action: + - secretsmanager:GetSecretValue + Resource: '*' - RegionSecret: + SecretRegion: Type: "AWS::SecretsManager::Secret" Properties: Name: TestRegion SecretString: !Select [1, !Split [".", !Ref SCIMEndpointUrl]] - IdentityStoreIdSecret: + SecretRegionPolicy: + Type: AWS::SecretsManager::ResourcePolicy + Properties: + SecretId: !Ref SecretRegion + ResourcePolicy: + Version: 2012-10-17 + Statement: + - Effect: Allow + Principal: + AWS: !Sub arn:aws:iam::${ManagementAccount}:root + Action: + - secretsmanager:GetSecretValue + Resource: '*' + - Effect: Allow + Principal: + AWS: !Sub arn:aws:iam::${DelegatedAccount}:root + Action: + - secretsmanager:GetSecretValue + Resource: '*' + - Effect: Allow + Principal: + AWS: !Sub arn:aws:iam::${NonDelegatedAccount}:root + Action: + - secretsmanager:GetSecretValue + Resource: '*' + + SecretIdentityStoreID: Type: "AWS::SecretsManager::Secret" Properties: Name: TestIdentityStoreId SecretString: !Ref IdentityStoreId + + SecretIdentityStoreIDPolicy: + Type: AWS::SecretsManager::ResourcePolicy + Properties: + SecretId: !Ref SecretIdentityStoreID + ResourcePolicy: + Version: 2012-10-17 + Statement: + - Effect: Allow + Principal: + AWS: !Sub arn:aws:iam::${ManagementAccount}:root + Action: + - secretsmanager:GetSecretValue + Resource: '*' + - Effect: Allow + Principal: + AWS: !Sub arn:aws:iam::${DelegatedAccount}:root + Action: + - secretsmanager:GetSecretValue + Resource: '*' + - Effect: Allow + Principal: + AWS: !Sub arn:aws:iam::${NonDelegatedAccount}:root + Action: + - secretsmanager:GetSecretValue + Resource: '*' +Outputs: + TestConfigGoogleCreds: + Condition: GoogleCreds + Description: "The Comma Separated list of Secrets and KMS Key ARNs to copy and paste into the CrossStackConfig field of the app for cross-account stack." + Value: !Sub ${SecretSCIMEndpoint},${SecretSCIMAccessToken},${SecretRegion},${SecretIdentityStoreID},${SecretGoogleCredentials},${SecretGoogleAdminEmail},"","",arn:aws:kms:${AWS::Region}:${AWS::AccountId}:key/${KeyForSecrets} + Export: + Name: TestConfig + + TestConfigWIFCreds: + Condition: WIFCreds + Description: "The Comma Separated list of Secrets and KMS Key ARNs to copy and paste into the CrossStackConfig field of the app for cross-account stack." + Value: !Sub ${SecretSCIMEndpoint},${SecretSCIMAccessToken},${SecretRegion},${SecretIdentityStoreID},"","",${SecretWIFClientLibraryConfig},${SecretWIFServiceAccountEmail},arn:aws:kms:${AWS::Region}:${AWS::AccountId}:key/${KeyForSecrets} + Export: + Name: TestConfig + + TestConfigBoth: + Condition: BothCreds + Description: "The Comma Separated list of Secrets and KMS Key ARNs to copy and paste into the CrossStackConfig field of the app for cross-account stack." + Value: !Sub ${SecretSCIMEndpoint},${SecretSCIMAccessToken},${SecretRegion},${SecretIdentityStoreID},${SecretGoogleCredentials},${SecretGoogleAdminEmail},${SecretWIFClientLibraryConfig},${SecretWIFServiceAccountEmail},arn:aws:kms:${AWS::Region}:${AWS::AccountId}:key/${KeyForSecrets} + Export: + Name: TestConfig diff --git a/template.yaml b/template.yaml index ea614c3c..0c22e0b4 100644 --- a/template.yaml +++ b/template.yaml @@ -132,7 +132,7 @@ Parameters: Description: | Credentials to log into Google (content of credentials.json) Default: "" - AllowedPattern: '(?!.*\s)|(\d{12})|(\{(\s)*(".*")(\s)*:(\s)*(".*")(\s)*\})' + AllowedPattern: '(?!.*\s)|(\{(\s)*(".*")(\s)*:(\s)*(".*")(\s)*\})' NoEcho: true GoogleAdminEmail: @@ -140,7 +140,7 @@ Parameters: Description: | Google Admin email Default: "" - AllowedPattern: '(?!.*\s)|(\d{12})|(([a-zA-Z0-9.+=_-]{0,61})@[a-zA-Z0-9](?:[a-zA-Z0-9-]{0,61}[a-zA-Z0-9])?(?:\.[a-zA-Z0-9](?:[a-zA-Z0-9-]{0,61}[a-zA-Z0-9])?)*)' + AllowedPattern: '(?!.*\s)|(([a-zA-Z0-9.+=_-]{0,61})@[a-zA-Z0-9](?:[a-zA-Z0-9-]{0,61}[a-zA-Z0-9])?(?:\.[a-zA-Z0-9](?:[a-zA-Z0-9-]{0,61}[a-zA-Z0-9])?)*)' NoEcho: true SCIMEndpointUrl: @@ -148,14 +148,14 @@ Parameters: Description: | AWS IAM Identity Center - SCIM Endpoint Url Default: "" - AllowedPattern: '(?!.*\s)|(\d{12})|(https://scim.(us(-gov)?|ap|ca|cn|eu|sa)-(central|(north|south)?(east|west)?)-([0-9]{1}).amazonaws.com/(.*)-([a-z0-9]{4})-([a-z0-9]{4})-([a-z0-9]{12})/scim/v2/)' + AllowedPattern: '(?!.*\s)|(https://scim.(us(-gov)?|ap|ca|cn|eu|sa)-(central|(north|south)?(east|west)?)-([0-9]{1}).amazonaws.com/(.*)-([a-z0-9]{4})-([a-z0-9]{4})-([a-z0-9]{12})/scim/v2/)' SCIMEndpointAccessToken: Type: String Description: | AWS IAM Identity Center - SCIM AccessToken Default: "" - AllowedPattern: '(?!.*\s)|(\d{12})|([0-9a-zA-Z/=+-\\]{500,600})' + AllowedPattern: '(?!.*\s)|([0-9a-zA-Z/=+-\\]{500,600})' NoEcho: true Region: @@ -163,14 +163,14 @@ Parameters: Description: | AWS Region where AWS IAM Identity Center is enabled Default: "" - AllowedPattern: '(?!.*\s)|(\d{12})|(us(-gov)?|ap|ca|cn|eu|sa)-(central|(north|south)?(east|west)?)-\d' + AllowedPattern: '(?!.*\s)|(us(-gov)?|ap|ca|cn|eu|sa)-(central|(north|south)?(east|west)?)-\d' IdentityStoreID: Type: String Description: | Identifier of Identity Store in AWS IAM Identity Center Default: "" - AllowedPattern: '(?!.*\s)|(\d{12})|d-[1-z0-9]{10}' + AllowedPattern: '(?!.*\s)|d-[1-z0-9]{10}' GoogleUserMatch: Type: String