AWSTemplateFormatVersion: '2010-09-09' Description: Nakama ECS Service Parameters: #------------------------ # Deployment Information #------------------------ environment: Type: String Description: Name of the environment to use in naming. Default: production release: Type: String Description: Name of the release name of the stack version to use. Default: production AllowedValues: ['develop', 'production'] ConstraintDescription: "Must be a possible release version." VpcId: Description: ID of the VPC Type: AWS::EC2::VPC::Id #------------------- # ECS Configuration #------------------- EcsCluster: Type: String Description: The cluster to run the Nakama service on. #----------------- # Load Balancing #----------------- PublicSubnets: Description: The public subnets for the ALB to run in. Type: String PortalCertificate: Description: Arn of AWS Certificate Type: String #---------------------- # Nakama Configuration #---------------------- NakamaUsername: Type: String Description: Username to access the Nakama admin portal Default: "admin" NakamaPasswordOverride: Type: String Description: Override Nakama admin portal password. Leave blank for random password. Default: "" #------------------------ # Database Configuration #------------------------ CreateDatabase: Type: String Default: "true" AllowedValues: ["true", "false"] # Manual Database Configuration DatabaseUsername: Type: String Description: Username of the Postgres server Default: postgres DatabasePassword: Type: String Description: Password for the Postgres server Default: "" DatabaseEndpoint: Type: String Description: Endpoint for the Postgres server Default: "" DatabasePort: Type: Number Description: Port for the Postgres server Default: 5432 # Advanced RDS Configuration RdsInstanceClass: Type: String Description: Instance class for the dabase to run on Default: db.t2.micro RdsEngine: Type: String Description: Database engine for the database to use Default: postgres AllowedValues: ["aurora", "aurora-mysql", "aurora-postgresql", "mariadb", "mysql", "oracle-ee", "oracle-se2", "oracle-se1", "oracle-se", "postgres", "sqlserver-ee", "sqlserver-se", "sqlserver-ex", "sqlserver-web"] RdsUsername: Type: String Description: Master account's username for database Default: postgres RdsPort: Type: Number Description: Port for the database to open a socket on Default: "5432" RdsStorage: Type: Number Description: The amount of storage (in GB) allocated to the RDS instance Default: "100" RdsAccessCidr: Type: String Description: The CIDR used in the security group to secure the database Default: "0.0.0.0/0" Domain: Type: String Description: The domain to create the endpoint on (Must have an existing hosted zone ex. `example.com`) Leave blank to skip DNS. Default: "" SubDomain: Type: String Description: The subdomain to be used by nakama. (ex. `nakama.example.com`) Default: nakama Conditions: CreateRdsStack: !Equals [!Ref CreateDatabase, "true"] CreateDns: !Not [!Equals [!Ref Domain, ""]] Resources: #----- # DNS #----- DnsRecords: Condition: CreateDns Type: AWS::CloudFormation::Stack Properties: TemplateURL: !Sub 'https://s3.${AWS::Region}.amazonaws.com/sumu-stacks/nakama/${release}/cloudformation/nakama/dns.yaml' Parameters: environment: !Ref environment Domain: !Ref Domain SubDomain: !Ref SubDomain NakamaDns: !GetAtt PublicNLB.DNSName AdminDns: !GetAtt PublicALB.DNSName #---------- # Database #---------- RdsDatabase: Condition: CreateRdsStack Type: AWS::CloudFormation::Stack Properties: TemplateURL: !Sub 'https://s3.${AWS::Region}.amazonaws.com/sumu-stacks/nakama/${release}/cloudformation/nakama/rds.yaml' Parameters: environment: !Ref environment VpcId: !Ref VpcId InstanceClass: !Ref RdsInstanceClass DatabaseEngine: !Ref RdsEngine DatabaseUsername: !Ref RdsUsername DatabasePort: !Ref RdsPort DatabaseStorage: !Ref RdsStorage DatabaseAccessCidr: !Ref RdsAccessCidr #----------------- # Load Balancing #----------------- #-- Network Load Balancer --# PublicNLB: Type: AWS::ElasticLoadBalancingV2::LoadBalancer Properties: Type: network LoadBalancerAttributes: - Key: deletion_protection.enabled Value: false Scheme: internet-facing Subnets: !Split [",", !Ref PublicSubnets] Tags: - Key: Name Value: !Sub "Nakama-${environment}-NLB" - Key: environment Value: !Ref environment # Target group for HTTP api HttpApiTargetGroup: Type: AWS::ElasticLoadBalancingV2::TargetGroup Properties: Port: 7350 Protocol: TCP TargetGroupAttributes: - Key: deregistration_delay.timeout_seconds Value: '20' VpcId: !Ref 'VpcId' Tags: - Key: Name Value: !Sub 'nakama-http-${release}' # Listener for HTTP HttpApiNlbListener: Type: AWS::ElasticLoadBalancingV2::Listener Properties: DefaultActions: - Type: forward TargetGroupArn: !Ref HttpApiTargetGroup LoadBalancerArn: !Ref PublicNLB Port: 7350 Protocol: TCP # Target group for gRPC API GRpcApiTargetGroup: Type: AWS::ElasticLoadBalancingV2::TargetGroup Properties: Port: 7349 Protocol: TCP_UDP TargetGroupAttributes: - Key: deregistration_delay.timeout_seconds Value: '20' VpcId: !Ref 'VpcId' Tags: - Key: Name Value: !Sub 'nakama-GRpc-${release}' # Listener for gRPC API GRpcNlbListener: Type: AWS::ElasticLoadBalancingV2::Listener Properties: DefaultActions: - Type: forward TargetGroupArn: !Ref GRpcApiTargetGroup LoadBalancerArn: !Ref PublicNLB Port: 7349 Protocol: TCP_UDP # Target group for gRPC embeded console GRpcEApiTargetGroup: Type: AWS::ElasticLoadBalancingV2::TargetGroup Properties: Port: 7348 Protocol: TCP_UDP TargetGroupAttributes: - Key: deregistration_delay.timeout_seconds Value: '20' VpcId: !Ref 'VpcId' Tags: - Key: Name Value: !Sub 'nakama-GRpc-${release}' # Listener for gRPC embeded console GRpcENlbListener: Type: AWS::ElasticLoadBalancingV2::Listener Properties: DefaultActions: - Type: forward TargetGroupArn: !Ref GRpcEApiTargetGroup LoadBalancerArn: !Ref PublicNLB Port: 7348 Protocol: TCP_UDP #-- Application Load Balancer --# PublicALB: Type: AWS::ElasticLoadBalancingV2::LoadBalancer Properties: Type: application LoadBalancerAttributes: - Key: deletion_protection.enabled Value: false - Key: idle_timeout.timeout_seconds Value: 60 Scheme: internet-facing SecurityGroups: - !Ref AlbSecurityGroup Subnets: !Split [",", !Ref PublicSubnets] Tags: - Key: Name Value: !Sub "Nakama-${environment}-ALB" - Key: environment Value: !Ref environment AlbSecurityGroup: Type: AWS::EC2::SecurityGroup Properties: GroupDescription: ECS Allowed Ports VpcId: !Ref VpcId SecurityGroupIngress: - IpProtocol: icmp FromPort: "-1" ToPort: "-1" CidrIp: 0.0.0.0/0 - IpProtocol: tcp FromPort: "443" ToPort: "443" CidrIp: 0.0.0.0/0 - IpProtocol: tcp FromPort: "80" ToPort: "80" CidrIp: 0.0.0.0/0 SecurityGroupEgress: - IpProtocol: icmp FromPort: "-1" ToPort: "-1" CidrIp: 0.0.0.0/0 - IpProtocol: tcp FromPort: "0" ToPort: "65535" CidrIp: 0.0.0.0/0 - IpProtocol: udp FromPort: "0" ToPort: "65535" CidrIp: 0.0.0.0/0 # Target group for admin portal port AdminPortalTargetGroup: Type: AWS::ElasticLoadBalancingV2::TargetGroup Properties: HealthCheckIntervalSeconds: 30 HealthCheckProtocol: HTTP HealthCheckTimeoutSeconds: 15 HealthyThresholdCount: 2 UnhealthyThresholdCount: 2 Matcher: HttpCode: '200' HealthCheckPath: '/' Port: 7351 Protocol: HTTP TargetGroupAttributes: - Key: deregistration_delay.timeout_seconds Value: '20' VpcId: !Ref 'VpcId' Tags: - Key: Name Value: !Sub 'nakama-${release}' # HTTPS for Admin Portal AdminPortalAlbListener: Type: AWS::ElasticLoadBalancingV2::Listener Properties: Certificates: - CertificateArn: !Ref PortalCertificate DefaultActions: - Type: forward TargetGroupArn: !Ref AdminPortalTargetGroup LoadBalancerArn: !Ref PublicALB Port: 443 Protocol: HTTPS # Redirect HTTP -> HTTPS AdminPortalRedirectAlbListener: Type: AWS::ElasticLoadBalancingV2::Listener Properties: DefaultActions: - Type: redirect RedirectConfig: Protocol: HTTPS Port: 443 Host: '#{host}' Path: '/#{path}' Query: '#{query}' StatusCode: HTTP_301 LoadBalancerArn: !Ref PublicALB Port: 80 Protocol: HTTP #------------------- # ECS Task & Service #------------------- TaskDefinition: Type: AWS::CloudFormation::Stack Properties: TemplateURL: !Sub 'https://s3.${AWS::Region}.amazonaws.com/sumu-stacks/nakama/${release}/cloudformation/nakama/task.yaml' Parameters: DatabaseUsername: !If ["CreateRdsStack", !GetAtt RdsDatabase.Outputs.RdsUsername, !Ref DatabaseUsername] DatabasePassword: !If ["CreateRdsStack", !Join ["", ["{{resolve:secretsmanager:", !GetAtt RdsDatabase.Outputs.RdsSecret, ":SecretString}}" ]], !Ref DatabasePassword] DatabaseEndpoint: !If ["CreateRdsStack", !GetAtt RdsDatabase.Outputs.RdsEnpoint, !Ref DatabaseEndpoint] DatabasePort: !If ["CreateRdsStack", !GetAtt RdsDatabase.Outputs.RdsPort, !Ref DatabasePort] NakamaUsername: !Ref NakamaUsername NakamaPasswordOverride: !Ref NakamaPasswordOverride EcsService: DependsOn: AdminPortalAlbListener Type: AWS::ECS::Service Properties: Cluster: !Ref EcsCluster DesiredCount: 1 TaskDefinition: !GetAtt TaskDefinition.Outputs.TaskArn LoadBalancers: - ContainerName: "nakama" ContainerPort: 7351 TargetGroupArn: !Ref AdminPortalTargetGroup - ContainerName: "nakama" ContainerPort: 7350 TargetGroupArn: !Ref HttpApiTargetGroup - ContainerName: "nakama" ContainerPort: 7349 TargetGroupArn: !Ref GRpcApiTargetGroup - ContainerName: "nakama" ContainerPort: 7348 TargetGroupArn: !Ref GRpcEApiTargetGroup