AWSTemplateFormatVersion: 2010-09-09 Description: AWS Perspective Set Up (SO0075) - Solution - Master Template (uksb-1qbkclgj9) (version:v1.1.4) Transform: AWS::Serverless-2016-10-31 Globals: Api: Cors: AllowMethods: "'GET,POST,OPTIONS,DELETE,PUT'" AllowHeaders: "'Content-Type,X-Amz-Date,Authorization,X-Api-Key,X-Amz-Security-Token'" AllowOrigin: "'*'" Function: Runtime: nodejs12.x Environment: Variables: VERSION: v1.1.4 Parameters: OptOutOfSendingAnonymousUsageMetrics: Type: String Default: 'No' Description: Opt out of sending any anonymous usage metrics to AWS Perspective AllowedValues: - 'No' - 'Yes' AlreadyHaveConfigSetup: Type: String Default: 'No' Description: Is AWS Config set-up within this Region? AllowedValues: - 'No' - 'Yes' ConstraintDescription: Please specify if this Region has AWS Config set-up (Yes / No) CreateOpensearchServiceRole: Type: String Default: 'Yes' Description: Do you need an OpenSearch Service Role to be created? You can check for a Role called AWSServiceRoleForAmazonElasticsearchService in your account. If it exists then you do NOT need one creating AllowedValues: - 'No' - 'Yes' ConstraintDescription: Please specify if this account has AWS Config set-up (Yes / No) AdminUserEmailAddress: Type: String AllowedPattern: "^[\\w!#$%&\u2019*+/=?`{|}~^-]+(?:\\.[\\w!#$%&\u2019*+/=?`{|}~^-]+)*@(?:[a-zA-Z0-9-]+\\\ .)+[a-zA-Z]{2,6}$" ConstraintDescription: Must be an email address Description: A user will be created in the UI. This email address will be used to send your username and password. NeptuneInstanceClass: Type: String Description: Neptune DB instance class that will be used for primary and all replicas. Changing this will affect the cost of running this solution. Default: db.r5.large AllowedValues: - db.t3.medium - db.r4.large - db.r4.xlarge - db.r4.2xlarge - db.r4.4xlarge - db.r4.8xlarge - db.r5.large - db.r5.xlarge - db.r5.2xlarge - db.r5.4xlarge - db.r5.8xlarge - db.r5.12xlarge CreateNeptuneReplica: Type: String AllowedValues: - 'No' - 'Yes' Default: 'No' Description: If you would like a read replica creating in a separate AZ. Please select 'Yes'. This will increase the cost of running the solution. OpensearchInstanceType: Description: The instance type for OpenSearch data nodes Type: String Default: m6g.large.elasticsearch AllowedValues: - t3.small.elasticsearch - t3.medium.elasticsearch - t2.micro.elasticsearch - t2.small.elasticsearch - t2.medium.elasticsearch - m5.large.elasticsearch - m5.xlarge.elasticsearch - m5.2xlarge.elasticsearch - m5.4xlarge.elasticsearch - m5.12xlarge.elasticsearch - m4.large.elasticsearch - m4.xlarge.elasticsearch - m4.2xlarge.elasticsearch - m4.4xlarge.elasticsearch - m4.10xlarge.elasticsearch - m6g.large.elasticsearch - m6g.xlarge.elasticsearch - m6g.2xlarge.elasticsearch - m6g.4xlarge.elasticsearch - m6g.8xlarge.elasticsearch - m6g.12xlarge.elasticsearch - c5.large.elasticsearch - c5.xlarge.elasticsearch - c5.2xlarge.elasticsearch - c5.4xlarge.elasticsearch - c5.9xlarge.elasticsearch - c5.19xlarge.elasticsearch - c4.large.elasticsearch - c4.xlarge.elasticsearch - c4.2xlarge.elasticsearch - c4.4xlarge.elasticsearch - c4.8xlarge.elasticsearch - c6g.large.elasticsearch - c6g.xlarge.elasticsearch - c6g.2xlarge.elasticsearch - c6g.4xlarge.elasticsearch - c6g.8xlarge.elasticsearch - c6g.12xlarge.elasticsearch - r5.large.elasticsearch - r5.xlarge.elasticsearch - r5.2xlarge.elasticsearch - r5.4xlarge.elasticsearch - r5.12xlarge.elasticsearch - r4.large.elasticsearch - r4.xlarge.elasticsearch - r4.2xlarge.elasticsearch - r4.4xlarge.elasticsearch - r4.8xlarge.elasticsearch - r4.16xlarge.elasticsearch - r3.large.elasticsearch - r3.xlarge.elasticsearch - r3.2xlarge.elasticsearch - r3.4xlarge.elasticsearch - r3.8xlarge.elasticsearch - i3.large.elasticsearch - i3.xlarge.elasticsearch - i3.2xlarge.elasticsearch - i3.4xlarge.elasticsearch - i3.8xlarge.elasticsearch - i3.16xlarge.elasticsearch OpensearchMultiAz: Description: Deploys the OpenSearch cluster across two Availability Zones (AZs) in the same region to prevent data loss and minimize downtime in the event of node or data center failure. This will increase the cost of running the solution Type: String Default: 'No' AllowedValues: - 'Yes' - 'No' CreateAPIGatewayCloudWatchLogsRole: Type: String Default: 'Yes' Description: "'Do you need an API Gateway CloudwatchLogs Role to be created? \n\ If set to Yes, Perspective will create a role and overwrite the existing ApiGateway\ \ Accout CloudWatchLogsRoleArn property.\nSet this to No if you already have\ \ an existing role set. You can check if a value is set using the `aws apigateway\ \ get-account` command.\nThe role created by Perspective will be retained upon\ \ deletion of the Perspective stack. \nThis is to prevent the interruption of\ \ logging for other API Gateways in a region.\n" AllowedValues: - 'Yes' - 'No' AthenaWorkgroup: Type: String Default: primary Description: Specify the name of the Athena Workgroup you would like to use. By default it will use 'primary'. Conditions: CreateAPIGatewayCloudWatchLogsRoleCondition: Fn::Equals: - Ref: CreateAPIGatewayCloudWatchLogsRole - 'Yes' Resources: LambdaExecutionRole: Type: AWS::IAM::Role Metadata: wildcard_resources: Certain actions required by this role demand wildcard resource to be defined cfn_nag: rules_to_suppress: - id: W11 reason: Some actions require wildcard resources as stated above. - id: W76 reason: Policy is complex as it is used for executing a cloudformation template which requires a large number of permissions - id: F3 reason: We have locked it down as far as we can. Properties: AssumeRolePolicyDocument: Statement: - Effect: Allow Principal: Service: - lambda.amazonaws.com Action: sts:AssumeRole Path: / ManagedPolicyArns: - arn:aws:iam::aws:policy/service-role/AWSLambdaBasicExecutionRole - arn:aws:iam::aws:policy/NeptuneFullAccess Policies: - PolicyName: lambda-execution-perspective PolicyDocument: Version: '2012-10-17' Statement: - Effect: Allow Action: - events:PutRule - events:DescribeRule - events:PutTargets Resource: '*' - Effect: Allow Action: iam:PassRole Resource: Fn::Sub: arn:aws:iam::${AWS::AccountId}:role/* - Effect: Allow Action: - iam:GetRole - iam:CreateRole - iam:PutRolePolicy - iam:getRolePolicy - iam:AttachRolePolicy - iam:CreateServiceLinkedRole - iam:ListRoles - iam:GetPolicy - iam:CreatePolicy - iam:CreateInstanceProfile - iam:AddRoleToInstanceProfile - iam:DeleteRolePolicy - iam:DeleteRole - iam:DetachRolePolicy Resource: '*' - Effect: Allow Action: - cognito-idp:CreateUserPoolClient - cognito-identity:SetIdentityPoolRoles - cognito-idp:AdminCreateUser Resource: - Fn::Sub: arn:aws:cognito-identity:${AWS::Region}:${AWS::AccountId}:identitypool/${PerspectiveCognitoIdentityPool} - Fn::GetAtt: - PerspectiveCognitoUserPool - Arn - Effect: Allow Action: - dynamodb:CreateTable - dynamodb:DeleteTable - dynamodb:DescribeTable - dynamodb:DescribeContinuousBackups - dynamodb:UpdateContinuousBackups Resource: Fn::Sub: arn:aws:dynamodb:${AWS::Region}:${AWS::AccountId}* - Effect: Allow Action: - s3:Get* - s3:List* - s3:Put* - s3:Create* - s3:DeleteBucket - s3:DeleteBucketPolicy Resource: arn:aws:s3:::* - Effect: Allow Action: sts:AssumeRole Resource: - Fn::Sub: arn:aws:iam::${AWS::AccountId}:role/*LambdaExecutionRole-* - Effect: Allow Action: - cloudformation:CreateStack - cloudformation:CreateChangeSet - cloudformation:DescribeStackResources - cloudformation:UpdateStack - cloudformation:UpdateTerminationProtection Resource: Fn::Sub: arn:aws:cloudformation:${AWS::Region}:* - Effect: Allow Action: - ssm:GetParameters - ssm:PutParameter - ssm:AddTagsToResource Resource: Fn::Sub: arn:aws:ssm:${AWS::Region}:${AWS::AccountId}* - Effect: Allow Action: - config:PutConfigurationAggregator - config:PutConfigRule Resource: Fn::Sub: arn:aws:config:${AWS::Region}:${AWS::AccountId}* - Effect: Allow Action: - config:PutDeliveryChannel - config:DescribeConfigurationRecorders - config:PutConfigurationRecorder - config:StartConfigurationRecorder - config:DescribeConfigurationAggregators Resource: '*' - Effect: Allow Action: - ec2:AllocateAddress - ec2:DescribeAddresses - ec2:CreateVpc - ec2:DescribeVpcEndpoints - ec2:DescribeVpcs - ec2:ModifyVpcAttribute - ec2:CreateRouteTable - ec2:CreateSubnet - ec2:CreateNetworkAcl - ec2:CreateInternetGateway - ec2:DescribeRouteTables - ec2:DescribeNetworkAcls - ec2:CreateNetworkAclEntry - ec2:DescribeSubnets - ec2:DescribeInternetGateways - ec2:ModifySubnetAttribute - ec2:AttachInternetGateway - ec2:ReplaceNetworkAclAssociation - ec2:AssociateRouteTable - ec2:CreateNatGateway - ec2:DescribeNatGateways - ec2:DescribeSecurityGroups - ec2:CreateSecurityGroup - ec2:CreateFlowLogs - ec2:DescribeFlowLogs Resource: '*' - Effect: Allow Action: - ec2:CreateVpcEndpoint - ec2:CreateTags - ec2:CreateRoute - ec2:AuthorizeSecurityGroupIngress - ec2:RevokeSecurityGroupEgress - ec2:AuthorizeSecurityGroupEgress Resource: Fn::Sub: arn:aws:ec2:${AWS::Region}:${AWS::AccountId}* - Effect: Allow Action: - lambda:CreateFunction - lambda:DeleteFunction - lambda:DeleteFunctionConcurrency - lambda:RemovePermission - lambda:GetFunctionConfiguration - lambda:GetFunction - lambda:InvokeFunction - lambda:UpdateFunctionCode - lambda:AddPermission - lambda:PublishLayerVersion - lambda:GetLayerVersion - lambda:EnableReplication - lambda:ListTags - lambda:TagResource - lambda:UntagResource - lambda:DeleteLayerVersion - lambda:UpdateFunctionConfiguration - lambda:PutFunctionConcurrency - lambda:DeleteFunctionConcurrency Resource: Fn::Sub: arn:aws:lambda:*:${AWS::AccountId}* - Effect: Allow Action: - kms:List* Resource: '*' - Effect: Allow Action: - kms:Describe* - kms:Enable* - kms:Get* Resource: Fn::Sub: arn:aws:kms:${AWS::Region}:${AWS::AccountId}* - Effect: Allow Action: - SNS:CreateTopic - SNS:GetTopicAttributes - SNS:Subscribe Resource: Fn::Sub: arn:aws:sns:${AWS::Region}:${AWS::AccountId}* - Effect: Allow Action: - rds:CreateDBClusterParameterGroup - rds:CreateDBInstance - rds:CreateDBSubnetGroup - rds:CreateDBParameterGroup - rds:ModifyDBClusterParameterGroup - rds:ModifyDBParameterGroup - rds:DescribeDBClusterParameterGroups - rds:DescribeDBParameterGroups - rds:RemoveTagsFromResource - rds:AddTagsToResource - rds:CreateDBCluster Resource: Fn::Sub: arn:aws:rds:${AWS::Region}:${AWS::AccountId}* - Effect: Allow Action: - rds:DescribeEngineDefaultClusterParameters - rds:DescribeEngineDefaultParameters Resource: '*' - Effect: Allow Action: - cloudwatch:PutMetricAlarm - cloudwatch:DescribeAlarms Resource: Fn::Sub: arn:aws:cloudwatch:${AWS::Region}:${AWS::AccountId}:alarm:* - Effect: Allow Action: - es:CreateElasticsearchDomain - es:DescribeElasticsearchDomain - es:UpdateElasticsearchDomainConfig - es:AddTags - es:UpgradeElasticsearchDomain Resource: Fn::Sub: arn:aws:es:${AWS::Region}:${AWS::AccountId}:domain/* - Effect: Allow Action: - neptune:ModifyDBInstance Resource: Fn::Sub: arn:${AWS::Partition}:neptune-db:${AWS::Region}:${AWS::AccountId}:db:* - Effect: Allow Action: - cloudfront:CreateCloudFrontOriginAccessIdentity - cloudfront:CreateDistribution - cloudfront:GetCloudFrontOriginAccessIdentity - cloudfront:TagResource - cloudfront:GetDistribution - cloudfront:CreateInvalidation - cloudfront:CreateFunction - cloudfront:DeleteFunction - cloudfront:DescribeFunction - cloudfront:GetFunction - cloudfront:ListFunctions - cloudfront:UpdateFunction - cloudfront:TestFunction - cloudfront:PublishFunction - cloudfront:GetDistribution - cloudfront:GetDistributionConfig - cloudfront:ListTagsForResource - cloudfront:UpdateDistribution Resource: '*' - Effect: Allow Action: - apigateway:GET - apigateway:POST - apigateway:PUT - apigateway:PATCH - apigateway:DELETE Resource: - Fn::Sub: arn:aws:execute-api:${AWS::Region}:${AWS::AccountId}:${PerspectiveWebRestAPI}/* - Fn::Sub: arn:aws:execute-api:${AWS::Region}:${AWS::AccountId}:${ServerGremlinAPI}/* - Fn::Sub: arn:aws:execute-api:${AWS::Region}:${AWS::AccountId}:${PerspectiveDrawioWebRestAPI}/* - Fn::Sub: arn:aws:apigateway:${AWS::Region}::/restapis/${PerspectiveWebRestAPI}/* - Fn::Sub: arn:aws:apigateway:${AWS::Region}::/restapis/${ServerGremlinAPI}/* - Fn::Sub: arn:aws:apigateway:${AWS::Region}::/restapis/${PerspectiveDrawioWebRestAPI}/* - Fn::Sub: arn:aws:apigateway:${AWS::Region}::/account - Effect: Allow Action: - codepipeline:CreatePipeline - codepipeline:GetPipeline - codepipeline:GetPipelineState - codepipeline:TagResource Resource: Fn::Sub: arn:aws:codepipeline:${AWS::Region}:${AWS::AccountId}* - Effect: Allow Action: - codebuild:BatchGetProjects - codebuild:CreateProject - codebuild:UpdateProject Resource: Fn::Sub: arn:aws:codebuild:${AWS::Region}:${AWS::AccountId}* - Effect: Allow Action: - ecr:ListImages - ecr:PutImage - ecr:DescribeImages - ecr:CreateRepository - ecr:DescribeRepositories - ecr:ListTagsForResource - ecr:PutImageScanningConfiguration - ecr:PutLifecyclePolicy - ecr:SetRepositoryPolicy - ecr:PutImageScanningConfiguration - ecr:TagResource Resource: Fn::Sub: arn:aws:ecr:${AWS::Region}:${AWS::AccountId}:repository/* - Effect: Allow Action: - ecs:CreateCluster - ecs:CreateTaskSet - ecs:ListClusters - ecs:ListServices - ecs:RegisterTaskDefinition - ecs:DeregisterTaskDefinition Resource: '*' - Effect: Allow Action: - ecs:CreateService - ecs:DeleteTaskSet - ecs:DescribeClusters - ecs:DescribeTasks - ecs:DescribeTaskSets - ecs:ListTasks - ecs:TagResource - ecs:UpdateTaskSet Resource: Fn::Sub: arn:aws:ecs:${AWS::Region}:${AWS::AccountId}* - Effect: Allow Action: - logs:CreateLogStream - logs:DeleteLogGroup - logs:GetLogEvents - logs:DescribeLogStreams - logs:DescribeLogGroups - logs:PutRetentionPolicy - logs:PutLogEvents Resource: Fn::Sub: arn:aws:logs:${AWS::Region}:${AWS::AccountId}:log-group:* - Effect: Allow Action: - logs:CreateLogGroup Resource: '*' - Effect: Allow Action: - appsync:TagResource - appsync:CreateGraphqlApi - appsync:GetGraphqlApi - appsync:StartSchemaCreation - appsync:GetSchemaCreationStatus - appsync:CreateDataSource - appsync:GetDataSource - appsync:CreateResolver Resource: '*' - Effect: Allow Action: - glue:CreateDatabase - glue:CreateTable - glue:CreateCrawler - glue:UpdateCrawler Resource: Fn::Sub: arn:aws:glue:${AWS::Region}:${AWS::AccountId}:* LambdaSetup: Metadata: cfn_nag: rules_to_suppress: - id: W89 reason: Not applicable - id: W92 reason: Not applicable Type: AWS::Serverless::Function Properties: Handler: index.handler CodeUri: Bucket: Fn::Sub: solutions-${AWS::Region} Key: aws-perspective/v1.1.4/setup.zip Description: Custom Lambda resource for the Perspective Cloudformation Stack MemorySize: 1024 Runtime: nodejs12.x Role: Fn::GetAtt: - LambdaExecutionRole - Arn Environment: Variables: STACK_NAME: Fn::Sub: ${AWS::StackName} ANONYMOUS_METRIC_OPT_OUT: Ref: OptOutOfSendingAnonymousUsageMetrics NEPTUNE_INSTANCE_CLASS: Ref: NeptuneInstanceClass CREATE_READ_REPLICA: Ref: CreateNeptuneReplica OPENSEARCH_INSTANCE_TYPE: Ref: OpensearchInstanceType OPENSEARCH_MULTI_AZ: Ref: OpensearchMultiAz ACCOUNT_ID: Ref: AWS::AccountId API_GATEWAY: Fn::Sub: https://${PerspectiveWebRestAPI}.execute-api.${AWS::Region}.amazonaws.com/Prod SERVER_API_GATEWAY: Fn::Sub: https://${ServerGremlinAPI}.execute-api.${AWS::Region}.amazonaws.com/Prod/ DRAWIO_API_GATEWAY: Fn::Sub: https://${PerspectiveDrawioWebRestAPI}.execute-api.${AWS::Region}.amazonaws.com/Prod/ COGNITO_IDENTITY_POOL: Ref: PerspectiveCognitoIdentityPool COGNITO_USER_POOL_ID: Ref: PerspectiveCognitoUserPool COGNITO_USER_POOL_WEB_CLIENT_ID: Ref: UserPoolClient DEPLOYMENT_BUCKET: Fn::Sub: solutions-${AWS::Region} DEPLOYMENT_BUCKET_KEY: aws-perspective/v1.1.4 COST_AND_USAGE_REPORT_BUCKET: Ref: CostAndUsageReportBucket COST_AND_USAGE_RESULTS_BUCKET: Ref: CostAndUsageAthenaResultsBucket IMAGE_VERSION: aws-perspective-8 REGION: Ref: AWS::Region WEBUI_BUCKET: Ref: WebUIBucket DISCOVERY_BUCKET: Ref: DiscoveryBucket AMPLIFY_STORAGE_BUCKET: Ref: AmplifyStorageBucket ACCESS_LOGS: Ref: AccessLogsBucket DISCOVERY_ARN: Fn::GetAtt: - PerspectiveDiscoveryRole - Arn CONFIG_AGGREGATOR: Fn::Sub: aws-perspective-${AWS::Region}-${AWS::AccountId}-aggregator EXISTING_CONFIG: Ref: AlreadyHaveConfigSetup CREATE_OPENSEARCH_SERVICE_ROLE: Ref: CreateOpensearchServiceRole ATHENA_WORKGROUP: Ref: AthenaWorkgroup APPSYNC_API_ARN: Fn::GetAtt: - PerspectiveAppSyncApi - Arn APPSYNC_API_ID: Fn::GetAtt: - PerspectiveAppSyncApi - ApiId APPSYNC_API_GRAPHQL_URL: Fn::GetAtt: - PerspectiveAppSyncApi - GraphQLUrl VERSION: v1.1.4 Timeout: 900 DeployPerspectiveCustomResource: DependsOn: - DiscoveryCodeBucket - DiscoveryCodeBucketName - PerspectiveCognitoIdentityPoolId - PerspectiveCognitoUserPoolARN - PerspectiveCognitoUserPoolId - PerspectiveDrawioWebRestAPIId - PerspectiveWebRestAPIId - PerspectiveWebRestAPIResourceId - PerspectiveDrawioWebRestAPIResourceId - PerspectiveWebRestAPIRootResourceId - PerspectiveDrawioWebRestAPIRootResourceId - ServerElasticAPIResourceId - ServerGremlinAPIId - ServerGremlinAPIResourceId Type: Custom::Setup Properties: ServiceToken: Fn::GetAtt: - LambdaSetup - Arn Region: Ref: AWS::Region Version: v1.1.4 CleanupBucketFunction: Metadata: cfn_nag: rules_to_suppress: - id: W89 reason: Not applicable - id: W92 reason: Not applicable Type: AWS::Serverless::Function Properties: Handler: cleanup_bucket.handler CodeUri: Bucket: Fn::Sub: solutions-${AWS::Region} Key: aws-perspective/v1.1.4/cleanup-bucket.zip Runtime: python3.8 Description: Custom Lambda resource for emptying S3 buckets on stack deletion Timeout: 900 Policies: - Statement: - Effect: Allow Action: - s3:DeleteObject* - s3:ListBucket* - s3:ListObject* - s3:PutBucketLogging Resource: - Fn::Sub: arn:aws:s3:::${WebUIBucket} - Fn::Sub: arn:aws:s3:::${WebUIBucket}/* - Fn::Sub: arn:aws:s3:::${DiscoveryBucket} - Fn::Sub: arn:aws:s3:::${DiscoveryBucket}/* - Fn::Sub: arn:aws:s3:::${AmplifyStorageBucket} - Fn::Sub: arn:aws:s3:::${AmplifyStorageBucket}/* - Fn::Sub: arn:aws:s3:::${AWS::StackName}-${AWS::AccountId}-${AWS::Region}-cost-bucket - Fn::Sub: arn:aws:s3:::${AWS::StackName}-${AWS::AccountId}-${AWS::Region}-cost-bucket/* - Fn::Sub: arn:aws:s3:::${CostAndUsageReportBucket} - Fn::Sub: arn:aws:s3:::${CostAndUsageReportBucket}/* - Fn::Sub: arn:aws:s3:::${CostAndUsageAthenaResultsBucket} - Fn::Sub: arn:aws:s3:::${CostAndUsageAthenaResultsBucket}/* - Fn::Sub: arn:aws:s3:::${AccessLogsBucket} - Fn::Sub: arn:aws:s3:::${AccessLogsBucket}/* CleanupAccessLoggingBucket: Type: Custom::Setup Properties: ServiceToken: Fn::GetAtt: - CleanupBucketFunction - Arn LogLevel: INFO Bucket: Ref: AccessLogsBucket CleanupCostAndUsageResultsBucket: Type: Custom::Setup Properties: ServiceToken: Fn::GetAtt: - CleanupBucketFunction - Arn LogLevel: INFO Bucket: Ref: CostAndUsageAthenaResultsBucket DependsOn: - CleanupAccessLoggingBucket CleanupCostAndUsageReportBucket: Type: Custom::Setup Properties: ServiceToken: Fn::GetAtt: - CleanupBucketFunction - Arn LogLevel: INFO Bucket: Ref: CostAndUsageReportBucket DependsOn: - CleanupAccessLoggingBucket CleanupWebUIBucket: Type: Custom::Setup Properties: ServiceToken: Fn::GetAtt: - CleanupBucketFunction - Arn LogLevel: INFO Bucket: Ref: WebUIBucket DependsOn: - CleanupAccessLoggingBucket CleanupAmplifyStorageBucket: Type: Custom::Setup Properties: ServiceToken: Fn::GetAtt: - CleanupBucketFunction - Arn LogLevel: INFO Bucket: Ref: AmplifyStorageBucket DependsOn: - CleanupAccessLoggingBucket CleanupDiscoveryBucket: Type: Custom::Setup Properties: ServiceToken: Fn::GetAtt: - CleanupBucketFunction - Arn LogLevel: INFO Bucket: Ref: DiscoveryBucket DependsOn: - CleanupAccessLoggingBucket PerspectiveCognitoIdentityPool: Type: AWS::Cognito::IdentityPool Properties: IdentityPoolName: Fn::Sub: perspective.${AWS::Region}.identitypool AllowUnauthenticatedIdentities: false CognitoIdentityProviders: - ClientId: Ref: UserPoolClient ProviderName: Fn::GetAtt: - PerspectiveCognitoUserPool - ProviderName ServerSideTokenCheck: true PerspectiveCognitoUserPool: Type: AWS::Cognito::UserPool DeletionPolicy: Delete UpdateReplacePolicy: Retain Properties: AdminCreateUserConfig: AllowAdminCreateUserOnly: true UnusedAccountValidityDays: 90 InviteMessageTemplate: EmailMessage: '

Thanks for your interest in AWS Perspective.

Here are your temporary credentials:

Any issues, please get in touch at aws-perspective-team@

' EmailSubject: Welcome to AWS Perspective UserPoolName: Fn::Sub: perspective.${AWS::Region}.userpool AutoVerifiedAttributes: - email Policies: PasswordPolicy: MinimumLength: 6 RequireLowercase: true RequireNumbers: true RequireSymbols: true RequireUppercase: true CognitoUserPoolAdmin: Type: AWS::Cognito::UserPoolUser Properties: Username: admin DesiredDeliveryMediums: - EMAIL UserPoolId: Ref: PerspectiveCognitoUserPool UserAttributes: - Name: email Value: Ref: AdminUserEmailAddress UserPoolClient: Type: AWS::Cognito::UserPoolClient Properties: ClientName: aws-perspective-client-web RefreshTokenValidity: 1 UserPoolId: Ref: PerspectiveCognitoUserPool PreventUserExistenceErrors: ENABLED ApiGatewayCloudWatchLogsRole: Type: AWS::IAM::Role Condition: CreateAPIGatewayCloudWatchLogsRoleCondition DeletionPolicy: Retain Properties: AssumeRolePolicyDocument: Statement: - Effect: Allow Principal: Service: - apigateway.amazonaws.com Action: sts:AssumeRole Path: / ManagedPolicyArns: - arn:aws:iam::aws:policy/service-role/AmazonAPIGatewayPushToCloudWatchLogs Account: Type: AWS::ApiGateway::Account Condition: CreateAPIGatewayCloudWatchLogsRoleCondition Properties: CloudWatchRoleArn: Fn::GetAtt: - ApiGatewayCloudWatchLogsRole - Arn PerspectiveWebRestAPI: Type: AWS::ApiGateway::RestApi Properties: Name: PerspectiveWebRestAPI Description: The API used by Perspective UI FailOnWarnings: true PerspectiveDrawioWebRestAPI: Type: AWS::ApiGateway::RestApi Properties: Name: PerspectiveDrawioWebRestAPI Description: The API used by Perspective UI to generate drawio url FailOnWarnings: true PerspectiveWebOptionMethod: Type: AWS::ApiGateway::Method Properties: ResourceId: Ref: PerspectiveWebResource RestApiId: Ref: PerspectiveWebRestAPI AuthorizationType: NONE HttpMethod: OPTIONS Integration: Type: MOCK IntegrationResponses: - ResponseParameters: method.response.header.Access-Control-Allow-Headers: "'Content-Type,X-Amz-Date,Authorization,X-Api-Key,X-Amz-Security-Token'" method.response.header.Access-Control-Allow-Methods: "'GET,POST,PUT,DELETE,OPTIONS'" method.response.header.Access-Control-Allow-Origin: "'*'" ResponseTemplates: application/json: '' StatusCode: '200' PassthroughBehavior: NEVER RequestTemplates: application/json: '{"statusCode": 200}' MethodResponses: - ResponseModels: application/json: Empty ResponseParameters: method.response.header.Access-Control-Allow-Headers: true method.response.header.Access-Control-Allow-Methods: true method.response.header.Access-Control-Allow-Origin: true StatusCode: '200' PerspectiveDrawioWebOptionMethod: Type: AWS::ApiGateway::Method Properties: ResourceId: Ref: PerspectiveDrawioWebResource RestApiId: Ref: PerspectiveDrawioWebRestAPI AuthorizationType: NONE HttpMethod: OPTIONS Integration: Type: MOCK IntegrationResponses: - ResponseParameters: method.response.header.Access-Control-Allow-Headers: "'Content-Type,X-Amz-Date,Authorization,X-Api-Key,X-Amz-Security-Token'" method.response.header.Access-Control-Allow-Methods: "'GET,POST,PUT,DELETE,OPTIONS'" method.response.header.Access-Control-Allow-Origin: "'*'" ResponseTemplates: application/json: '' StatusCode: '200' PassthroughBehavior: NEVER RequestTemplates: application/json: '{"statusCode": 200}' MethodResponses: - ResponseModels: application/json: Empty ResponseParameters: method.response.header.Access-Control-Allow-Headers: true method.response.header.Access-Control-Allow-Methods: true method.response.header.Access-Control-Allow-Origin: true StatusCode: '200' PerspectiveDrawioWebResource: Type: AWS::ApiGateway::Resource Properties: RestApiId: Ref: PerspectiveDrawioWebRestAPI ParentId: Fn::GetAtt: - PerspectiveDrawioWebRestAPI - RootResourceId PathPart: resources PerspectiveWebResource: Type: AWS::ApiGateway::Resource Properties: RestApiId: Ref: PerspectiveWebRestAPI ParentId: Fn::GetAtt: - PerspectiveWebRestAPI - RootResourceId PathPart: resources PerspectiveAppSyncLoggingRole: Metadata: cfn_nag: rules_to_suppress: - id: W11 reason: CreateLogGroup requires wildcard, but we have locked down actions that we can to resources in region and account Type: AWS::IAM::Role Properties: AssumeRolePolicyDocument: Version: 2012-10-17 Statement: - Effect: Allow Principal: Service: - appsync.amazonaws.com Action: - sts:AssumeRole Policies: - PolicyName: Fn::Sub: ${AWS::StackName}-AWSAppSyncPushToCloudWatchLogsPolicy PolicyDocument: Version: 2012-10-17 Statement: - Effect: Allow Action: - logs:CreateLogGroup - logs:CreateLogStream Resource: '*' - Effect: Allow Action: - logs:PutLogEvents Resource: Fn::Sub: arn:aws:logs:${AWS::Region}:${AWS::AccountId}:log-group:* PerspectiveAppSyncApi: Type: AWS::AppSync::GraphQLApi Properties: Name: Fn::Sub: ${AWS::StackName}-AppSync-api AuthenticationType: AMAZON_COGNITO_USER_POOLS AdditionalAuthenticationProviders: - AuthenticationType: AWS_IAM LogConfig: CloudWatchLogsRoleArn: Fn::GetAtt: - PerspectiveAppSyncLoggingRole - Arn FieldLogLevel: ALL UserPoolConfig: UserPoolId: Ref: PerspectiveCognitoUserPool AwsRegion: Fn::Sub: ${AWS::Region} DefaultAction: ALLOW PerspectiveDiscoveryRole: Metadata: wildcard_resources: We have locked down resources as much as we can. The nature of the role requires read-only access to many services in order to discover what is in the account cfn_nag: rules_to_suppress: - id: W28 reason: Role is for ECS task execution. It defines the actions read-only actions required for the Perspective Discovery process to function - id: W11 reason: We have locked down resources as far as we can. It is read only access. The actions we define require wildcard resources Type: AWS::IAM::Role Properties: AssumeRolePolicyDocument: Statement: - Action: - sts:AssumeRole Effect: Allow Principal: AWS: Fn::Sub: arn:aws:iam::${AWS::AccountId}:root - Action: - sts:AssumeRole Effect: Allow Principal: Service: ecs-tasks.amazonaws.com Version: '2012-10-17' Policies: - PolicyName: perspectiveAutoscaling PolicyDocument: Version: '2012-10-17' Statement: - Action: autoscaling:Describe* Effect: Allow Resource: '*' - PolicyName: perspectiveEC2 PolicyDocument: Version: '2012-10-17' Statement: - Effect: Allow Action: - ec2:Get* Resource: '*' - PolicyName: perspectiveEC2Wildcards PolicyDocument: Version: '2012-10-17' Statement: - Effect: Allow Action: - ec2:Describe* Resource: '*' - PolicyName: perspectiveIAM PolicyDocument: Version: '2012-10-17' Statement: - Effect: Allow Action: - iam:Get* - iam:List* Resource: '*' - PolicyName: perspectiveAPIGateway PolicyDocument: Version: '2012-10-17' Statement: - Effect: Allow Action: - apigateway:Get Resource: arn:aws:apigateway:*::/* - PolicyName: perspectiveLoadBalancers PolicyDocument: Version: '2012-10-17' Statement: - Action: elasticloadbalancing:Describe* Effect: Allow Resource: '*' - PolicyName: perspectiveRDS PolicyDocument: Version: '2012-10-17' Statement: - Effect: Allow Action: - rds:Describe* Resource: '*' - PolicyName: perspectiveLambda PolicyDocument: Version: '2012-10-17' Statement: - Effect: Allow Action: - lambda:List* - lambda:Get* Resource: '*' - PolicyName: perspectiveCloudFormation PolicyDocument: Version: '2012-10-17' Statement: - Effect: Allow Action: - logs:List* - logs:Describe* - logs:Get* Resource: '*' - PolicyName: perspectiveCloudWatch PolicyDocument: Version: '2012-10-17' Statement: - Effect: Allow Action: - cloudwatch:List* - cloudwatch:Describe* - cloudwatch:Get* Resource: '*' - PolicyName: perspectiveECS PolicyDocument: Version: '2012-10-17' Statement: - Effect: Allow Action: - ecs:List* - ecs:Describe* Resource: '*' - PolicyName: perspectiveConfig PolicyDocument: Version: '2012-10-17' Statement: - Effect: Allow Action: - config:Get* - config:Deliver* - config:List* - config:SelectResourceConfig - config:PutDeliveryChannel Resource: '*' - PolicyName: perspectiveCloudtrail PolicyDocument: Version: '2012-10-17' Statement: - Effect: Allow Action: - cloudtrail:GetTrailStatus Resource: Fn::Sub: arn:aws:cloudtrail:${AWS::Region}:${AWS::AccountId}:trail* - PolicyName: perspectiveCloudtrailWildcards PolicyDocument: Version: '2012-10-17' Statement: - Effect: Allow Action: - cloudtrail:DescribeTrails - cloudtrail:LookupEvents Resource: '*' - PolicyName: perspectiveTags PolicyDocument: Version: '2012-10-17' Statement: - Effect: Allow Action: - tag:GetResources - tag:GetTagKeys Resource: '*' - PolicyName: perspective-discovery-data-s3 PolicyDocument: Version: '2012-10-17' Statement: - Effect: Allow Action: - s3:*Object Resource: Fn::Sub: - ${DiscoveryBucketARN}/* - DiscoveryBucketARN: Fn::GetAtt: - DiscoveryBucket - Arn - PolicyName: perspectiveExecuteApi PolicyDocument: Version: '2012-10-17' Statement: - Effect: Allow Action: - execute-api:Invoke Resource: - Fn::Sub: arn:aws:execute-api:${AWS::Region}:${AWS::AccountId}:${PerspectiveWebRestAPI}/* - Fn::Sub: arn:aws:execute-api:${AWS::Region}:${AWS::AccountId}:${ServerGremlinAPI}/* - Fn::Sub: arn:aws:execute-api:${AWS::Region}:${AWS::AccountId}:${PerspectiveDrawioWebRestAPI}/* WebUIBucket: Metadata: cfn_nag: rules_to_suppress: - id: W51 reason: This bucket will get a policy attached to it from another template during deployment. Type: AWS::S3::Bucket Properties: PublicAccessBlockConfiguration: BlockPublicAcls: true BlockPublicPolicy: true IgnorePublicAcls: true RestrictPublicBuckets: true VersioningConfiguration: Status: Enabled BucketEncryption: ServerSideEncryptionConfiguration: - ServerSideEncryptionByDefault: SSEAlgorithm: AES256 LoggingConfiguration: DestinationBucketName: Ref: AccessLogsBucket LogFilePrefix: webui-bucket/ CorsConfiguration: CorsRules: - AllowedHeaders: - '*' AllowedMethods: - GET AllowedOrigins: - '*' Id: PerspectiveCorsRule MaxAge: 3600 WebsiteConfiguration: IndexDocument: index.html ErrorDocument: error.html AmplifyStorageBucket: Type: AWS::S3::Bucket Properties: VersioningConfiguration: Status: Enabled BucketEncryption: ServerSideEncryptionConfiguration: - ServerSideEncryptionByDefault: SSEAlgorithm: AES256 LoggingConfiguration: DestinationBucketName: Ref: AccessLogsBucket LogFilePrefix: amplify-storage-bucket/ CorsConfiguration: CorsRules: - AllowedHeaders: - '*' AllowedMethods: - GET - POST - PUT - DELETE AllowedOrigins: - '*' Id: PerspectiveCorsRule MaxAge: 3600 AmplifyStorageBucketPolicy: Type: AWS::S3::BucketPolicy Properties: Bucket: Ref: AmplifyStorageBucket PolicyDocument: Statement: - Sid: HttpsOnly Action: '*' Effect: Deny Resource: - Fn::Sub: arn:aws:s3:::${AmplifyStorageBucket}/* - Fn::Sub: arn:aws:s3:::${AmplifyStorageBucket} Principal: '*' Condition: Bool: aws:SecureTransport: 'false' AccessLogsBucket: Metadata: cfn_nag: rules_to_suppress: - id: W35 reason: This bucket will contain access logs for all buckets Type: AWS::S3::Bucket Properties: PublicAccessBlockConfiguration: BlockPublicAcls: true BlockPublicPolicy: true IgnorePublicAcls: true RestrictPublicBuckets: true AccessControl: LogDeliveryWrite VersioningConfiguration: Status: Enabled BucketEncryption: ServerSideEncryptionConfiguration: - ServerSideEncryptionByDefault: SSEAlgorithm: AES256 LifecycleConfiguration: Rules: - Id: DeleteAfter45Days Prefix: '' Status: Enabled ExpirationInDays: 45 AccessLogsBucketPolicy: Type: AWS::S3::BucketPolicy Properties: Bucket: Ref: AccessLogsBucket PolicyDocument: Statement: - Sid: HttpsOnly Action: '*' Effect: Deny Resource: - Fn::Sub: arn:aws:s3:::${AccessLogsBucket}/* - Fn::Sub: arn:aws:s3:::${AccessLogsBucket} Principal: '*' Condition: Bool: aws:SecureTransport: 'false' CostAndUsageAthenaResultsBucket: Type: AWS::S3::Bucket Properties: PublicAccessBlockConfiguration: BlockPublicAcls: true BlockPublicPolicy: true IgnorePublicAcls: true RestrictPublicBuckets: true LoggingConfiguration: DestinationBucketName: Ref: AccessLogsBucket LogFilePrefix: cost-and-usage-report-bucket/ AccessControl: Private VersioningConfiguration: Status: Enabled BucketEncryption: ServerSideEncryptionConfiguration: - ServerSideEncryptionByDefault: SSEAlgorithm: AES256 LifecycleConfiguration: Rules: - Id: DeleteAfter7Days Prefix: '' Status: Enabled ExpirationInDays: 7 CostAndUsageAthenaResultsBucketPolicy: Type: AWS::S3::BucketPolicy Properties: Bucket: Ref: CostAndUsageAthenaResultsBucket PolicyDocument: Statement: - Sid: HttpsOnly Action: '*' Effect: Deny Resource: - Fn::Sub: arn:aws:s3:::${CostAndUsageAthenaResultsBucket}/* - Fn::Sub: arn:aws:s3:::${CostAndUsageAthenaResultsBucket} Principal: '*' Condition: Bool: aws:SecureTransport: 'false' CostAndUsageReportBucket: Type: AWS::S3::Bucket Properties: PublicAccessBlockConfiguration: BlockPublicAcls: true BlockPublicPolicy: true IgnorePublicAcls: true RestrictPublicBuckets: true LoggingConfiguration: DestinationBucketName: Ref: AccessLogsBucket LogFilePrefix: cost-and-usage-report-bucket/ AccessControl: Private VersioningConfiguration: Status: Enabled BucketEncryption: ServerSideEncryptionConfiguration: - ServerSideEncryptionByDefault: SSEAlgorithm: AES256 CostAndUsageReportBucketPolicy: Type: AWS::S3::BucketPolicy Properties: Bucket: Ref: CostAndUsageReportBucket PolicyDocument: Statement: - Sid: HttpsOnly Action: '*' Effect: Deny Resource: - Fn::Sub: arn:aws:s3:::${CostAndUsageReportBucket}/* - Fn::Sub: arn:aws:s3:::${CostAndUsageReportBucket} Principal: '*' Condition: Bool: aws:SecureTransport: 'false' DiscoveryBucket: Type: AWS::S3::Bucket Properties: PublicAccessBlockConfiguration: BlockPublicAcls: true BlockPublicPolicy: true IgnorePublicAcls: true RestrictPublicBuckets: true LoggingConfiguration: DestinationBucketName: Ref: AccessLogsBucket LogFilePrefix: discovery-bucket/ AccessControl: Private VersioningConfiguration: Status: Enabled BucketEncryption: ServerSideEncryptionConfiguration: - ServerSideEncryptionByDefault: SSEAlgorithm: AES256 DiscoveryBucketBucketPolicy: Type: AWS::S3::BucketPolicy Properties: Bucket: Ref: DiscoveryBucket PolicyDocument: Statement: - Sid: HttpsOnly Action: '*' Effect: Deny Resource: - Fn::Sub: arn:aws:s3:::${DiscoveryBucket}/* - Fn::Sub: arn:aws:s3:::${DiscoveryBucket} Principal: '*' Condition: Bool: aws:SecureTransport: 'false' PerspectiveDiscoveryRoleArn: Type: AWS::SSM::Parameter Properties: Name: PerspectiveDiscoveryRoleArn Type: String Value: Fn::GetAtt: - PerspectiveDiscoveryRole - Arn PerspectiveCognitoUserPoolId: Type: AWS::SSM::Parameter Properties: Name: PerspectiveCognitoUserPoolId Type: String Value: Ref: PerspectiveCognitoUserPool PerspectiveCognitoIdentityPoolId: Type: AWS::SSM::Parameter Properties: Name: PerspectiveCognitoIdentityPoolId Type: String Value: Ref: PerspectiveCognitoIdentityPool Description: ID for Cognito Identity Pool PerspectiveCognitoUserPoolARN: Type: AWS::SSM::Parameter Properties: Name: PerspectiveCognitoUserPoolARN Type: String Value: Fn::GetAtt: - PerspectiveCognitoUserPool - Arn PerspectiveWebRestAPIId: Type: AWS::SSM::Parameter Properties: Name: PerspectiveWebRestAPIId Type: String Value: Ref: PerspectiveWebRestAPI Description: API Gateway Web UI REST API ID PerspectiveDrawioWebRestAPIId: Type: AWS::SSM::Parameter Properties: Name: PerspectiveDrawioWebRestAPIId Type: String Value: Ref: PerspectiveDrawioWebRestAPI Description: API Gateway Drawio Web UI REST API ID PerspectiveWebRestAPIRootResourceId: Type: AWS::SSM::Parameter Properties: Name: PerspectiveWebRestAPIRootResourceId Type: String Value: Fn::GetAtt: - PerspectiveWebRestAPI - RootResourceId Description: API Gateway Web UI REST API Root Resource ID PerspectiveDrawioWebRestAPIRootResourceId: Type: AWS::SSM::Parameter Properties: Name: PerspectiveDrawioWebRestAPIRootResourceId Type: String Value: Fn::GetAtt: - PerspectiveDrawioWebRestAPI - RootResourceId Description: API Gateway Web UI Drawio REST API Root Resource ID PerspectiveWebRestAPIResourceId: Type: AWS::SSM::Parameter Properties: Name: PerspectiveWebRestAPIResourceId Type: String Value: Ref: PerspectiveWebResource Description: API Gateway Resource ID PerspectiveDrawioWebRestAPIResourceId: Type: AWS::SSM::Parameter Properties: Name: PerspectiveDrawioWebRestAPIResourceId Type: String Value: Ref: PerspectiveDrawioWebResource Description: API Gateway Resource ID for Drawio WebUIBucketName: Type: AWS::SSM::Parameter Properties: Name: WebUIBucketName Type: String Value: Ref: WebUIBucket Description: The name of the bucket where the web ui is deployed. WebUIBucketRegionalDomainName: Type: AWS::SSM::Parameter Properties: Name: WebUIBucketRegionalDomainName Type: String Value: Fn::GetAtt: - WebUIBucket - RegionalDomainName Description: The name of the bucket where the web ui is deployed. DiscoveryCodeBucket: Type: AWS::SSM::Parameter Properties: Name: DiscoveryCodeBucket Type: String Value: Fn::GetAtt: - DiscoveryBucket - Arn Description: The ARN of the bucket where the meta data for the import is stored. DiscoveryCodeBucketName: Type: AWS::SSM::Parameter Properties: Name: DiscoveryCodeBucketName Type: String Value: Ref: DiscoveryBucket Description: The Name of the bucket where the meta data for the import is stored. ServerGremlinAPI: Type: AWS::ApiGateway::RestApi Properties: Name: PerspectiveServerAPI Description: The server zoomAPI FailOnWarnings: true ServerGremlinAPIId: Type: AWS::SSM::Parameter Properties: Name: ServerGremlinAPIId Type: String Value: Ref: ServerGremlinAPI Description: The ID of server API ServerGremlinResource: Type: AWS::ApiGateway::Resource Properties: RestApiId: Ref: ServerGremlinAPI ParentId: Fn::GetAtt: - ServerGremlinAPI - RootResourceId PathPart: resources ServerGremlinAPIResourceId: Type: AWS::SSM::Parameter Properties: Name: ServerGremlinAPIResourceId Type: String Value: Ref: ServerGremlinResource Description: The ARN of the gremlin resource ServerElasticResource: Type: AWS::ApiGateway::Resource Properties: RestApiId: Ref: ServerGremlinAPI ParentId: Fn::GetAtt: - ServerGremlinAPI - RootResourceId PathPart: search ServerElasticAPIResourceId: Type: AWS::SSM::Parameter Properties: Name: ServerElasticAPIResourceId Type: String Value: Ref: ServerElasticResource Description: The ARN of elastic resource Outputs: DrawIOApiUrl: Description: API URL for exporting to DrawIO. Use this to make direct API calls for export to DrawIO functionality Value: Fn::Sub: https://${PerspectiveDrawioWebRestAPI}.execute-api.${AWS::Region}.amazonaws.com/Prod PerspectiveWebUiApiUrl: Description: API URL for Perpective. Use this to make direct API calls Value: Fn::Sub: https://${PerspectiveWebRestAPI}.execute-api.${AWS::Region}.amazonaws.com/Prod