--- AWSTemplateFormatVersion: 2010-09-09 Description: CloudeeCMS Auto Deployment Full Installation (Online Update) 2023-06-07 13:30 Metadata: 'AWS::CloudFormation::Interface': ParameterGroups: - Label: default: CMS Settings Parameters: - ProjectName - Label: default: Website Settings Parameters: - CloudFrontParam - ProdURL - AcmCertificatePROD - CdnURL - AcmCertificateCDN - CognitoUserEmail - Label: default: Decisions Parameters: - EnableOAUTH - Label: default: Optional Settings - External IdP - only required if (A) = true Parameters: - OAUTHLoginLabel - SAMLMetadataURL ParameterLabels: CognitoUserEmail: default: Email address of admin user CdnURL: default: Content Delivery Network (CDN) CloudFront URL ProdURL: default: Production Website URL ProjectName: default: Project Name EnableOAUTH: default: (A) External IdP Login? OAUTHLoginLabel: default: Login Label for IdP SAMLMetadataURL: default: URL of the SAML Metadata File AcmCertificateCDN: default: SSL Certificate for Content Delivery Network AcmCertificatePROD: default: SSL Certificate for Website CloudFrontParam: default: CloudFront Price Class Parameters: ProjectName: Type: String Description: The name of this CMS Project, all lower case Default: "examplecms" AllowedPattern: '[a-z0-9\-]*' ConstraintDescription: "Only lowercase and alphanumeric characters." CognitoUserEmail: Type: String Description: "Enter a valid email address for the admin user login." Default: "" EnableOAUTH: Type: String Description: Allow login using IdP? (e.g. Azure AD) If you select true, you must enter a valid Metadata URL for the external IdP Default: "false" AllowedValues: - 'true' - 'false' OAUTHLoginLabel: Type: String Description: Label on login form for sign-in when using IdP. Default: "Sign in with Azure AD Account" SAMLMetadataURL: Type: String Description: URL of the SAML Metadata File. Default: "https://URLTOMETADATAFILE" CdnURL: Type: String Default: cdn.yourdomain.com Description: The URL of the CDN ProdURL: Type: String Default: www.yourdomain.com Description: The URL of the website CloudFrontParam: Type: String Default: PriceClass_100 Description: The CloudFront PriceClass AllowedValues: - 'PriceClass_100' - 'PriceClass_200' - 'PriceClass_All' AcmCertificateCDN: Type: String Default: "" Description: The ARN of the CDN certificate AcmCertificatePROD: Type: String Default: "" Description: The ARN of the PROD website certificate Conditions: CognitoIdPCondition: !Equals - !Ref EnableOAUTH - 'true' Resources: CodePipelineSourceBucket: Type: AWS::S3::Bucket DeletionPolicy: Delete Properties: BucketName: !Sub ${ProjectName}-pipeline-source-${AWS::AccountId} VersioningConfiguration: Status: Enabled PipelineArtifactsBucket: Type: AWS::S3::Bucket DeletionPolicy: Delete Properties: BucketName: !Sub ${ProjectName}-pipeline-artifacts-${AWS::AccountId} AdminBucket: Type: AWS::S3::Bucket Properties: BucketName: !Sub ${ProjectName}-cloudeecms-editor-${AWS::AccountId} PublicAccessBlockConfiguration: BlockPublicAcls: false BlockPublicPolicy: false IgnorePublicAcls: false RestrictPublicBuckets: false OwnershipControls: Rules: - ObjectOwnership: ObjectWriter MetricsConfigurations: - Id: EntireBucket WebsiteConfiguration: IndexDocument: index.html ErrorDocument: error.html DeletionPolicy: Delete TestBucket: Type: AWS::S3::Bucket Properties: BucketName: !Sub ${ProjectName}-cloudeecms-test-${AWS::AccountId} PublicAccessBlockConfiguration: BlockPublicAcls: false BlockPublicPolicy: false IgnorePublicAcls: false RestrictPublicBuckets: false OwnershipControls: Rules: - ObjectOwnership: ObjectWriter CorsConfiguration: CorsRules: - AllowedHeaders: - "Authorization" AllowedMethods: - GET AllowedOrigins: - "*" MaxAge: 3000 - AllowedHeaders: - "*" AllowedMethods: - POST AllowedOrigins: - "*" ExposedHeaders: - x-amz-request-id - x-amz-id-2 - AllowedHeaders: - "*" AllowedMethods: - PUT AllowedOrigins: - "*" ExposedHeaders: - x-amz-request-id - x-amz-id-2 MetricsConfigurations: - Id: EntireBucket WebsiteConfiguration: IndexDocument: index.html ErrorDocument: error.html DeletionPolicy: Delete ProdBucket: Type: AWS::S3::Bucket Properties: BucketName: !Sub ${ProjectName}-cloudeecms-prod-${AWS::AccountId} PublicAccessBlockConfiguration: BlockPublicAcls: false BlockPublicPolicy: false IgnorePublicAcls: false RestrictPublicBuckets: false OwnershipControls: Rules: - ObjectOwnership: ObjectWriter CorsConfiguration: CorsRules: - AllowedHeaders: - "Authorization" AllowedMethods: - GET AllowedOrigins: - "*" MaxAge: 3000 - AllowedHeaders: - "*" AllowedMethods: - POST AllowedOrigins: - "*" ExposedHeaders: - x-amz-request-id - x-amz-id-2 - AllowedHeaders: - "*" AllowedMethods: - PUT AllowedOrigins: - "*" ExposedHeaders: - x-amz-request-id - x-amz-id-2 MetricsConfigurations: - Id: EntireBucket WebsiteConfiguration: IndexDocument: index.html ErrorDocument: error.html DeletionPolicy: Delete CDNBucket: Type: AWS::S3::Bucket Properties: BucketName: !Sub ${ProjectName}-cloudeecms-cdn-${AWS::AccountId} PublicAccessBlockConfiguration: BlockPublicAcls: false BlockPublicPolicy: false IgnorePublicAcls: false RestrictPublicBuckets: false OwnershipControls: Rules: - ObjectOwnership: ObjectWriter CorsConfiguration: CorsRules: - AllowedHeaders: - "Authorization" AllowedMethods: - GET AllowedOrigins: - "*" MaxAge: 3000 - AllowedHeaders: - "*" AllowedMethods: - POST AllowedOrigins: - "*" ExposedHeaders: - x-amz-request-id - x-amz-id-2 - AllowedHeaders: - "*" AllowedMethods: - PUT AllowedOrigins: - "*" ExposedHeaders: - x-amz-request-id - x-amz-id-2 MetricsConfigurations: - Id: EntireBucket WebsiteConfiguration: IndexDocument: index.html ErrorDocument: error.html DeletionPolicy: Delete CFDeployerRole: Type: AWS::IAM::Role Properties: RoleName: !Sub ${ProjectName}-cloudformationdeployer-role AssumeRolePolicyDocument: Version: 2012-10-17 Statement: - Effect: Allow Principal: Service: - cloudformation.amazonaws.com - lambda.amazonaws.com Action: - sts:AssumeRole Path: / CFDeployerPolicy: Type: AWS::IAM::Policy Properties: PolicyName: !Sub ${ProjectName}-cloudformationdeployer-policy PolicyDocument: Version: 2012-10-17 Statement: - Sid: General Effect: Allow Action: - iam:CreateRole - iam:AttachRolePolicy - iam:DetachRolePolicy - iam:DeleteRole - iam:GetRole - iam:PassRole - iam:CreatePolicy - iam:CreatePolicyVersion - iam:DeletePolicy - iam:DeletePolicyVersion - iam:GetPolicy - iam:GetPolicyVersion - iam:ListPolicyVersions - lambda:CreateFunction - lambda:GetFunction - lambda:DeleteFunction - lambda:GetFunctionConfiguration - lambda:AddPermission - lambda:RemovePermission - lambda:UpdateFunctionCode - lambda:UpdateFunctionConfiguration - lambda:ListTags - lambda:TagResource - apigateway:POST - apigateway:PATCH - apigateway:DELETE - apigateway:GET - apigateway:PUT - logs:* Resource: "*" - Sid: CodePipeline Effect: Allow Action: - codepipeline:StartPipelineExecution Resource: "*" - Sid: CloudFormation Effect: Allow Action: - cloudformation:* Resource: "*" - Sid: S3 Effect: Allow Action: - s3:PutObject - s3:GetBucketPolicy - s3:GetObject - s3:DeleteObject - s3:ListBucket Resource: - !Sub 'arn:aws:s3:::${ProjectName}-pipeline-artifacts-${AWS::AccountId}/*' - !Sub 'arn:aws:s3:::${ProjectName}-pipeline-artifacts-${AWS::AccountId}' - !Sub 'arn:aws:s3:::${ProjectName}-pipeline-source-${AWS::AccountId}/*' - !Sub 'arn:aws:s3:::${ProjectName}-pipeline-source-${AWS::AccountId}' Roles: - !Ref CFDeployerRole CodePipelinePolicy: Type: AWS::IAM::ManagedPolicy Properties: ManagedPolicyName: !Sub ${ProjectName}-CodePipeline Path: "/" PolicyDocument: Version: "2012-10-17" Statement: - Sid: S3 Effect: Allow Action: - s3:PutObject - s3:GetBucketPolicy - s3:GetObject - s3:DeleteObject - s3:ListBucket Resource: - !Sub 'arn:aws:s3:::${ProjectName}-pipeline-artifacts-${AWS::AccountId}/*' - !Sub 'arn:aws:s3:::${ProjectName}-pipeline-artifacts-${AWS::AccountId}' - !Sub 'arn:aws:s3:::${ProjectName}-cloudeecms-editor-${AWS::AccountId}/*' - !Sub 'arn:aws:s3:::${ProjectName}-cloudeecms-editor-${AWS::AccountId}' - Sid: S3PipelineSource Effect: Allow Action: - s3:* Resource: - !Sub 'arn:aws:s3:::${ProjectName}-pipeline-source-${AWS::AccountId}/*' - !Sub 'arn:aws:s3:::${ProjectName}-pipeline-source-${AWS::AccountId}' - Sid: cloudformation Effect: Allow Action: [ "cloudformation:DescribeStacks", "cloudformation:CreateStack", "cloudformation:UpdateStack", "cloudformation:DescribeChangeSet", "cloudformation:CreateChangeSet", "cloudformation:ExecuteChangeSet", "cloudformation:DeleteChangeSet" ] Resource: - !Sub 'arn:aws:cloudformation:${AWS::Region}:${AWS::AccountId}:stack/${AWS::StackName}*' - Sid: codebuild Effect: Allow Action: [ "codebuild:StartBuild", "codebuild:BatchGetBuilds" ] Resource: - !Sub 'arn:aws:codebuild:${AWS::Region}:${AWS::AccountId}:project/${ProjectName}-buildproject-backend' - !Sub 'arn:aws:codebuild:${AWS::Region}:${AWS::AccountId}:project/${ProjectName}-buildproject-frontend' - Sid: iam Effect: Allow Action: iam:PassRole Resource: !GetAtt CFDeployerRole.Arn CodePipelineRole: Type: 'AWS::IAM::Role' Properties: ManagedPolicyArns: [ !Ref CodePipelinePolicy ] AssumeRolePolicyDocument: Statement: - Action: - 'sts:AssumeRole' Effect: Allow Principal: Service: - "codepipeline.amazonaws.com" Path: / RoleName: !Sub ${ProjectName}_CodePipeline_Role CodeBuildPolicy: Type: AWS::IAM::ManagedPolicy Properties: ManagedPolicyName: !Sub ${ProjectName}-CodeBuildAccess_Buckets Path: "/" PolicyDocument: Version: "2012-10-17" Statement: - Sid: S3 Effect: Allow Action: - s3:PutObject - s3:DeleteObject - s3:GetBucketPolicy - s3:GetObject - s3:ListBucket - s3:PutObjectAcl Resource: - !Sub 'arn:aws:s3:::${ProjectName}-pipeline-artifacts-${AWS::AccountId}/*' - !Sub 'arn:aws:s3:::${ProjectName}-pipeline-artifacts-${AWS::AccountId}' - !Sub 'arn:aws:s3:::${ProjectName}-pipeline-source-${AWS::AccountId}/*' - !Sub 'arn:aws:s3:::${ProjectName}-pipeline-source-${AWS::AccountId}' - !Sub 'arn:aws:s3:::${ProjectName}-webpages-bucket-${AWS::AccountId}/*' - !Sub 'arn:aws:s3:::${ProjectName}-webpages-bucket-${AWS::AccountId}' - !Sub 'arn:aws:s3:::${ProjectName}-cloudeecms-editor-${AWS::AccountId}/*' - !Sub 'arn:aws:s3:::${ProjectName}-cloudeecms-editor-${AWS::AccountId}' - Sid: cloudwatch Effect: Allow Action: [ "logs:CreateLogStream", "logs:PutLogEvents", "logs:CreateLogGroup" ] Resource: !Sub 'arn:aws:logs:${AWS::Region}:${AWS::AccountId}:log-group:/aws/codebuild/${ProjectName}-*' - Sid: cloudformation Effect: Allow Action: [ "cloudformation:DescribeStacks" ] Resource: !Sub 'arn:aws:cloudformation:${AWS::Region}:${AWS::AccountId}:stack/${AWS::StackName}-Backend*' - Sid: dynamodb Effect: Allow Action: [ "dynamodb:GetItem", "dynamodb:PutItem", "dynamodb:DeleteItem", "dynamodb:UpdateItem" ] Resource: !Sub 'arn:aws:dynamodb:${AWS::Region}:${AWS::AccountId}:table/${ProjectName}-CMS' CodeBuildRole: Type: 'AWS::IAM::Role' Properties: ManagedPolicyArns: [ !Ref CodeBuildPolicy ] AssumeRolePolicyDocument: Statement: - Action: - 'sts:AssumeRole' Effect: Allow Principal: Service: - "codebuild.amazonaws.com" Path: / RoleName: !Sub ${ProjectName}_CodeBuild_Role CodeBuildProjectBackend: Type: AWS::CodeBuild::Project Properties: Source: Type: CODEPIPELINE BuildSpec: buildspec_1_backend.yml ServiceRole: !Ref CodeBuildRole Name: !Sub ${ProjectName}-buildproject-backend Artifacts: Type: CODEPIPELINE Environment: Type: LINUX_CONTAINER ComputeType: BUILD_GENERAL1_SMALL Image: aws/codebuild/standard:6.0 EnvironmentVariables: - Name: PIPELINE_BUCKET Type: PLAINTEXT Value: !Sub ${ProjectName}-pipeline-artifacts-${AWS::AccountId} TimeoutInMinutes: 10 CodeBuildProjectFrontend: Type: AWS::CodeBuild::Project Properties: Source: Type: CODEPIPELINE BuildSpec: buildspec_2_frontend.yml ServiceRole: !Ref CodeBuildRole Name: !Sub ${ProjectName}-buildproject-frontend Artifacts: Type: CODEPIPELINE Environment: Type: LINUX_CONTAINER ComputeType: BUILD_GENERAL1_SMALL Image: aws/codebuild/standard:6.0 EnvironmentVariables: - Name: S3_BUCKET Type: PLAINTEXT Value: !Sub ${ProjectName}-pipeline-artifacts-${AWS::AccountId} - Name: S3BUCKET_CDN Type: PLAINTEXT Value: !Sub ${ProjectName}-cloudeecms-cdn-${AWS::AccountId} - Name: S3BUCKET_TEST Type: PLAINTEXT Value: !Sub ${ProjectName}-cloudeecms-test-${AWS::AccountId} - Name: S3BUCKET_PROD Type: PLAINTEXT Value: !Sub ${ProjectName}-cloudeecms-prod-${AWS::AccountId} - Name: S3BUCKET_PROD_URL Type: PLAINTEXT Value: !GetAtt ProdBucket.WebsiteURL - Name: S3BUCKET_TEST_URL Type: PLAINTEXT Value: !GetAtt TestBucket.WebsiteURL - Name: CFDIST_CDN_ID Type: PLAINTEXT Value: !Ref CloudfrontDistCDN - Name: CFDIST_PROD_ID Type: PLAINTEXT Value: !Ref CloudfrontDistProd - Name: CFDIST_CDN_URL Type: PLAINTEXT Value: !Sub ${CdnURL} - Name: CFDIST_PROD_URL Type: PLAINTEXT Value: !Sub ${ProdURL} - Name: DYNAMO_TABLE_NAME Type: PLAINTEXT Value: !Sub ${ProjectName}-CMS - Name: STACKNAME Type: PLAINTEXT Value: !Sub ${AWS::StackName}-Backend - Name: S3BUCKET_ADMIN Type: PLAINTEXT Value: !Sub ${ProjectName}-cloudeecms-editor-${AWS::AccountId} - Name: ADMINBUCKETURL Type: PLAINTEXT Value: !GetAtt AdminBucket.RegionalDomainName - Name: EnableOAUTH Type: PLAINTEXT Value: !Sub ${EnableOAUTH} - Name: OAUTHDOMAIN Type: PLAINTEXT Value: !Sub '${UserPoolDomain}.auth.${AWS::Region}.amazoncognito.com' - Name: OAUTHLoginLabel Type: PLAINTEXT Value: !Sub ${OAUTHLoginLabel} - Name: REGION Type: PLAINTEXT Value: !Sub ${AWS::Region} - Name: ONLINEUPDATE Type: PLAINTEXT Value: "true" TimeoutInMinutes: 15 Pipeline: Type: AWS::CodePipeline::Pipeline DependsOn: CodePipelineSourceBucket Properties: Tags: - Key: "InitialVersion" Value: !GetAtt StartFirstRunLambda.version - Key: "SourceLoaded" Value: !GetAtt StartFirstRunLambda.status RoleArn: !GetAtt CodePipelineRole.Arn Name: !Sub ${ProjectName}-pipeline Stages: - Name: Source Actions: - Name: SourceS3ZIP ActionTypeId: Category: Source Owner: AWS Version: '1' Provider: S3 Configuration: S3Bucket: !Ref CodePipelineSourceBucket S3ObjectKey: "codepipeline/cloudeecms/deploy.zip" PollForSourceChanges: 'false' OutputArtifacts: - Name: SourceArtifact RunOrder: 1 - Name: Build Actions: - Name: Build ActionTypeId: Category: Build Owner: AWS Version: '1' Provider: CodeBuild Configuration: ProjectName: !Ref CodeBuildProjectBackend InputArtifacts: - Name: SourceArtifact OutputArtifacts: - Name: BuildArtifact RunOrder: 1 - Name: Deploy-Backend Actions: - Name: Deploy-Backend-Functions ActionTypeId: Category: Deploy Owner: AWS Version: '1' Provider: CloudFormation Configuration: ChangeSetName: !Sub ${ProjectName}-Backend-ChangeSet ActionMode: CHANGE_SET_REPLACE StackName: !Sub ${AWS::StackName}-Backend Capabilities: CAPABILITY_NAMED_IAM ParameterOverrides: !Sub '{"CognitoUserPoolID": "${UserPool}", "CognitoUserPoolARN": "${UserPool.Arn}", "CognitoClientID": "${UserPoolClient}", "DBTableName": "${ProjectName}-CMS", "AdminBucket": "${AdminBucket}", "TestBucket": "${TestBucket}", "ProdBucket": "${ProdBucket}", "CDNBucket": "${CDNBucket}", "PipelineName": "${ProjectName}-pipeline", "PipelineBucket": "${CodePipelineSourceBucket}", "CloudFrontProdDistId": "${CloudfrontDistProd}", "CloudFrontCDNDistId": "${CloudfrontDistCDN}"}' TemplatePath: BuildArtifact::outputSAMTemplate_backend.yaml RoleArn: !GetAtt CFDeployerRole.Arn InputArtifacts: - Name: BuildArtifact OutputArtifacts: - Name: ChangeSetArtifact RunOrder: 1 - Name: ExecuteChangeSet-Backend ActionTypeId: Category: Deploy Owner: AWS Version: '1' Provider: CloudFormation Configuration: ChangeSetName: !Sub ${ProjectName}-Backend-ChangeSet ActionMode: CHANGE_SET_EXECUTE StackName: !Sub ${AWS::StackName}-Backend RoleArn: !GetAtt CFDeployerRole.Arn InputArtifacts: - Name: ChangeSetArtifact OutputArtifacts: - Name: ExecArtifact RunOrder: 2 - Name: Compile-Frontend Actions: - Name: Build ActionTypeId: Category: Build Owner: AWS Version: '1' Provider: CodeBuild Configuration: ProjectName: !Ref CodeBuildProjectFrontend InputArtifacts: - Name: SourceArtifact OutputArtifacts: - Name: FrontendArtifact RunOrder: 1 ArtifactStore: Location: !Sub ${ProjectName}-pipeline-artifacts-${AWS::AccountId} Type: "S3" DynamoDBTable: Type: AWS::DynamoDB::Table DeletionPolicy: Retain UpdateReplacePolicy: Retain Properties: AttributeDefinitions: - AttributeName: "id" AttributeType: "S" - AttributeName: "otype" AttributeType: "S" - AttributeName: "GSI1SK" AttributeType: "S" GlobalSecondaryIndexes: - IndexName: GSI1-index KeySchema: - AttributeName: otype KeyType: HASH - AttributeName: GSI1SK KeyType: RANGE Projection: ProjectionType: ALL BillingMode: PAY_PER_REQUEST PointInTimeRecoverySpecification: PointInTimeRecoveryEnabled: true KeySchema: - AttributeName: "id" KeyType: "HASH" TableName: !Sub ${ProjectName}-CMS CloudFrontOrigin: Type: AWS::CloudFront::CloudFrontOriginAccessIdentity Properties: CloudFrontOriginAccessIdentityConfig: Comment: !Sub ${ProjectName}-OAI CloudfrontDistCDN: Type: AWS::CloudFront::Distribution DependsOn: CloudFrontOrigin Properties: DistributionConfig: Aliases: - !Ref CdnURL Origins: - DomainName: !GetAtt CDNBucket.DomainName Id: S3Origin S3OriginConfig: OriginAccessIdentity: !Sub "origin-access-identity/cloudfront/${CloudFrontOrigin}" Enabled: true Comment: "CDN Content Delivery Network for CloudeeCMS website" CustomErrorResponses: - ErrorCachingMinTTL: 0 ErrorCode: 403 ResponseCode: 200 ResponsePagePath: /index.html DefaultRootObject: index.html DefaultCacheBehavior: TargetOriginId: S3Origin AllowedMethods: - GET - HEAD ForwardedValues: QueryString: false Cookies: Forward: none ViewerProtocolPolicy: redirect-to-https PriceClass: !Ref CloudFrontParam ViewerCertificate: AcmCertificateArn: !Ref AcmCertificateCDN MinimumProtocolVersion: TLSv1.1_2016 SslSupportMethod: sni-only HttpVersion: http2and3 CloudfrontDistProd: Type: AWS::CloudFront::Distribution DependsOn: CloudFrontOrigin Properties: DistributionConfig: Aliases: - !Ref ProdURL Origins: - DomainName: !GetAtt ProdBucket.DomainName Id: S3Origin S3OriginConfig: OriginAccessIdentity: !Sub "origin-access-identity/cloudfront/${CloudFrontOrigin}" Enabled: true Comment: "CloudeeCMS website" CustomErrorResponses: - ErrorCachingMinTTL: 0 ErrorCode: 403 ResponseCode: 200 ResponsePagePath: /index.html DefaultRootObject: index.html DefaultCacheBehavior: TargetOriginId: S3Origin AllowedMethods: - GET - HEAD ForwardedValues: QueryString: false Cookies: Forward: none ViewerProtocolPolicy: redirect-to-https PriceClass: !Ref CloudFrontParam ViewerCertificate: AcmCertificateArn: !Ref AcmCertificatePROD MinimumProtocolVersion: TLSv1.1_2016 SslSupportMethod: sni-only HttpVersion: http2and3 UserPool: Type: AWS::Cognito::UserPool Properties: UserPoolName: !Sub ${ProjectName}-UserPool AutoVerifiedAttributes: - email AliasAttributes: - 'email' Schema: - Name: email Required: true Mutable: true AdminCreateUserConfig: AllowAdminCreateUserOnly: true UserPoolDomain: Type: AWS::Cognito::UserPoolDomain Properties: Domain: !Sub ${ProjectName}-${AWS::AccountId} UserPoolId: !Ref UserPool UserPoolIdentityProvider: Condition: CognitoIdPCondition Type: AWS::Cognito::UserPoolIdentityProvider Properties: ProviderName: IdP ProviderType: "SAML" ProviderDetails: {"MetadataURL": !Ref SAMLMetadataURL} AttributeMapping: {"email": "http://schemas.xmlsoap.org/ws/2005/05/identity/claims/name", "family_name": "http://schemas.xmlsoap.org/ws/2005/05/identity/claims/surname", "given_name": "http://schemas.xmlsoap.org/ws/2005/05/identity/claims/givenname"} UserPoolId: !Ref UserPool UserPoolClient: Type: AWS::Cognito::UserPoolClient Properties: UserPoolId: !Ref UserPool ClientName: !Sub scms-${ProjectName} GenerateSecret: false RefreshTokenValidity: 30 SupportedIdentityProviders: - !If [CognitoIdPCondition, 'IdP', !Ref 'AWS::NoValue'] CallbackURLs: - "http://localhost:4200/login-redirect" - !Sub https://${AdminBucket.RegionalDomainName}/scms/index.html AllowedOAuthFlows: - code - implicit AllowedOAuthScopes: - openid - email - aws.cognito.signin.user.admin - profile ExplicitAuthFlows: - ALLOW_USER_PASSWORD_AUTH - ALLOW_USER_SRP_AUTH - ALLOW_REFRESH_TOKEN_AUTH PreventUserExistenceErrors: ENABLED ReadAttributes: - address - birthdate - email - email_verified - family_name - gender - given_name - locale - middle_name - name - nickname - phone_number - phone_number_verified - picture - preferred_username - profile - zoneinfo - updated_at - website WriteAttributes: - address - birthdate - email - family_name - gender - given_name - locale - middle_name - name - nickname - phone_number - picture - preferred_username - profile - zoneinfo - updated_at - website CognitoGroupAdmins: Type: AWS::Cognito::UserPoolGroup Properties: Description: CloudeeCMS Full Admins (full access to all functions) GroupName: CloudeeCMS-Admin UserPoolId: !Ref UserPool CognitoGroupLayoutEditors: Type: AWS::Cognito::UserPoolGroup Properties: Description: CloudeeCMS Layout Editors (can edit layouts, layout blocks, micro templates) GroupName: CloudeeCMS-LayoutEditor UserPoolId: !Ref UserPool CognitoGroupUserAdmins: Type: AWS::Cognito::UserPoolGroup Properties: Description: CloudeeCMS User Admins (can view and edit cognito users) GroupName: CloudeeCMS-UserAdmin UserPoolId: !Ref UserPool CognitoAdminUser: DependsOn: UserPool Type: AWS::Cognito::UserPoolUser Properties: DesiredDeliveryMediums: - 'EMAIL' Username: "cloudeecmsadmin" UserPoolId: !Ref UserPool UserAttributes: - Name: email Value: !Sub ${CognitoUserEmail} CognitoAdminGroupMembership1: DependsOn: CognitoAdminUser Type: AWS::Cognito::UserPoolUserToGroupAttachment Properties: GroupName: CloudeeCMS-Admin Username: cloudeecmsadmin UserPoolId: !Ref UserPool CognitoAdminGroupMembership2: DependsOn: CognitoAdminUser Type: AWS::Cognito::UserPoolUserToGroupAttachment Properties: GroupName: CloudeeCMS-UserAdmin Username: cloudeecmsadmin UserPoolId: !Ref UserPool StartFirstRunLambda: Type: Custom::StartFirstRunLambda Properties: ServiceToken: !GetAtt CloudeeFirstRunLambda.Arn Region: !Ref "AWS::Region" CloudeeFirstRunLambda: Type: AWS::Lambda::Function Properties: Description: Run this once to finalize setup of CloudeeCMS Runtime: nodejs18.x Role: !GetAtt CFDeployerRole.Arn Handler: index.handler Timeout: 40 Environment: Variables: PIPELINE_NAME: !Sub ${ProjectName}-pipeline PIPELINE_BUCKET: !Sub ${CodePipelineSourceBucket} WEBAPP_BUCKET: !Sub ${AdminBucket.RegionalDomainName} Code: S3Bucket: "cloudeecms-updates" S3Key: "cloudeecms/firstrun/firstrun_20230607.zip" Outputs: AdminBucket: Value: !Sub 'https://${AdminBucket.RegionalDomainName}/scms/index.html' Export: Name: !Sub "${AWS::StackName}-WebsiteURL"