cloudformation.yaml (818 lines of code) (raw):

AWSTemplateFormatVersion: 2010-09-09 Description: gateway Parameters: AMI: Description: AMI to use in the autoscaling group Type: String App: Description: Application name Default: identity-gateway Type: String IdapiBaseUrl: Description: The base url for idapi Type: AWS::SSM::Parameter::Value<String> SignInPageUrl: Description: Sign in page URL used as a fallback if auth redirect retrieval fails. Type: AWS::SSM::Parameter::Value<String> OauthBaseUrl: Description: The base url for social sign-in with google or apple Type: AWS::SSM::Parameter::Value<String> OktaOrgUrl: Description: The org url for interacting with okta APIs Type: AWS::SSM::Parameter::Value<String> MembersDataApiUrl: Description: The url for members-data-api Type: AWS::SSM::Parameter::Value<String> RedisHost: Description: The Redis server URL, used for rate limiting. Type: AWS::SSM::Parameter::Value<String> CertificateArn: Description: ARN of certificate for loadbalancer use. Type: String KeyName: Description: The EC2 Key Pair to allow SSH access to the instances Type: AWS::EC2::KeyPair::KeyName AlarmEmailAddress: Description: Email address to send CloudWatch alerts Type: String PrivateVpcSubnets: Description: Private VPC Subnet for the EC2 instances. Type: List<AWS::EC2::Subnet::Id> PublicVpcSubnets: Description: Public VPC Subnet for the ELB Type: List<AWS::EC2::Subnet::Id> Stack: Description: tag Default: identity Type: String Stage: Description: Deployment environment Default: CODE Type: String AllowedValues: - CODE - PROD SsmManagedPolicyArn: Description: The ARN for the ssm iam role Type: String VpcId: Description: VPC id of VPC for this service to use Type: String KinesisStream: Description: Kinesis Stream name for logging Type: AWS::SSM::Parameter::Value<String> Default: /account/services/logging.stream/name LoadBalancerLogsS3Bucket: Description: S3 Bucket to write ELB access logs to Type: String IdentityArtifactBucket: Description: S3 Bucket to read identity artifacts from Type: String IdentityConfigBucket: Description: S3 Bucket to read identity config from Type: String Mappings: StageVariables: CODE: BaseUri: profile.code.dev-theguardian.com DefaultReturnUri: https://m.code.dev-theguardian.com MaxInstances: 2 MinInstances: 1 LatencyAlarmThreshold: 5 LatencyAlarmPeriod: 1200 PROD: BaseUri: profile.theguardian.com DefaultReturnUri: https://theguardian.com MaxInstances: 12 MinInstances: 3 LatencyAlarmThreshold: 0.5 LatencyAlarmPeriod: 60 AlarmPriorities: P1: 'CRITICAL Respond Immediately' P2: 'URGENT 9-5' P3: 'MODERATE' Conditions: IsProd: !Equals [!Ref Stage, PROD] NotIsProd: !Not [!Equals [!Ref Stage, PROD]] Resources: AppRole: Type: AWS::IAM::Role Properties: Path: '/' AssumeRolePolicyDocument: Statement: - Effect: Allow Principal: Service: - ec2.amazonaws.com Action: sts:AssumeRole ManagedPolicyArns: - !Ref SsmManagedPolicyArn Policies: - PolicyName: root PolicyDocument: Version: 2012-10-17 Statement: - Effect: Allow Action: s3:GetObject Resource: - !Sub arn:aws:s3:::${IdentityArtifactBucket}/${Stage}/${App}/* - Effect: Allow Action: s3:GetObject Resource: - !Sub arn:aws:s3:::${IdentityConfigBucket}/${Stage}/${App}/* - PolicyName: DevxLogs PolicyDocument: Statement: - Effect: Allow Action: - ec2:DescribeTags - ec2:DescribeInstances Resource: '*' - Effect: Allow Action: - kinesis:DescribeStream - kinesis:PutRecord - kinesis:PutRecords Resource: - !Sub arn:aws:kinesis:${AWS::Region}:${AWS::AccountId}:stream/${KinesisStream} - PolicyName: GetParameters PolicyDocument: Statement: - Effect: Allow Action: - ssm:GetParameter Resource: - !Sub arn:aws:ssm:${AWS::Region}:${AWS::AccountId}:parameter/${Stack}/${App}/${Stage}/* - PolicyName: PushMetrics PolicyDocument: Version: 2012-10-17 Statement: - Effect: Allow Action: cloudwatch:PutMetricData Resource: '*' - PolicyName: DescribeASG PolicyDocument: Version: 2012-10-17 Statement: - Effect: Allow Action: - autoscaling:DescribeAutoScalingGroups - autoscaling:DescribeAutoScalingInstances Resource: '*' - PolicyName: SendEmailSES PolicyDocument: Version: 2012-10-17 Statement: - Effect: Allow Action: ses:SendEmail Resource: '*' - PolicyName: SSMTunnel PolicyDocument: Version: 2012-10-17 Statement: - Effect: Allow Action: - ec2messages:AcknowledgeMessage - ec2messages:DeleteMessage - ec2messages:FailMessage - ec2messages:GetEndpoint - ec2messages:GetMessages - ec2messages:SendReply - ssm:UpdateInstanceInformation - ssm:ListInstanceAssociations - ssm:DescribeInstanceProperties - ssm:DescribeDocumentParameters - ssmmessages:CreateControlChannel - ssmmessages:CreateDataChannel - ssmmessages:OpenControlChannel - ssmmessages:OpenDataChannel Resource: '*' GithubActionsSESSendEmailsRole: Type: AWS::IAM::Role Condition: NotIsProd Properties: RoleName: GithubActionsSESSendEmailsRole AssumeRolePolicyDocument: Statement: - Effect: Allow Action: sts:AssumeRoleWithWebIdentity Principal: Federated: !Sub arn:aws:iam::${AWS::AccountId}:oidc-provider/token.actions.githubusercontent.com Condition: StringLike: # All GitHub Actions running from the guardian/gateway repository. token.actions.githubusercontent.com:sub: !Sub repo:guardian/gateway:* Policies: - PolicyName: SendEmailSES PolicyDocument: Version: '2012-10-17' Statement: - Effect: Allow Action: ses:SendEmail Resource: '*' AutoScalingGroup: Type: AWS::AutoScaling::AutoScalingGroup Properties: LaunchTemplate: LaunchTemplateId: !Ref LaunchTemplate Version: !GetAtt 'LaunchTemplate.LatestVersionNumber' HealthCheckType: ELB HealthCheckGracePeriod: 300 MinSize: !FindInMap [StageVariables, !Ref Stage, MinInstances] MaxSize: !FindInMap [StageVariables, !Ref Stage, MaxInstances] TargetGroupARNs: - !Ref TargetGroup VPCZoneIdentifier: !Ref PrivateVpcSubnets Tags: - Key: Name Value: !Sub '${Stage}:${App}' PropagateAtLaunch: 'true' - Key: App Value: !Ref App PropagateAtLaunch: true - Key: Stack Value: !Ref Stack PropagateAtLaunch: true - Key: Stage Value: !Ref Stage PropagateAtLaunch: true - Key: LogKinesisStreamName Value: !Ref KinesisStream PropagateAtLaunch: true - Key: SystemdUnit Value: identity-gateway.service PropagateAtLaunch: true LaunchTemplate: Type: AWS::EC2::LaunchTemplate Properties: LaunchTemplateName: !Sub '${Stage}-${Stack}-${App}' LaunchTemplateData: ImageId: !Ref AMI IamInstanceProfile: Arn: !GetAtt 'InstanceProfile.Arn' InstanceType: t4g.small KeyName: !Ref KeyName SecurityGroupIds: - !Ref InstanceSecurityGroup MetadataOptions: HttpTokens: required UserData: Fn::Base64: !Sub - |+ #!/bin/bash -ev mkdir /etc/gu # Get Riff Raff deployed artefact S3 aws s3 cp s3://${IdentityArtifactBucket}/${Stage}/${App}/${App}.zip /etc/gu unzip -o /etc/gu/${App}.zip -d /etc/gu # Get Rate Limiter configuration file # Try multiple times to the config file. The s3 cp command can fail when called immediately on instance startup. while true; do if \ aws s3 cp s3://${IdentityConfigBucket}/${Stage}/${App}/.ratelimit.json /etc/gu/.ratelimit.json then break fi sleep 1 done # Setup user groupadd identity-gateway useradd -r -s /usr/bin/nologin -g identity-gateway identity-gateway chown -R identity-gateway:identity-gateway /etc/gu # Setup logs touch /var/log/identity-gateway.log chown identity-gateway:identity-gateway /var/log/identity-gateway.log # Try multiple times to get parameter store values. The SSM command can fail when called immediately on instance startup. while true; do if \ IDAPI_CLIENT_ACCESS_TOKEN=$(aws ssm get-parameter --name '/${Stack}/${App}/${Stage}/idapi-client-access-token' --with-decryption --region eu-west-1 --query="Parameter.Value" --output="text") && \ APP_SECRET=$(aws ssm get-parameter --name '/${Stack}/${App}/${Stage}/appSecret' --with-decryption --region eu-west-1 --query="Parameter.Value" --output="text") && \ GOOGLE_RECAPTCHA_SITE_KEY=$(aws ssm get-parameter --name '/${Stack}/${App}/${Stage}/recaptcha-site-key' --with-decryption --region eu-west-1 --query="Parameter.Value" --output="text") && \ GOOGLE_RECAPTCHA_SECRET_KEY=$(aws ssm get-parameter --name '/${Stack}/${App}/${Stage}/recaptcha-secret-key' --with-decryption --region eu-west-1 --query="Parameter.Value" --output="text") && \ REDIS_PASSWORD=$(aws ssm get-parameter --name '/${Stack}/${App}/${Stage}/redis-password' --with-decryption --region eu-west-1 --query="Parameter.Value" --output="text") && \ ENCRYPTION_SECRET_KEY=$(aws ssm get-parameter --name '/${Stack}/${App}/${Stage}/encryption-secret-key' --with-decryption --region eu-west-1 --query="Parameter.Value" --output="text") && \ OKTA_API_TOKEN=$(aws ssm get-parameter --name '/${Stack}/${App}/${Stage}/okta-api-token' --with-decryption --region eu-west-1 --query="Parameter.Value" --output="text") && \ OKTA_CUSTOM_OAUTH_SERVER=$(aws ssm get-parameter --name '/${Stack}/${App}/${Stage}/oktaCustomOAuthServer' --with-decryption --region eu-west-1 --query="Parameter.Value" --output="text") && \ OKTA_CLIENT_ID=$(aws ssm get-parameter --name '/${Stack}/${App}/${Stage}/oktaClientId' --with-decryption --region eu-west-1 --query="Parameter.Value" --output="text") && \ OKTA_CLIENT_SECRET=$(aws ssm get-parameter --name '/${Stack}/${App}/${Stage}/oktaClientSecret' --with-decryption --region eu-west-1 --query="Parameter.Value" --output="text") OKTA_IDP_APPLE=$(aws ssm get-parameter --name '/${Stack}/${App}/${Stage}/oktaIdpApple' --with-decryption --region eu-west-1 --query="Parameter.Value" --output="text") OKTA_IDP_GOOGLE=$(aws ssm get-parameter --name '/${Stack}/${App}/${Stage}/oktaIdpGoogle' --with-decryption --region eu-west-1 --query="Parameter.Value" --output="text") OKTA_GUARDIAN_USERS_ALL_GROUP_ID=$(aws ssm get-parameter --name '/${Stack}/${App}/${Stage}/oktaGuardianUsersAllGroupId' --with-decryption --region eu-west-1 --query="Parameter.Value" --output="text") USER_BENEFITS_API_URL=$(aws ssm get-parameter --name '/${Stack}/${App}/${Stage}/user-benefits-api-url' --with-decryption --region eu-west-1 --query="Parameter.Value" --output="text") DELETE_ACCOUNT_STEP_FUNCTION_URL=$(aws ssm get-parameter --name '/${Stack}/${App}/${Stage}/deleteAccountStepFunctionUrl' --with-decryption --region eu-west-1 --query="Parameter.Value" --output="text") DELETE_ACCOUNT_STEP_FUNCTION_API_KEY=$(aws ssm get-parameter --name '/${Stack}/${App}/${Stage}/deleteAccountStepFunctionApiKey' --with-decryption --region eu-west-1 --query="Parameter.Value" --output="text") then break fi sleep 1 done # systemd setup cat > /etc/systemd/system/identity-gateway.service <<EOL [Service] ExecStart=/bin/sh -ec '/usr/bin/node /etc/gu/server.js 2>&1' Restart=always StandardOutput=journal StandardError=journal SyslogIdentifier=identity-gateway User=identity-gateway Group=identity-gateway Environment=NODE_ENV=production Environment=PORT=9233 Environment=IDAPI_CLIENT_ACCESS_TOKEN=$IDAPI_CLIENT_ACCESS_TOKEN Environment=IDAPI_BASE_URL=${IdapiBaseUrl} Environment=SIGN_IN_PAGE_URL=${SignInPageUrl} Environment=OAUTH_BASE_URL=${OauthBaseUrl} Environment=BASE_URI=${BaseUri} Environment=DEFAULT_RETURN_URI=${DefaultReturnUri} Environment=STAGE=${Stage} Environment=IS_HTTPS=true Environment=APP_SECRET=$APP_SECRET Environment=GOOGLE_RECAPTCHA_SITE_KEY=$GOOGLE_RECAPTCHA_SITE_KEY Environment=GOOGLE_RECAPTCHA_SECRET_KEY=$GOOGLE_RECAPTCHA_SECRET_KEY Environment=ENCRYPTION_SECRET_KEY=$ENCRYPTION_SECRET_KEY Environment=OKTA_ORG_URL=${OktaOrgUrl} Environment=OKTA_API_TOKEN=$OKTA_API_TOKEN Environment=OKTA_CUSTOM_OAUTH_SERVER=$OKTA_CUSTOM_OAUTH_SERVER Environment=OKTA_CLIENT_ID=$OKTA_CLIENT_ID Environment=OKTA_CLIENT_SECRET=$OKTA_CLIENT_SECRET Environment=OKTA_IDP_APPLE=$OKTA_IDP_APPLE Environment=OKTA_IDP_GOOGLE=$OKTA_IDP_GOOGLE Environment=OKTA_GUARDIAN_USERS_ALL_GROUP_ID=$OKTA_GUARDIAN_USERS_ALL_GROUP_ID Environment=REDIS_PASSWORD=$REDIS_PASSWORD Environment=REDIS_HOST=${RedisHost} Environment=REDIS_SSL_ON=true Environment=MEMBERS_DATA_API_URL=${MembersDataApiUrl} Environment=USER_BENEFITS_API_URL=$USER_BENEFITS_API_URL Environment=DELETE_ACCOUNT_STEP_FUNCTION_URL=$DELETE_ACCOUNT_STEP_FUNCTION_URL Environment=DELETE_ACCOUNT_STEP_FUNCTION_API_KEY=$DELETE_ACCOUNT_STEP_FUNCTION_API_KEY [Install] WantedBy=multi-user.target EOL systemctl enable identity-gateway systemctl start identity-gateway - BaseUri: !FindInMap [StageVariables, !Ref Stage, BaseUri] DefaultReturnUri: !FindInMap [StageVariables, !Ref Stage, DefaultReturnUri] InstanceProfile: Type: AWS::IAM::InstanceProfile Properties: Path: '/' Roles: - !Ref AppRole InstanceSecurityGroup: Type: AWS::EC2::SecurityGroup Properties: GroupDescription: Allow SSH and HTTPS access VpcId: !Ref VpcId SecurityGroupIngress: - IpProtocol: tcp FromPort: 9233 ToPort: 9233 SourceSecurityGroupId: !Ref LoadBalancerSecurityGroup SecurityGroupEgress: - IpProtocol: tcp FromPort: 443 ToPort: 443 CidrIp: 0.0.0.0/0 LoadBalancer: Type: AWS::ElasticLoadBalancingV2::LoadBalancer Properties: Name: !Sub '${Stack}-${App}-${Stage}' Subnets: !Ref PublicVpcSubnets SecurityGroups: - !Ref LoadBalancerSecurityGroup Tags: - Key: App Value: !Ref App - Key: Stack Value: !Ref Stack - Key: Stage Value: !Ref Stage LoadBalancerAttributes: - Key: access_logs.s3.enabled Value: true - Key: access_logs.s3.bucket Value: !Ref 'LoadBalancerLogsS3Bucket' - Key: access_logs.s3.prefix Value: !Sub 'ELBLogs/${Stack}/${App}/${Stage}' LoadBalancerListener: Type: AWS::ElasticLoadBalancingV2::Listener Properties: Certificates: - CertificateArn: !Ref CertificateArn DefaultActions: - Type: forward TargetGroupArn: Ref: TargetGroup LoadBalancerArn: Ref: LoadBalancer Port: 443 Protocol: HTTPS SslPolicy: ELBSecurityPolicy-TLS-1-2-2017-01 LoadBalancerSecurityGroup: Type: AWS::EC2::SecurityGroup Properties: GroupDescription: Allow HTTPS traffic and egress to 9233 VpcId: !Ref VpcId SecurityGroupIngress: - IpProtocol: tcp FromPort: 443 ToPort: 443 CidrIp: 0.0.0.0/0 SecurityGroupEgress: - IpProtocol: tcp FromPort: 9233 ToPort: 9233 CidrIp: 0.0.0.0/0 TargetGroup: Type: AWS::ElasticLoadBalancingV2::TargetGroup Properties: Name: !Sub ${Stage}-${Stack}-${App} Port: 9233 Protocol: HTTP VpcId: Ref: VpcId HealthCheckIntervalSeconds: 10 HealthCheckPath: /healthcheck HealthCheckPort: 9233 HealthCheckProtocol: HTTP HealthCheckTimeoutSeconds: 5 HealthyThresholdCount: 2 UnhealthyThresholdCount: 2 Matcher: HttpCode: 200 TargetGroupAttributes: - Key: deregistration_delay.timeout_seconds Value: 45 DependsOn: - LoadBalancer TopicSendEmail: Type: AWS::SNS::Topic Condition: IsProd Properties: DisplayName: SendEmailToIdentityDev Subscription: - Endpoint: !Ref 'AlarmEmailAddress' Protocol: email HighLatencyScalingAlarm: Type: AWS::CloudWatch::Alarm Condition: IsProd Properties: AlarmName: !Sub - '${Priority} - ${App}-${Stage} high load balancer latency scaling' - Priority: !FindInMap [StageVariables, AlarmPriorities, P3] AlarmDescription: !Sub - 'Scale-Up if latency is greater than ${Threshold} seconds over last ${Period} seconds' - Period: !FindInMap [StageVariables, !Ref 'Stage', LatencyAlarmPeriod] Threshold: !FindInMap [StageVariables, !Ref 'Stage', LatencyAlarmThreshold] Namespace: AWS/ApplicationELB MetricName: TargetResponseTime Statistic: Average ComparisonOperator: GreaterThanOrEqualToThreshold Dimensions: - Name: LoadBalancer Value: !GetAtt 'LoadBalancer.LoadBalancerFullName' Threshold: !FindInMap [StageVariables, !Ref 'Stage', LatencyAlarmThreshold] Period: !FindInMap [StageVariables, !Ref 'Stage', LatencyAlarmPeriod] EvaluationPeriods: 1 AlarmActions: - !Ref 'ScaleUpPolicy' OKActions: - !Ref 'ScaleDownPolicy' ScaleUpPolicy: Type: AWS::AutoScaling::ScalingPolicy Properties: AutoScalingGroupName: !Ref 'AutoScalingGroup' AdjustmentType: ChangeInCapacity ScalingAdjustment: 1 Cooldown: 300 ScaleDownPolicy: Type: AWS::AutoScaling::ScalingPolicy Properties: AdjustmentType: ChangeInCapacity AutoScalingGroupName: !Ref 'AutoScalingGroup' Cooldown: 1800 ScalingAdjustment: -1 AlarmHighLatency: Type: AWS::CloudWatch::Alarm Condition: IsProd Properties: AlarmName: !Sub - '${Priority} - ${App}-${Stage} high load balancer latency' - Priority: !FindInMap [StageVariables, AlarmPriorities, P3] AlarmDescription: !Sub - 'Latency is greater than ${Threshold} seconds over ${Period} seconds for last 5 periods' - Period: !FindInMap [StageVariables, !Ref 'Stage', LatencyAlarmPeriod] Threshold: !FindInMap [StageVariables, !Ref 'Stage', LatencyAlarmThreshold] Namespace: AWS/ApplicationELB MetricName: TargetResponseTime Statistic: Average ComparisonOperator: GreaterThanOrEqualToThreshold Dimensions: - Name: LoadBalancer Value: !GetAtt 'LoadBalancer.LoadBalancerFullName' Threshold: !FindInMap [StageVariables, !Ref 'Stage', LatencyAlarmThreshold] Period: !FindInMap [StageVariables, !Ref 'Stage', LatencyAlarmPeriod] EvaluationPeriods: 5 AlarmActions: - !Ref 'TopicSendEmail' InsufficientDataActions: - !Ref 'TopicSendEmail' AlarmNoHealthyHosts: Type: AWS::CloudWatch::Alarm Condition: IsProd Properties: ActionsEnabled: 'true' AlarmName: !Sub - '${Priority} - ${App}-${Stage} insufficient healthy hosts' - Priority: !FindInMap [StageVariables, AlarmPriorities, P3] AlarmDescription: There are insufficient healthy hosts ComparisonOperator: LessThanThreshold EvaluationPeriods: 1 MetricName: HealthyHostCount Namespace: AWS/ApplicationELB Period: 60 Statistic: Average Threshold: !FindInMap [StageVariables, !Ref 'Stage', MinInstances] AlarmActions: - !Ref 'TopicSendEmail' InsufficientDataActions: - !Ref 'TopicSendEmail' OKActions: - !Ref 'TopicSendEmail' Dimensions: - Name: LoadBalancer Value: !GetAtt 'LoadBalancer.LoadBalancerFullName' - Name: TargetGroup Value: !GetAtt 'TargetGroup.TargetGroupFullName' DependsOn: - TargetGroup - LoadBalancer Alarm5XXSustained: Type: AWS::CloudWatch::Alarm Condition: IsProd Properties: ActionsEnabled: 'true' AlarmName: !Sub - '${Priority} - ${App}-${Stage} sustained 5xx errors' - Priority: !FindInMap [StageVariables, AlarmPriorities, P2] AlarmDescription: 'Sustained server errors detected' AlarmActions: - !Ref 'TopicSendEmail' OKActions: - !Ref 'TopicSendEmail' InsufficientDataActions: - !Ref 'TopicSendEmail' ComparisonOperator: GreaterThanOrEqualToThreshold Threshold: 15 EvaluationPeriods: 5 TreatMissingData: notBreaching Metrics: - Id: total5XXCount Expression: backend5XXCount + elb5XXCount Label: 'Count of Backend AND ELB 5XX' - Id: backend5XXCount MetricStat: Metric: Namespace: AWS/ApplicationELB MetricName: HTTPCode_Target_5XX_Count Dimensions: - Name: LoadBalancer Value: !GetAtt LoadBalancer.LoadBalancerFullName - Name: TargetGroup Value: !GetAtt TargetGroup.TargetGroupFullName Period: 60 Stat: Sum Unit: Count ReturnData: false - Id: elb5XXCount MetricStat: Metric: Namespace: AWS/ApplicationELB MetricName: HTTPCode_ELB_5XX_Count Dimensions: - Name: LoadBalancer Value: !GetAtt LoadBalancer.LoadBalancerFullName Period: 60 Stat: Sum Unit: Count ReturnData: false SigninInactivityAlarm: Type: AWS::CloudWatch::Alarm Condition: IsProd Properties: AlarmName: !Sub - '${Priority} - ${App} ${Stage} has had no new sign-ins in the last 20 minutes' - Priority: !FindInMap [StageVariables, AlarmPriorities, P1] AlarmDescription: No one has successfully signed ins in the last 20 minutes. Metrics: - Id: totalSignInCount Expression: oktaSignInCount + oktaIdxSignInCount Label: 'Total sign-ins in Okta' - Id: oktaSignInCount MetricStat: Metric: Namespace: Gateway MetricName: 'OktaSignIn::Success' Dimensions: - Name: Stage Value: !Ref 'Stage' - Name: ApiMode Value: identity-gateway Period: 1200 Stat: Sum Unit: Count ReturnData: false - Id: oktaIdxSignInCount MetricStat: Metric: Namespace: Gateway MetricName: 'OktaIdxSignIn::Success' Dimensions: - Name: Stage Value: !Ref 'Stage' - Name: ApiMode Value: identity-gateway Period: 1200 Stat: Sum Unit: Count ReturnData: false ComparisonOperator: LessThanThreshold Threshold: 1 EvaluationPeriods: 1 AlarmActions: - !Ref 'TopicSendEmail' InsufficientDataActions: - !Ref 'TopicSendEmail' RegisterInactivityAlarm: Type: AWS::CloudWatch::Alarm Condition: IsProd Properties: AlarmName: !Sub - '${Priority} - ${App} ${Stage} has had no new registrations in the last hour' - Priority: !FindInMap [StageVariables, AlarmPriorities, P1] AlarmDescription: No one has successfully registered in the last hour. Metrics: - Id: totalRegistrationCount Expression: oktaIdxRegistrationCount + oktaRegistrationCount Label: 'Total registrations in Okta Classic and Okta IDX' - Id: oktaIdxRegistrationCount MetricStat: Metric: Namespace: Gateway MetricName: 'OktaIDXRegister::Success' Dimensions: - Name: Stage Value: !Ref 'Stage' - Name: ApiMode Value: identity-gateway Period: 3600 Stat: Sum Unit: Count ReturnData: false - Id: oktaRegistrationCount MetricStat: Metric: Namespace: Gateway MetricName: 'OktaRegistration::Success' Dimensions: - Name: Stage Value: !Ref 'Stage' - Name: ApiMode Value: identity-gateway Period: 3600 Stat: Sum Unit: Count ReturnData: false ComparisonOperator: LessThanThreshold Threshold: 1 EvaluationPeriods: 1 AlarmActions: - !Ref 'TopicSendEmail' InsufficientDataActions: - !Ref 'TopicSendEmail' OAuthAuthenticationCallbackInactivityAlarm: Type: AWS::CloudWatch::Alarm Condition: IsProd Properties: AlarmName: !Sub - '${Priority} - ${App} ${Stage} has had no success OAuth Authorization code flow callbacks for Authentication in the last 20 minutes' - Priority: !FindInMap [StageVariables, AlarmPriorities, P1] AlarmDescription: No one has successfully completed OAuth Authorization code flow callbacks for Authentication in the last 20 minutes. Metrics: - Id: totalOAuthAuthenticationCallbackCount Expression: oktaOAuthAuthenticationCallbackCount Label: 'Total OAuth Authorization Callbacks for Authentication in Okta' - Id: oktaOAuthAuthenticationCallbackCount MetricStat: Metric: Namespace: Gateway MetricName: 'OAuthAuthenticationCallback::Success' Dimensions: - Name: Stage Value: !Ref 'Stage' - Name: ApiMode Value: identity-gateway Period: 1200 Stat: Sum Unit: Count ReturnData: false ComparisonOperator: LessThanThreshold Threshold: 1 EvaluationPeriods: 1 AlarmActions: - !Ref 'TopicSendEmail' InsufficientDataActions: - !Ref 'TopicSendEmail' OAuthApplicationCallbackInactivityAlarm: Type: AWS::CloudWatch::Alarm Condition: IsProd Properties: AlarmName: !Sub - '${Priority} - ${App} ${Stage} has had no success OAuth Authorization code flow callbacks for internal Gateway routes in the last 1 hour' - Priority: !FindInMap [StageVariables, AlarmPriorities, P1] AlarmDescription: No one has successfully completed OAuth Authorization code flow callbacks for internal Gateway routes in the last 1 hour. Metrics: - Id: totalOAuthApplicationCallbackCount Expression: oktaOAuthApplicationCallbackCount Label: 'Total OAuth Authorization Callbacks for internal Gateway routes in Okta' - Id: oktaOAuthApplicationCallbackCount MetricStat: Metric: Namespace: Gateway MetricName: 'OAuthApplicationCallback::Success' Dimensions: - Name: Stage Value: !Ref 'Stage' - Name: ApiMode Value: identity-gateway Period: 3600 Stat: Sum Unit: Count ReturnData: false ComparisonOperator: LessThanThreshold Threshold: 1 EvaluationPeriods: 1 AlarmActions: - !Ref 'TopicSendEmail' InsufficientDataActions: - !Ref 'TopicSendEmail' DeletionInactivityAlarm: Type: AWS::CloudWatch::Alarm Condition: IsProd Properties: AlarmName: !Sub - '${Priority} - ${App} ${Stage} has had no success self service user deletion in the last 6 hours' - Priority: !FindInMap [StageVariables, AlarmPriorities, P2] AlarmDescription: No one has successfully deleted their account in the last 6 hours. Metrics: - Id: totalDeletionCount Expression: deleteAccountCount Label: 'Total self service user deletions' - Id: deleteAccountCount MetricStat: Metric: Namespace: Gateway MetricName: 'OAuthDeleteCallback::Success' Dimensions: - Name: Stage Value: !Ref 'Stage' - Name: ApiMode Value: identity-gateway Period: 21600 Stat: Sum Unit: Count ReturnData: false ComparisonOperator: LessThanThreshold Threshold: 1 EvaluationPeriods: 1 AlarmActions: - !Ref 'TopicSendEmail' InsufficientDataActions: - !Ref 'TopicSendEmail' UnsubscribeAllInactivityAlarm: Type: AWS::CloudWatch::Alarm Condition: IsProd Properties: AlarmName: !Sub - '${Priority} - ${App} ${Stage} has had successful no unsubscribe all from email clients in the last hour' - Priority: !FindInMap [StageVariables, AlarmPriorities, P2] AlarmDescription: 'No one has successfully unsubscribed all from email clients in the last hour.' Metrics: - Id: totalUnsubscribeAllCount Expression: unsubscribeAllCount Label: 'Total unsubscribe all' - Id: unsubscribeAllCount MetricStat: Metric: Namespace: Gateway MetricName: 'UnsubscribeAll::Success' Dimensions: - Name: Stage Value: !Ref 'Stage' - Name: ApiMode Value: identity-gateway Period: 3600 Stat: Sum Unit: Count ReturnData: false ComparisonOperator: LessThanThreshold Threshold: 1 EvaluationPeriods: 1 AlarmActions: - !Ref 'TopicSendEmail' InsufficientDataActions: - !Ref 'TopicSendEmail'