Files
jambonz-infrastructure/cloudformation/jambonz-scalable-production.yaml
2023-02-25 14:42:05 -05:00

1980 lines
68 KiB
YAML

---
AWSTemplateFormatVersion: "2010-09-09"
Mappings:
AWSRegion2AMI:
us-east-1:
SbcSipAmi: ami-0b1129362b8ff76db
SbcRtpAmi: ami-08aa0cd1abd23684e
FsAmi: ami-012cde43def9ebfd3
WebserverAmi: ami-07c01a396d6359a74
MonitoringServerAmi: ami-0ec77ae7ad225eab0
eu-west-3:
SbcSipAmi: ami-0a597618da83f0f0a
SbcRtpAmi: ami-089faad36bf087a19
FsAmi: ami-09261164ad65cc50b
WebserverAmi: ami-097efdd8d82136079
MonitoringServerAmi: ami-02fedcc080183735c
Parameters:
KeyName:
Description: "The keypair that you will use to access the EC2 instances via ssh"
Type: "AWS::EC2::KeyPair::KeyName"
InstanceTypeSbcSip:
Description: "the EC2 instance type for the SBC SIP server"
Type: String
Default: t2.small
AllowedValues:
- t2.small
- t2.medium
- t2.large
- t2.xlarge
- t3.small
- t3.medium
- t3.large
- t3.xlarge
- t3a.small
- t3a.medium
- t3a.large
- t3a.xlarge
- c5.large
- c5.xlarge
- c5.2xlarge
- c5n.large
- c5n.xlarge
- c5n.2xlarge
- c5n.4xlarge
- c5n.18xlarge
- c5n.metal
InstanceTypeSbcRtp:
Description: "the EC2 instance type to use for the SBC Media server"
Type: String
Default: t2.small
AllowedValues:
- t2.small
- t2.medium
- t2.large
- t2.xlarge
- t3.small
- t3.medium
- t3.large
- t3.xlarge
- t3a.small
- t3a.medium
- t3a.large
- t3a.xlarge
- c5.large
- c5.xlarge
- c5.2xlarge
- c5n.large
- c5n.xlarge
- c5n.2xlarge
- c5n.4xlarge
- c5n.18xlarge
- c5n.metal
InstanceTypeFeatureServer:
Description: "the EC2 instance type to use for the Feature Server"
Type: String
Default: t2.small
AllowedValues:
- t2.small
- t2.medium
- t2.large
- t2.xlarge
- t3.small
- t3.medium
- t3.large
- t3.xlarge
- t3a.small
- t3a.medium
- t3a.large
- t3a.xlarge
- c5.large
- c5.xlarge
- c5.2xlarge
- c5n.large
- c5n.xlarge
- c5n.2xlarge
- c5n.4xlarge
- c5n.18xlarge
- c5n.metal
InstanceTypeWebserver:
Description: "the EC2 instance type to use for webServer"
Type: String
Default: t2.small
AllowedValues:
- t2.small
- t2.medium
- t2.large
- t2.xlarge
- t3.small
- t3.medium
- t3.large
- t3.xlarge
- t3a.small
- t3a.medium
- t3a.large
- t3a.xlarge
- c5.large
- c5.xlarge
- c5.2xlarge
- c5n.large
- c5n.xlarge
- c5n.2xlarge
- c5n.4xlarge
- c5n.18xlarge
- c5n.metal
InstanceTypeMonitoringServer:
Description: "the EC2 instance type for the monitoring server"
Type: String
Default: t2.small
AllowedValues:
- t2.small
- t2.medium
- t2.large
- t2.xlarge
- t3.small
- t3.medium
- t3.large
- t3.xlarge
- t3a.small
- t3a.medium
- t3a.large
- t3a.xlarge
- c5.large
- c5.xlarge
- c5.2xlarge
- c5n.large
- c5n.xlarge
- c5n.2xlarge
- c5n.4xlarge
- c5n.18xlarge
- c5n.metal
ElastiCacheNodeType:
Type: String
Default: 'cache.t2.medium'
AllowedValues:
- cache.t3.micro
- cache.t3.small
- cache.t3.medium
- cache.t2.small
- cache.t2.medium
- cache.m6g.large
- cache.m6g.xlarge
- cache.m6g.2xlarge
- cache.m6g.4xlarge
- cache.m6g.8xlarge
- cache.m6g.12xlarge
- cache.m6g.16xlarge
- cache.m5.large
- cache.m5.xlarge
- cache.m5.2xlarge
- cache.m5.4xlarge
- cache.m5.12xlarge
- cache.m5.24xlarge
- cache.r6g.large
- cache.r6g.xlarge
- cache.r6g.2xlarge
- cache.r6g.4xlarge
- cache.r6g.8xlarge
- cache.r6g.12xlarge
- cache.r6g.16xlarge
- cache.r5.large
- cache.r5.xlarge
- cache.r5.2xlarge
- cache.r5.4xlarge
- cache.r5.12xlarge
- cache.r5.24xlarge
AuroraDBMinCapacity:
Description: "min capacity for database"
Type: Number
Default: 1
AuroraDBMaxCapacity:
Description: "max capacity for database"
Type: Number
Default: 4
AllowedValues:
- 1
- 2
- 4
- 8
- 16
- 32
- 64
- 128
- 256
Prefix:
Description: "Name of VPC and other identifiers - lower case letters only"
Type: "String"
Default: "jb"
AllowedSshCidr:
Description: Please set CIDR to x.x.x.x/32 to allow one specific IP address ssh access, 0.0.0.0/0 to allow all IP addresses access, or another CIDR range.
Type: String
AllowedPattern: \d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3}\/\d{1,2}
ConstraintDescription: must be a valid network CIDR
AllowedHttpCidr:
Description: Please set CIDR to x.x.x.x/32 to allow one specific IP address http(s) access, 0.0.0.0/0 to allow all IP addresses access, or another CIDR range.
Type: String
AllowedPattern: \d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3}\/\d{1,2}
ConstraintDescription: must be a valid network CIDR
Default: 0.0.0.0/0
AllowedSipCidr:
Description: Please set CIDR to x.x.x.x/32 to allow one specific IP address sip access, 0.0.0.0/0 to allow all IP addresses access, or another CIDR range.
Type: String
ConstraintDescription: must be a valid network CIDR
AllowedPattern: \d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3}\/\d{1,2}
Default: 0.0.0.0/0
AllowedSmppCidr:
Description: Please set CIDR to x.x.x.x/32 to allow one specific IP address smpp access, 0.0.0.0/0 to allow all IP addresses access, or another CIDR range.
Type: String
ConstraintDescription: must be a valid network CIDR
AllowedPattern: \d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3}\/\d{1,2}
Default: 0.0.0.0/0
AllowedRtpCidr:
Description: Please set CIDR to x.x.x.x/32 to allow one specific IP address to send RTP traffic, 0.0.0.0/0 to allow all IP addresses access, or another CIDR range.
Type: String
ConstraintDescription: must be a valid network CIDR
AllowedPattern: \d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3}\/\d{1,2}
Default: 0.0.0.0/0
VpcCIDR:
Description: "The CIDR block for the whole VPC"
Type: "String"
Default: '172.20.0.0/16'
PublicSubnet1CIDR:
Description: "Please enter the IP range (CIDR notation) for the public subnet in the first Availability Zone"
Type: "String"
Default: '172.20.10.0/24'
PublicSubnet2CIDR:
Description: "Please enter the IP range (CIDR notation) for the public subnet in the second Availability Zone"
Type: "String"
Default: '172.20.11.0/24'
MySQLUsername:
Description: 'the database username'
Type: String
Default: 'admin'
MySQLPassword:
NoEcho: true
Description: 'The database admin account password'
Type: String
Default: 'JambonzR0ck$'
EncryptionSecret:
Type: String
Description: "secret to use for encrypting jwt and other data"
Default: "G=u$Dj%-97#TffYf"
URLPortal:
Type: String
Description: "DNS name you will point to the jambonz webserver(s)"
Default: "yourdomain.com"
JaegerUsername:
Type: String
Description: "Basic Auth username for Jaeger"
Default: "admin"
JaegerPassword:
Type: String
Description: "Basic Auth password for Jaeger"
Default: "JambonzR0ck$"
StatsSampleRate:
Type: Number
Description: sampling rate for metrics, a number between 0 and 1 inclusive
Default: 1
DbCachingTTS:
Type: Number
Description: Number of seconds to cache results from DB queries (0=no caching)
Default: 0
EnableTracing:
Type: Number
Description: enable opentelemetry application tracing?
AllowedValues:
- 0
- 1
Default: 1
CloudwatchLogRetention:
Description: "Number of days to retain cloudwatch logs"
Type: Number
Default: 3
AllowedValues:
- 1
- 3
- 5
- 7
- 14
- 30
- 60
- 90
- 120
- 150
Resources:
###########################################
#
# VPC Resources
#
###########################################
VPC:
Type: "AWS::EC2::VPC"
Properties:
CidrBlock: !Ref "VpcCIDR"
Tags:
- Key: "Name"
Value: !Sub "${Prefix}-VPC"
# Create Internet Gateway
InternetGateway:
Type: "AWS::EC2::InternetGateway"
Properties:
Tags:
- Key: "Name"
Value: !Sub "${Prefix}-IGW"
# Attach Internet Gateway to VPC
GatewayToInternet:
Type: "AWS::EC2::VPCGatewayAttachment"
Properties:
VpcId: !Ref "VPC"
InternetGatewayId: !Ref "InternetGateway"
# Create Public Subnet
PublicSubnet1:
Type: "AWS::EC2::Subnet"
Properties:
VpcId: !Ref "VPC"
CidrBlock: !Ref "PublicSubnet1CIDR"
AvailabilityZone: !Select [ '0', !GetAZs ]
MapPublicIpOnLaunch: "True"
Tags:
- Key: "Name"
Value: !Sub "${Prefix}-${PublicSubnet1CIDR}-PublicSubnet1"
PublicSubnet2:
Type: "AWS::EC2::Subnet"
Properties:
VpcId: !Ref "VPC"
CidrBlock: !Ref "PublicSubnet2CIDR"
AvailabilityZone: !Select [ '1', !GetAZs ]
MapPublicIpOnLaunch: "True"
Tags:
- Key: "Name"
Value: !Sub "${Prefix}-${PublicSubnet2CIDR}-PublicSubnet2"
# Create Public Route Table 1
PublicRouteTable1:
Type: "AWS::EC2::RouteTable"
Properties:
VpcId: !Ref "VPC"
Tags:
- Key: "Name"
Value: !Sub "${Prefix}-PublicRoute1"
# Create Public Route Table 2
PublicRouteTable2:
Type: "AWS::EC2::RouteTable"
Properties:
VpcId: !Ref "VPC"
Tags:
- Key: "Name"
Value: !Sub "${Prefix}-PublicRoute2"
# Route-out Public Route Table to Internet Gateway (Internet connection)
PublicRouteIGW1:
Type: "AWS::EC2::Route"
DependsOn: "GatewayToInternet"
Properties:
RouteTableId: !Ref "PublicRouteTable1"
DestinationCidrBlock: "0.0.0.0/0"
GatewayId: !Ref "InternetGateway"
PublicRouteIGW2:
Type: "AWS::EC2::Route"
DependsOn: "GatewayToInternet"
Properties:
RouteTableId: !Ref "PublicRouteTable2"
DestinationCidrBlock: "0.0.0.0/0"
GatewayId: !Ref "InternetGateway"
# Associate Public Route Table with Public Subnet1 & Subnet2
PublicSubnet1RouteTableAssociation:
Type: "AWS::EC2::SubnetRouteTableAssociation"
Properties:
SubnetId: !Ref "PublicSubnet1"
RouteTableId: !Ref "PublicRouteTable1"
PublicSubnet2RouteTableAssociation:
Type: "AWS::EC2::SubnetRouteTableAssociation"
Properties:
SubnetId: !Ref "PublicSubnet2"
RouteTableId: !Ref "PublicRouteTable2"
###########################################
#
# SECURITY GROUPS
#
###########################################
SshSecurityGroup:
Type: AWS::EC2::SecurityGroup
Properties:
GroupName: !Sub '${Prefix}-jambonz-ssh-sg'
GroupDescription: !Sub 'Security group for ssh to ${Prefix} jambonz cluster'
VpcId: !Ref VPC
SecurityGroupIngress:
- IpProtocol: tcp
FromPort: 22
ToPort: 22
CidrIp: !Ref AllowedSshCidr
Description: Allow SSH access
RedisSecurityGroup:
Type: AWS::EC2::SecurityGroup
Properties:
GroupName: !Sub '${Prefix}-redis-sg'
GroupDescription: !Sub 'Security group for ${Prefix} Redis'
VpcId: !Ref VPC
SecurityGroupIngress:
- IpProtocol: tcp
FromPort: 6379
ToPort: 6379
CidrIp: !Ref VpcCIDR
Description: Allow traffic from VPC
SecurityGroupEgress:
- IpProtocol: -1
FromPort: 0
ToPort: 0
CidrIp: 0.0.0.0/0
Tags:
- Key: Name
Value: !Sub '${Prefix}-redis-sg'
MySQLSecurityGroup:
Type: AWS::EC2::SecurityGroup
Properties:
GroupName: !Sub '${Prefix}-mysql-sg'
GroupDescription: !Sub 'Security group for ${Prefix} MySQL'
VpcId: !Ref VPC
SecurityGroupIngress:
- IpProtocol: tcp
FromPort: 3306
ToPort: 3306
CidrIp: !Ref VpcCIDR
Description: Allow HTTP traffic from VPC
SecurityGroupEgress:
- IpProtocol: -1
FromPort: 0
ToPort: 0
CidrIp: 0.0.0.0/0
Tags:
- Key: Name
Value: !Sub '${Prefix}-mysql-sg'
FeatureServerSecurityGroup:
Type: AWS::EC2::SecurityGroup
Properties:
GroupName: !Sub '${Prefix}-feature-server-sg'
GroupDescription: !Sub 'Security group for ${Prefix} Feature Server'
VpcId: !Ref VPC
SecurityGroupIngress:
- IpProtocol: tcp
FromPort: 3000
ToPort: 3009
CidrIp: !Ref VpcCIDR
Description: Allow HTTP from sbc/api server
- IpProtocol: tcp
FromPort: 3010
ToPort: 3019
CidrIp: !Ref AllowedHttpCidr
Description: Allow http access from AWS SNS
- IpProtocol: tcp
FromPort: 5060
ToPort: 5060
CidrIp: !Ref VpcCIDR
Description: Allow sip from VPC
- IpProtocol: udp
FromPort: 5060
ToPort: 5060
CidrIp: !Ref VpcCIDR
Description: Allow sip from VPC
- IpProtocol: udp
FromPort: 25000
ToPort: 40000
CidrIp: !Ref VpcCIDR
Description: rtp
SecurityGroupEgress:
- IpProtocol: -1
FromPort: 0
ToPort: 0
CidrIp: 0.0.0.0/0
Tags:
- Key: Name
Value: !Sub '${Prefix}-feature-server-sg'
WebserverSecurityGroup:
Type: AWS::EC2::SecurityGroup
Properties:
GroupName: !Sub '${Prefix}-webserver-sg'
GroupDescription: !Sub 'Security group for ${Prefix} WebServer'
VpcId: !Ref VPC
SecurityGroupIngress:
- IpProtocol: tcp
FromPort: 80
ToPort: 80
CidrIp: !Ref AllowedHttpCidr
Description: Allow HTTP access
- IpProtocol: tcp
FromPort: 443
ToPort: 443
CidrIp: !Ref AllowedHttpCidr
Description: Allow HTTPS access
- IpProtocol: tcp
FromPort: 3000
ToPort: 3000
SourceSecurityGroupId: !Ref FeatureServerSecurityGroup
Description: Allow HTTPS access
SecurityGroupEgress:
- IpProtocol: -1
FromPort: 0
ToPort: 0
CidrIp: 0.0.0.0/0
Tags:
- Key: Name
Value: !Sub '${Prefix}-webserver-sg'
SbcSipSecurityGroup:
Type: AWS::EC2::SecurityGroup
Properties:
GroupName: !Sub '${Prefix}-sbc-sip-sg'
GroupDescription: !Sub 'Security group for ${Prefix} Sbc Sip Server'
VpcId: !Ref VPC
SecurityGroupIngress:
- IpProtocol: tcp
FromPort: 3000
ToPort: 3009
CidrIp: !Ref VpcCIDR
Description: Allow HTTP from sbc/api server
- IpProtocol: tcp
FromPort: 3010
ToPort: 3019
CidrIp: !Ref AllowedHttpCidr
Description: Allow http access from AWS SNS
- IpProtocol: tcp
FromPort: 5060
ToPort: 5060
CidrIp: !Ref AllowedSipCidr
Description: Allow sip (tcp) from Internet
- IpProtocol: udp
FromPort: 5060
ToPort: 5060
CidrIp: !Ref AllowedSipCidr
Description: Allow sip (udp) from Internet
- IpProtocol: tcp
Description: sip over wss
FromPort: 8443
ToPort: 8443
CidrIp: !Ref AllowedSipCidr
- IpProtocol: tcp
FromPort: 5061
ToPort: 5061
CidrIp: '52.114.148.0/32'
Description: sip (tls) for teams
- IpProtocol: tcp
FromPort: 5061
ToPort: 5061
CidrIp: '52.114.132.46/32'
Description: sip (tls) for teams
- IpProtocol: tcp
FromPort: 5061
ToPort: 5061
CidrIp: '52.114.75.24/32'
Description: sip (tls) for teams
- IpProtocol: tcp
FromPort: 5061
ToPort: 5061
CidrIp: '52.114.76.76/32'
Description: sip (tls) for teams
- IpProtocol: tcp
FromPort: 5061
ToPort: 5061
CidrIp: '52.114.7.24/32'
Description: sip (tls) for teams
- IpProtocol: tcp
FromPort: 5061
ToPort: 5061
CidrIp: '52.114.14.70/32'
Description: sip (tls) for teams
- IpProtocol: tcp
FromPort: 4433
ToPort: 4433
CidrIp: !Ref AllowedSipCidr
Description: Allow sip (wss) from Internet
- IpProtocol: tcp
FromPort: 2775
ToPort: 2775
CidrIp: !Ref AllowedSmppCidr
Description: Allow SMPP/tcp from Internet
- IpProtocol: tcp
FromPort: 3550
ToPort: 3550
CidrIp: !Ref AllowedSmppCidr
Description: Allow SMPP/tls from Internet
- IpProtocol: tcp
FromPort: 3020
ToPort: 3020
SourceSecurityGroupId: !Ref FeatureServerSecurityGroup
Description: Allow HTTP access from VPC to jambonz-smpp-esme
- IpProtocol: tcp
FromPort: 9090
ToPort: 9090
CidrIp: !Ref VpcCIDR
Description: Allow access to prometheus scrape port from VPC
- IpProtocol: udp
FromPort: 22224
ToPort: 22233
CidrIp: !Ref VpcCIDR
Description: Allow dtmf events from rtpengine-sidecar in the VPC
SecurityGroupEgress:
- IpProtocol: -1
FromPort: 0
ToPort: 0
CidrIp: 0.0.0.0/0
Tags:
- Key: Name
Value: !Sub '${Prefix}-sbc-sip-sg'
SbcRTPSecurityGroup:
Type: AWS::EC2::SecurityGroup
Properties:
GroupName: !Sub '${Prefix}-spc-rtp-sg'
GroupDescription: !Sub 'Security group for ${Prefix} sbc RTP'
VpcId: !Ref VPC
SecurityGroupIngress:
- IpProtocol: udp
FromPort: 40000
ToPort: 60000
CidrIp: !Ref AllowedRtpCidr
Description: Allow RTP from everywhere
- IpProtocol: udp
FromPort: 5060
ToPort: 5060
CidrIp: !Ref VpcCIDR
Description: Allow Freeswitch sip from VPC
- IpProtocol: udp
FromPort: 22222
ToPort: 22223
CidrIp: !Ref VpcCIDR
Description: Allow rtpengine ng protocol from VPC
- IpProtocol: tcp
FromPort: 8080
ToPort: 8080
CidrIp: !Ref VpcCIDR
Description: rtpengine ws protocol from VPC
- IpProtocol: tcp
FromPort: 3001
ToPort: 3001
CidrIp: !Ref AllowedHttpCidr
Description: Allow http access from AWS SNS
SecurityGroupEgress:
- IpProtocol: -1
FromPort: 0
ToPort: 0
CidrIp: 0.0.0.0/0
Tags:
- Key: Name
Value: !Sub '${Prefix}-spc-rtp-sg'
MonitoringSecurityGroup:
Type: AWS::EC2::SecurityGroup
Properties:
GroupName: !Sub '${Prefix}-monitoring-sg'
GroupDescription: !Sub 'Security group for ${Prefix} Monitoring'
VpcId: !Ref VPC
SecurityGroupIngress:
- IpProtocol: tcp
FromPort: 3000
ToPort: 3000
CidrIp: !Ref AllowedHttpCidr
Description: Allow grafana access
- IpProtocol: tcp
FromPort: 8086
ToPort: 8086
CidrIp: !Ref VpcCIDR
Description: Allow influxdb access from VPC
- IpProtocol: tcp
FromPort: 8088
ToPort: 8088
CidrIp: !Ref VpcCIDR
Description: Allow influxdb backup access from VPC
- IpProtocol: tcp
FromPort: 9080
ToPort: 9080
CidrIp: !Ref VpcCIDR
Description: Allow access to homer webapp
- IpProtocol: udp
FromPort: 9060
ToPort: 9060
CidrIp: !Ref VpcCIDR
Description: Allow access to homer HEP
- IpProtocol: tcp
FromPort: 1880
ToPort: 1880
CidrIp: !Ref AllowedHttpCidr
Description: Allow access to Node-RED
- IpProtocol: tcp
FromPort: 16686
ToPort: 16686
CidrIp: !Ref VpcCIDR
Description: Allow access to Jaeger
- IpProtocol: udp
FromPort: 6831
ToPort: 6831
CidrIp: !Ref VpcCIDR
Description: Jaeger collector - compact
- IpProtocol: udp
FromPort: 6832
ToPort: 6832
CidrIp: !Ref VpcCIDR
Description: Jaeger collector (udp)
- IpProtocol: tcp
FromPort: 14268
ToPort: 14268
CidrIp: !Ref VpcCIDR
Description: Jaeger collector (http)
SecurityGroupEgress:
- IpProtocol: -1
FromPort: 0
ToPort: 0
CidrIp: 0.0.0.0/0
Tags:
- Key: Name
Value: !Sub '${Prefix}-monitoring-sg'
###########################################
#
# Aurora RDS Database
#
###########################################
DatabaseSubnetGroup:
Type: AWS::RDS::DBSubnetGroup
Properties:
DBSubnetGroupName: !Sub '${Prefix}-aurora-mysql-subnetgroup'
DBSubnetGroupDescription: CloudFormation managed DB subnet group.
SubnetIds:
- !Ref PublicSubnet1
- !Ref PublicSubnet2
DatabaseCluster:
Type: AWS::RDS::DBCluster
Properties:
DBClusterIdentifier: !Sub '${Prefix}-aurora-mysql-cluster'
Engine: aurora
EngineVersion: '5.6.10a'
EngineMode: 'serverless'
MasterUsername: !Ref MySQLUsername
MasterUserPassword: !Ref MySQLPassword
DatabaseName: 'jambones'
BackupRetentionPeriod: 5
PreferredBackupWindow: "07:00-09:00"
DBSubnetGroupName: !Ref DatabaseSubnetGroup
VpcSecurityGroupIds:
- !Ref MySQLSecurityGroup
ScalingConfiguration:
AutoPause: false
MaxCapacity: !Ref AuroraDBMaxCapacity
MinCapacity: !Ref AuroraDBMinCapacity
###########################################
#
# ElastiCache Redis
#
###########################################
ElastiCacheSubnetGroup:
Type: 'AWS::ElastiCache::SubnetGroup'
Properties:
CacheSubnetGroupName: !Sub '${Prefix}-cache-subnetgroup'
Description: !Sub '${Prefix} Subnet Group'
SubnetIds:
- !Ref PublicSubnet1
- !Ref PublicSubnet2
ElastiCacheCluster:
Type: AWS::ElastiCache::CacheCluster
Properties:
Engine: redis
EngineVersion: "5.0.6"
CacheNodeType: !Ref ElastiCacheNodeType
ClusterName : !Sub '${Prefix}-redis'
NumCacheNodes: 1
CacheSubnetGroupName: !Ref ElastiCacheSubnetGroup
CacheParameterGroupName: 'default.redis5.0'
VpcSecurityGroupIds:
- !GetAtt RedisSecurityGroup.GroupId
Port: 6379
Tags:
- Key: Name
Value: !Sub '${Prefix}-redis'
###########################################
#
# Monitoring Instance
#
###########################################
MonitoringServerEC2:
Type: 'AWS::EC2::Instance'
Properties:
SubnetId: !Ref PublicSubnet1
ImageId: !FindInMap [ "AWSRegion2AMI", !Ref AWS::Region, "MonitoringServerAmi"]
InstanceType: !Ref InstanceTypeMonitoringServer
SecurityGroupIds:
- Ref: SshSecurityGroup
- Ref: MonitoringSecurityGroup
KeyName: !Ref KeyName
Monitoring: true
UserData:
Fn::Base64:
Fn::Sub:
- |
#!/bin/bash -xe
# restart heplify-server
sudo systemctl restart heplify-server
- EnableTracing: !Ref EnableTracing
Tags:
-
Key: Name
Value: !Sub '${Prefix}-monitoring-server'
###########################################
# New SBC SIP instances
# Create a couple of EIPs for SBC SIP Servers, and tag them as such
# Note: devops can create more EIPs later, the Environment tag
# is what caused them to get associated when sip servers scale.
# The idea is simply to have a pre-allocated set of N EIPs
# for sip signaling so these can be whitelisted with carriers
###########################################
SbcSipServerEIP1:
Type: AWS::EC2::EIP
Properties:
Domain: vpc
Tags:
-
Key: Environment
Value: !Sub '${Prefix}-sbc-sip'
-
Key: Name
Value: !Sub '${Prefix}-sbc-sip-1'
SbcSipServerEIP2:
Type: AWS::EC2::EIP
Properties:
Domain: vpc
Tags:
-
Key: Environment
Value: !Sub '${Prefix}-sbc-sip'
-
Key: Name
Value: !Sub '${Prefix}-sbc-sip-2'
# --- SIP server EC2 IAM role
SbcSipServerIamRole:
Type: AWS::IAM::Role
Properties:
Description: SBC RTP EC2 service role
RoleName: !Sub '${Prefix}-sbc-sip-ec2-role'
AssumeRolePolicyDocument:
Statement:
- Effect: Allow
Principal:
Service: [ec2.amazonaws.com]
Action: ['sts:AssumeRole']
Path: /
Policies:
- PolicyName: root
PolicyDocument:
Version: "2012-10-17"
Statement:
- Effect: Allow
Action:
- 'cloudwatch:PutMetricData'
- 'ec2:DescribeVolumes'
- 'ec2:DescribeTags'
- 'logs:PutLogEvents'
- 'logs:DescribeLogStreams'
- 'logs:DescribeLogGroups'
- 'logs:CreateLogStream'
- 'logs:CreateLogGroup'
Resource: '*'
- Effect: Allow
Action:
- 'ssm:GetParameter'
Resource: 'arn:aws:ssm:*:*:parameter/AmazonCloudWatch-*'
ManagedPolicyArns:
- arn:aws:iam::aws:policy/AmazonSNSFullAccess
- arn:aws:iam::aws:policy/AutoScalingReadOnlyAccess
- arn:aws:iam::aws:policy/AmazonEC2FullAccess
# --- SIP server EC2 Role Instance profile
SbcSipServerInstanceProfile:
Type: 'AWS::IAM::InstanceProfile'
Properties:
InstanceProfileName: !Sub '${Prefix}-sbc-sip-ec2-role'
Path: /
Roles:
- !Ref SbcSipServerIamRole
SbcSipConfig:
Type: AWS::AutoScaling::LaunchConfiguration
Properties:
ImageId: !FindInMap [ "AWSRegion2AMI", !Ref AWS::Region, "SbcSipAmi"]
SecurityGroups:
- Ref: SshSecurityGroup
- Ref: SbcSipSecurityGroup
InstanceType: !Ref InstanceTypeSbcSip
IamInstanceProfile: !Ref SbcSipServerInstanceProfile
KeyName: !Ref KeyName
AssociatePublicIpAddress: true
UserData:
Fn::Base64:
Fn::Sub:
- |
#!/bin/bash
echo "running jambonz user data script"
PRE_PUBLIC_IP=`curl -s http://169.254.169.254/latest/meta-data/public-ipv4`
echo "before retrieving EIP for SIP server, public IP is $PRE_PUBLIC_IP"
/usr/local/bin/auto-assign-elastic-ip.sh
sleep 15
PUBLIC_IP=`curl -s http://169.254.169.254/latest/meta-data/public-ipv4`
echo "after retrieving EIP for SIP server, public IP is $PUBLIC_IP"
echo "writing /home/admin/apps/ecosystem.config.js.."
cat << EOF > /home/admin/apps/ecosystem.config.js
module.exports = {
apps : [
{
name: 'jambonz-smpp-esme',
cwd: '/home/admin/apps/jambonz-smpp-esme',
script: 'app.js',
out_file: '/home/admin/.pm2/logs/jambonz-smpp-esme.log',
err_file: '/home/admin/.pm2/logs/jambonz-smpp-esme.log',
combine_logs: true,
instance_var: 'INSTANCE_ID',
exec_mode: 'fork',
instances: 1,
autorestart: true,
watch: false,
max_memory_restart: '1G',
env: {
NODE_ENV: 'production',
JAMBONES_LOGLEVEL: 'info',
JAMBONES_CLUSTER_ID: '${JAMBONES_CLUSTER_ID}',
AVOID_UDH: true,
JAMBONES_MYSQL_REFRESH_TTL: ${DbCachingTTS},
JAMBONES_MYSQL_HOST: '${JAMBONES_MYSQL_HOST}',
JAMBONES_MYSQL_USER: '${JAMBONES_MYSQL_USER}',
JAMBONES_MYSQL_PASSWORD: '${JAMBONES_MYSQL_PASSWORD}',
JAMBONES_MYSQL_DATABASE: 'jambones',
JAMBONES_MYSQL_CONNECTION_LIMIT: 10,
JAMBONES_REDIS_HOST: '${JAMBONES_REDIS_HOST}',
JAMBONES_REDIS_PORT: 6379,
HTTP_PORT: 3020
}
},
{
name: 'sbc-sip-sidecar',
cwd: '/home/admin/apps/sbc-sip-sidecar',
script: 'app.js',
instance_var: 'INSTANCE_ID',
out_file: '/home/admin/.pm2/logs/sbc-sip-sidecar.log',
err_file: '/home/admin/.pm2/logs/sbc-sip-sidecar.log',
exec_mode: 'fork',
instances: 1,
autorestart: true,
watch: false,
max_memory_restart: '1G',
env: {
NODE_ENV: 'production',
JAMBONES_CLUSTER_ID: '${JAMBONES_CLUSTER_ID}',
JAMBONES_LOGLEVEL: 'info',
DRACHTIO_HOST: '127.0.0.1',
DRACHTIO_PORT: 9022,
DRACHTIO_SECRET: 'cymru',
JAMBONES_MYSQL_REFRESH_TTL: ${DbCachingTTS},
JAMBONES_MYSQL_HOST: '${JAMBONES_MYSQL_HOST}',
JAMBONES_MYSQL_USER: '${JAMBONES_MYSQL_USER}',
JAMBONES_MYSQL_PASSWORD: '${JAMBONES_MYSQL_PASSWORD}',
JAMBONES_MYSQL_DATABASE: 'jambones',
JAMBONES_MYSQL_CONNECTION_LIMIT: 10,
JAMBONES_REDIS_HOST: '${JAMBONES_REDIS_HOST}',
JAMBONES_REDIS_PORT: 6379,
JAMBONES_TIME_SERIES_HOST: '${JAMBONES_TIME_SERIES_HOST}',
ENABLE_METRICS: 1,
STATS_HOST: '127.0.0.1',
STATS_PORT: 8125,
STATS_PROTOCOL: 'tcp',
STATS_TELEGRAF: 1,
STATS_SAMPLE_RATE: ${JAMBONES_SAMPLE_RATE},
JAMBONES_NETWORK_CIDR: '${VPC_CIDR}'
}
},
{
name: 'sbc-call-router',
cwd: '/home/admin/apps/sbc-call-router',
script: 'app.js',
instance_var: 'INSTANCE_ID',
out_file: '/home/admin/.pm2/logs/jambonz-sbc-call-router.log',
err_file: '/home/admin/.pm2/logs/jambonz-sbc-call-router.log',
exec_mode: 'fork',
instances: 1,
autorestart: true,
watch: false,
max_memory_restart: '1G',
env: {
NODE_ENV: 'production',
HTTP_PORT: 4000,
JAMBONES_INBOUND_ROUTE: '127.0.0.1:4002',
JAMBONES_OUTBOUND_ROUTE: '127.0.0.1:4003',
JAMBONZ_TAGGED_INBOUND: 1,
ENABLE_METRICS: 1,
STATS_HOST: '127.0.0.1',
STATS_PORT: 8125,
STATS_PROTOCOL: 'tcp',
STATS_TELEGRAF: 1,
STATS_SAMPLE_RATE: ${JAMBONES_SAMPLE_RATE},
JAMBONES_NETWORK_CIDR: '${VPC_CIDR}'
}
},
{
name: 'sbc-outbound',
cwd: '/home/admin/apps/sbc-outbound',
script: 'app.js',
instance_var: 'INSTANCE_ID',
out_file: '/home/admin/.pm2/logs/jambonz-sbc-outbound.log',
err_file: '/home/admin/.pm2/logs/jambonz-sbc-outbound.log',
exec_mode: 'fork',
instances: 1,
autorestart: true,
watch: false,
max_memory_restart: '1G',
env: {
NODE_ENV: 'production',
JAMBONES_LOGLEVEL: 'info',
JAMBONES_NETWORK_CIDR: '${VPC_CIDR}',
MIN_CALL_LIMIT: 9999,
RTPENGINE_PING_INTERVAL: 30000,
DRACHTIO_HOST: '127.0.0.1',
DRACHTIO_PORT: 9022,
DRACHTIO_SECRET: 'cymru',
JAMBONES_MYSQL_REFRESH_TTL: ${DbCachingTTS},
JAMBONES_MYSQL_HOST: '${JAMBONES_MYSQL_HOST}',
JAMBONES_MYSQL_USER: '${JAMBONES_MYSQL_USER}',
JAMBONES_MYSQL_PASSWORD: '${JAMBONES_MYSQL_PASSWORD}',
JAMBONES_MYSQL_DATABASE: 'jambones',
JAMBONES_MYSQL_CONNECTION_LIMIT: 10,
JAMBONES_REDIS_HOST: '${JAMBONES_REDIS_HOST}',
JAMBONES_REDIS_PORT: 6379,
JAMBONES_CLUSTER_ID: '${JAMBONES_CLUSTER_ID}',
JAMBONES_TIME_SERIES_HOST: '${JAMBONES_TIME_SERIES_HOST}',
ENABLE_METRICS: 1,
STATS_HOST: '127.0.0.1',
STATS_PORT: 8125,
STATS_PROTOCOL: 'tcp',
STATS_SAMPLE_RATE: ${JAMBONES_SAMPLE_RATE},
STATS_TELEGRAF: 1
}
},
{
name: 'sbc-inbound',
cwd: '/home/admin/apps/sbc-inbound',
script: 'app.js',
instance_var: 'INSTANCE_ID',
out_file: '/home/admin/.pm2/logs/jambonz-sbc-inbound.log',
err_file: '/home/admin/.pm2/logs/jambonz-sbc-inbound.log',
exec_mode: 'fork',
instances: 'max',
autorestart: true,
watch: false,
max_memory_restart: '1G',
env: {
NODE_ENV: 'production',
JAMBONES_NETWORK_CIDR: '${VPC_CIDR}',
JAMBONES_LOGLEVEL: 'info',
AWS_REGION: '${AWS_REGION}',
DRACHTIO_HOST: '127.0.0.1',
DRACHTIO_PORT: 9022,
DRACHTIO_SECRET: 'cymru',
AWS_SNS_TOPIC_ARM: '${AWS_SNS_TOPIC_ARN}',
HTTP_PORT: 3000,
HTTP_PORT_MAX: 3009,
AWS_SNS_PORT: 3010,
AWS_SNS_PORT_MAX: 3019,
JAMBONES_MYSQL_REFRESH_TTL: ${DbCachingTTS},
JAMBONES_MYSQL_HOST: '${JAMBONES_MYSQL_HOST}',
JAMBONES_MYSQL_USER: '${JAMBONES_MYSQL_USER}',
JAMBONES_MYSQL_PASSWORD: '${JAMBONES_MYSQL_PASSWORD}',
JAMBONES_MYSQL_DATABASE: 'jambones',
JAMBONES_MYSQL_CONNECTION_LIMIT: 10,
JAMBONES_REDIS_HOST: '${JAMBONES_REDIS_HOST}',
JAMBONES_REDIS_PORT: 6379,
JAMBONES_CLUSTER_ID: '${JAMBONES_CLUSTER_ID}',
JAMBONES_TIME_SERIES_HOST: '${JAMBONES_TIME_SERIES_HOST}',
ENABLE_METRICS: 1,
STATS_HOST: '127.0.0.1',
STATS_PORT: 8125,
STATS_PROTOCOL: 'tcp',
STATS_TELEGRAF: 1,
STATS_SAMPLE_RATE: ${JAMBONES_SAMPLE_RATE},
MS_TEAMS_SIP_PROXY_IPS: '52.114.148.0, 52.114.132.46, 52.114.75.24, 52.114.76.76, 52.114.7.24, 52.114.14.70'
}
}
]
};
EOF
echo "finished writing config file"
echo "restarting telegraf"
# configure telegraph to send to the monitoring server
sudo sed -i -e "s/influxdb:8086/${MONITORING_SERVER_IP}:8086/g" /etc/telegraf/telegraf.conf
sudo systemctl restart telegraf
echo "enabling HEP and restarting drachtio server"
sudo sed -i -e "s/--address 0.0.0.0 --port 9022/--address 0.0.0.0 --port 9022 --homer ${MONITORING_SERVER_IP}:9060 --homer-id 10/g" /etc/systemd/system/drachtio.service
sudo systemctl daemon-reload
sudo systemctl restart drachtio
echo "starting jambonz apps"
sudo -u admin bash -c "pm2 restart /home/admin/apps/ecosystem.config.js"
sudo env PATH=$PATH:/usr/bin /usr/lib/node_modules/pm2/bin/pm2 startup systemd -u admin --hp /home/admin
sudo -u admin bash -c "pm2 save"
sudo systemctl enable pm2-admin.service
echo "enabling cloudwatch"
sudo sed -i -e "s/retention_in_days\": 3/retention_in_days\": ${CloudwatchLogRetention}/g" /opt/aws/amazon-cloudwatch-agent/bin/config.json
sudo /opt/aws/amazon-cloudwatch-agent/bin/amazon-cloudwatch-agent-ctl -a fetch-config -m ec2 -s -c file:/opt/aws/amazon-cloudwatch-agent/bin/config.json
echo "user data script completed"
- VPC_CIDR: !Ref VpcCIDR
AWS_REGION: !Ref AWS::Region
JAMBONES_MYSQL_HOST: !GetAtt DatabaseCluster.Endpoint.Address
JAMBONES_MYSQL_USER: !Ref MySQLUsername
JAMBONES_MYSQL_PASSWORD: !Ref MySQLPassword
JAMBONES_REDIS_HOST: !GetAtt ElastiCacheCluster.RedisEndpoint.Address
JAMBONES_CLUSTER_ID: !Ref Prefix
JAMBONES_SAMPLE_RATE: !Ref StatsSampleRate
MONITORING_SERVER_IP: !GetAtt MonitoringServerEC2.PrivateIp
AWS_SNS_TOPIC_ARN: !Ref SbcSipServerSNSTopic
JAMBONES_TIME_SERIES_HOST: !GetAtt MonitoringServerEC2.PrivateIp
CloudwatchLogRetention: !Ref CloudwatchLogRetention
DbCachingTTS: !Ref DbCachingTTS
SbcSipServerPlacementGroup:
Type: AWS::EC2::PlacementGroup
Properties:
Strategy: spread
SbcSipServerAutoScalingGroup:
Type: AWS::AutoScaling::AutoScalingGroup
Properties:
AutoScalingGroupName: !Sub '${Prefix}-sbc-sip-autoscaling-group'
LaunchConfigurationName: !Ref SbcSipConfig
MinSize: 1
MaxSize: 4
DesiredCapacity: 1
TerminationPolicies:
- OldestInstance
VPCZoneIdentifier:
- !Ref PublicSubnet1
- !Ref PublicSubnet2
Tags:
-
Key: Name
Value: !Sub '${Prefix}-sip-server'
PropagateAtLaunch: 'true'
-
Key: Environment
Value: !Sub '${Prefix}-sbc-sip'
PropagateAtLaunch: 'true'
SbcSipServerSNSTopic:
Type: AWS::SNS::Topic
Properties:
TopicName: !Sub '${Prefix}-${AWS::Region}-sip-lifecycle-events'
SbcSipServerSNSPublishRole:
Type: "AWS::IAM::Role"
Properties:
AssumeRolePolicyDocument:
Version: 2012-10-17
Statement:
- Effect: Allow
Principal:
Service:
- autoscaling.amazonaws.com
Action:
- "sts:AssumeRole"
ManagedPolicyArns:
- "arn:aws:iam::aws:policy/service-role/AutoScalingNotificationAccessRole"
SbcSipServerLifecycleHook:
Type: AWS::AutoScaling::LifecycleHook
Properties:
LifecycleHookName: !Sub '${Prefix}-sip-scale-in'
AutoScalingGroupName: !Ref SbcSipServerAutoScalingGroup
LifecycleTransition: "autoscaling:EC2_INSTANCE_TERMINATING"
NotificationTargetARN: !Ref SbcSipServerSNSTopic
RoleARN: !GetAtt SbcSipServerSNSPublishRole.Arn
###########################################
#
# Feature Instance
#
###########################################
# --- Feature server EC2 IAM role
FeatureServerIamRole:
Type: AWS::IAM::Role
Properties:
Description: Feature Server EC2 service role
RoleName: !Sub '${Prefix}-feature-server-ec2-role'
AssumeRolePolicyDocument:
Statement:
- Effect: Allow
Principal:
Service: [ec2.amazonaws.com]
Action: ['sts:AssumeRole']
Path: /
Policies:
- PolicyName: root
PolicyDocument:
Version: "2012-10-17"
Statement:
- Effect: Allow
Action:
- 'cloudwatch:PutMetricData'
- 'ec2:DescribeVolumes'
- 'ec2:DescribeTags'
- 'logs:PutLogEvents'
- 'logs:DescribeLogStreams'
- 'logs:DescribeLogGroups'
- 'logs:CreateLogStream'
- 'logs:CreateLogGroup'
Resource: '*'
- Effect: Allow
Action:
- 'ssm:GetParameter'
Resource: 'arn:aws:ssm:*:*:parameter/AmazonCloudWatch-*'
ManagedPolicyArns:
- arn:aws:iam::aws:policy/AmazonSNSFullAccess
- arn:aws:iam::aws:policy/AutoScalingReadOnlyAccess
# --- Feature server EC2 Role Instance profile
FeatureServerInstanceProfile:
Type: 'AWS::IAM::InstanceProfile'
Properties:
InstanceProfileName: !Sub '${Prefix}-feature-server-ec2-role'
Path: /
Roles:
- !Ref FeatureServerIamRole
FeatureServerConfig:
Type: AWS::AutoScaling::LaunchConfiguration
Properties:
ImageId: !FindInMap [ "AWSRegion2AMI", !Ref AWS::Region, "FsAmi"]
SecurityGroups:
- Ref: SshSecurityGroup
- Ref: FeatureServerSecurityGroup
InstanceType: !Ref InstanceTypeFeatureServer
IamInstanceProfile: !Ref FeatureServerInstanceProfile
KeyName: !Ref KeyName
AssociatePublicIpAddress: true
UserData:
Fn::Base64:
Fn::Sub:
- |
#!/bin/bash -e
#
# Cache a bucket name on this host
echo "running jambonz user data script"
echo "writing /home/admin/apps/ecosystem.config.js.."
cat << EOF > /home/admin/apps/ecosystem.config.js
module.exports = {
apps : [
{
name: 'jambonz-feature-server',
cwd: '/home/admin/apps/jambonz-feature-server',
script: 'app.js',
instance_var: 'INSTANCE_ID',
out_file: '/home/admin/.pm2/logs/jambonz-feature-server.log',
err_file: '/home/admin/.pm2/logs/jambonz-feature-server.log',
exec_mode: 'fork',
instances: 'max',
autorestart: true,
watch: false,
max_memory_restart: '1G',
env: {
NODE_ENV: 'production',
ENABLE_METRICS: 1,
STATS_HOST: '127.0.0.1',
STATS_PORT: 8125,
STATS_PROTOCOL: 'tcp',
STATS_TELEGRAF: 1,
STATS_SAMPLE_RATE: ${JAMBONES_SAMPLE_RATE},
JAMBONES_OTEL_ENABLED: ${OTEL_TRACING},
OTEL_EXPORTER_JAEGER_ENDPOINT: 'http://${MONITORING_SERVER_IP}:14268/api/traces',
OTEL_EXPORTER_OTLP_METRICS_INSECURE: 1,
OTEL_EXPORTER_JAEGER_GRPC_INSECURE: 1,
AWS_SNS_TOPIC_ARM: '${AWS_SNS_TOPIC_ARN}',
AWS_REGION: '${AWS_REGION}',
JAMBONES_NETWORK_CIDR: '${VPC_CIDR}',
JAMBONES_MYSQL_REFRESH_TTL: ${DbCachingTTS},
JAMBONES_MYSQL_HOST: '${JAMBONES_MYSQL_HOST}',
JAMBONES_MYSQL_USER: '${JAMBONES_MYSQL_USER}',
JAMBONES_MYSQL_PASSWORD: '${JAMBONES_MYSQL_PASSWORD}',
JAMBONES_MYSQL_DATABASE: 'jambones',
JAMBONES_MYSQL_CONNECTION_LIMIT: 10,
JAMBONES_REDIS_HOST: '${JAMBONES_REDIS_HOST}',
JAMBONES_REDIS_PORT: 6379,
JAMBONES_LOGLEVEL: 'info',
JAMBONES_TIME_SERIES_HOST: '${JAMBONES_TIME_SERIES_HOST}',
HTTP_PORT: 3000,
HTTP_PORT_MAX: 3009,
AWS_SNS_PORT: 3010,
AWS_SNS_PORT_MAX: 3019,
DRACHTIO_HOST: '127.0.0.1',
DRACHTIO_PORT: 9022,
DRACHTIO_SECRET: 'cymru',
JAMBONES_CLUSTER_ID: '${JAMBONES_CLUSTER_ID}',
JAMBONES_FEATURE_SERVERS: '127.0.0.1:9022:cymru',
JAMBONES_FREESWITCH: '127.0.0.1:8021:JambonzR0ck$',
JWT_SECRET: '${JWT_SECRET}'
}
}]
};
EOF
echo "finished writing config file"
sudo -u admin bash -c "pm2 start /home/admin/apps/ecosystem.config.js"
sudo env PATH=$PATH:/usr/bin /usr/lib/node_modules/pm2/bin/pm2 startup systemd -u admin --hp /home/admin
sudo -u admin bash -c "pm2 save"
sudo systemctl enable pm2-admin.service
# configure telegraph to send to the monitoring server
sudo sed -i -e "s/influxdb:8086/${MONITORING_SERVER_IP}:8086/g" /etc/telegraf/telegraf.conf
sudo systemctl restart telegraf
echo "enabling cloudwatch"
sudo sed -i -e "s/retention_in_days\": 3/retention_in_days\": ${CloudwatchLogRetention}/g" /opt/aws/amazon-cloudwatch-agent/bin/config.json
sudo /opt/aws/amazon-cloudwatch-agent/bin/amazon-cloudwatch-agent-ctl -a fetch-config -m ec2 -s -c file:/opt/aws/amazon-cloudwatch-agent/bin/config.json
echo "user data script completed"
- VPC_CIDR: !Ref VpcCIDR
JAMBONES_MYSQL_HOST: !GetAtt DatabaseCluster.Endpoint.Address
JAMBONES_MYSQL_USER: !Ref MySQLUsername
JAMBONES_MYSQL_PASSWORD: !Ref MySQLPassword
JAMBONES_REDIS_HOST: !GetAtt ElastiCacheCluster.RedisEndpoint.Address
AWS_SNS_TOPIC_ARN: !Ref FeatureServerSNSTopic
AWS_REGION: !Ref AWS::Region
JAMBONES_SAMPLE_RATE: !Ref StatsSampleRate
OTEL_TRACING: !Ref EnableTracing
JAMBONES_CLUSTER_ID: !Ref Prefix
MONITORING_SERVER_IP: !GetAtt MonitoringServerEC2.PrivateIp
JAMBONES_TIME_SERIES_HOST: !GetAtt MonitoringServerEC2.PrivateIp
JWT_SECRET: !Ref EncryptionSecret
CloudwatchLogRetention: !Ref CloudwatchLogRetention
DbCachingTTS: !Ref DbCachingTTS
FeatureServerPlacementGroup:
Type: AWS::EC2::PlacementGroup
Properties:
Strategy: spread
FeatureServerAutoScalingGroup:
Type: AWS::AutoScaling::AutoScalingGroup
Properties:
AutoScalingGroupName: !Sub '${Prefix}-feature-server-autoscaling-group'
LaunchConfigurationName: !Ref FeatureServerConfig
MinSize: 1
MaxSize: 2
DesiredCapacity: 1
TerminationPolicies:
- OldestInstance
VPCZoneIdentifier:
- !Ref PublicSubnet1
- !Ref PublicSubnet2
Tags:
-
Key: Name
Value: !Sub '${Prefix}-feature-server'
PropagateAtLaunch: 'true'
FeatureServerSNSTopic:
Type: AWS::SNS::Topic
Properties:
TopicName: !Sub '${Prefix}-${AWS::Region}-fs-lifecycle-events'
FeatureServerSNSPublishRole:
Type: "AWS::IAM::Role"
Properties:
AssumeRolePolicyDocument:
Version: 2012-10-17
Statement:
- Effect: Allow
Principal:
Service:
- autoscaling.amazonaws.com
Action:
- "sts:AssumeRole"
ManagedPolicyArns:
- "arn:aws:iam::aws:policy/service-role/AutoScalingNotificationAccessRole"
FeatureServerLifecycleHook:
Type: AWS::AutoScaling::LifecycleHook
Properties:
LifecycleHookName: !Sub '${Prefix}-fs-scale-in'
AutoScalingGroupName: !Ref FeatureServerAutoScalingGroup
LifecycleTransition: "autoscaling:EC2_INSTANCE_TERMINATING"
NotificationTargetARN: !Ref FeatureServerSNSTopic
RoleARN: !GetAtt FeatureServerSNSPublishRole.Arn
###########################################
#
# SBC RTP Instance
#
###########################################
# --- Feature server EC2 IAM role
SbcRTPServerIamRole:
Type: AWS::IAM::Role
Properties:
Description: SBC RTP EC2 service role
RoleName: !Sub '${Prefix}-sbc-rtp-ec2-role'
AssumeRolePolicyDocument:
Statement:
- Effect: Allow
Principal:
Service: [ec2.amazonaws.com]
Action: ['sts:AssumeRole']
Path: /
Policies:
- PolicyName: root
PolicyDocument:
Version: "2012-10-17"
Statement:
- Effect: Allow
Action:
- 'cloudwatch:PutMetricData'
- 'ec2:DescribeVolumes'
- 'ec2:DescribeTags'
- 'logs:PutLogEvents'
- 'logs:DescribeLogStreams'
- 'logs:DescribeLogGroups'
- 'logs:CreateLogStream'
- 'logs:CreateLogGroup'
Resource: '*'
- Effect: Allow
Action:
- 'ssm:GetParameter'
Resource: 'arn:aws:ssm:*:*:parameter/AmazonCloudWatch-*'
ManagedPolicyArns:
- arn:aws:iam::aws:policy/AmazonSNSFullAccess
- arn:aws:iam::aws:policy/AutoScalingReadOnlyAccess
# --- SBC RTP EC2 Role Instance profile
SbcRTPServerInstanceProfile:
Type: 'AWS::IAM::InstanceProfile'
Properties:
InstanceProfileName: !Sub '${Prefix}-sbc-rtp-ec2-role'
Path: /
Roles:
- !Ref SbcRTPServerIamRole
SbcRTPConfig:
Type: AWS::AutoScaling::LaunchConfiguration
Properties:
ImageId: !FindInMap [ "AWSRegion2AMI", !Ref AWS::Region, "SbcRtpAmi"]
SecurityGroups:
- Ref: SshSecurityGroup
- Ref: SbcRTPSecurityGroup
InstanceType: !Ref InstanceTypeSbcRtp
IamInstanceProfile: !Ref SbcRTPServerInstanceProfile
KeyName: !Ref KeyName
AssociatePublicIpAddress: true
UserData:
Fn::Base64:
Fn::Sub:
- |
#!/bin/bash
echo "writing /home/admin/apps/ecosystem.config.js.."
cat << EOF > /home/admin/apps/ecosystem.config.js
module.exports = {
apps : [
{
name: 'sbc-rtpengine-sidecar',
cwd: '/home/admin/apps/sbc-rtpengine-sidecar',
script: 'app.js',
instance_var: 'INSTANCE_ID',
out_file: '/home/admin/.pm2/logs/jambonz-sbc-rtpengine-sidecar.log',
err_file: '/home/admin/.pm2/logs/jambonz-sbc-rtpengine-sidecar.log',
exec_mode: 'fork',
instances: 1,
autorestart: true,
watch: false,
max_memory_restart: '1G',
env: {
NODE_ENV: 'production',
LOGLEVEL: 'info',
RTPENGINE_DTMF_LOG_PORT: 22223,
AWS_SNS_TOPIC_ARM: '${AWS_SNS_TOPIC_ARN}',
AWS_REGION: '${AWS_REGION}',
JAMBONES_CLUSTER_ID: '${JAMBONES_CLUSTER_ID}',
JAMBONES_REDIS_HOST: '${JAMBONES_REDIS_HOST}',
JAMBONES_REDIS_PORT: 6379,
AWS_SNS_PORT: 3001,
ENABLE_METRICS: 1,
STATS_HOST: '127.0.0.1',
STATS_PORT: 8125,
STATS_PROTOCOL: 'tcp',
STATS_SAMPLE_RATE: ${JAMBONES_SAMPLE_RATE},
STATS_TELEGRAF: 1
}
}
]
};
EOF
echo "finished writing config file"
sudo -u admin bash -c "pm2 start /home/admin/apps/ecosystem.config.js"
sudo env PATH=$PATH:/usr/bin /usr/lib/node_modules/pm2/bin/pm2 startup systemd -u admin --hp /home/admin
sudo -u admin bash -c "pm2 save"
sudo systemctl enable pm2-admin.service
# configure telegraph to send to the monitoring server
sudo sed -i -e "s/influxdb:8086/${MONITORING_SERVER_IP}:8086/g" /etc/telegraf/telegraf.conf
sudo systemctl restart telegraf
# point rtpengine to the HEP endpoint on the monitoring server
sudo sed -i -e "s/--delete-delay 0/--delete-delay 0 --homer=${MONITORING_SERVER_IP}:9060 --homer-protocol=udp --homer-id=11/g" /etc/systemd/system/rtpengine.service
sudo systemctl daemon-reload
sudo sytemctl restart rtpengine
echo "enabling cloudwatch"
sudo sed -i -e "s/retention_in_days\": 3/retention_in_days\": ${CloudwatchLogRetention}/g" /opt/aws/amazon-cloudwatch-agent/bin/config.json
sudo /opt/aws/amazon-cloudwatch-agent/bin/amazon-cloudwatch-agent-ctl -a fetch-config -m ec2 -s -c file:/opt/aws/amazon-cloudwatch-agent/bin/config.json
- VPC_CIDR: !Ref VpcCIDR
AWS_REGION: !Ref AWS::Region
JAMBONES_MYSQL_HOST: !GetAtt DatabaseCluster.Endpoint.Address
JAMBONES_MYSQL_USER: !Ref MySQLUsername
JAMBONES_MYSQL_PASSWORD: !Ref MySQLPassword
JAMBONES_CLUSTER_ID: !Ref Prefix
JAMBONES_SAMPLE_RATE: !Ref StatsSampleRate
JAMBONES_REDIS_HOST: !GetAtt ElastiCacheCluster.RedisEndpoint.Address
AWS_SNS_TOPIC_ARN: !Ref SbcRTPServerSNSTopic
MONITORING_SERVER_IP: !GetAtt MonitoringServerEC2.PrivateIp
CloudwatchLogRetention: !Ref CloudwatchLogRetention
SbcRTPServerPlacementGroup:
Type: AWS::EC2::PlacementGroup
Properties:
Strategy: spread
SbcRTPServerAutoScalingGroup:
Type: AWS::AutoScaling::AutoScalingGroup
Properties:
AutoScalingGroupName: !Sub '${Prefix}-sbc-rtp-autoscaling-group'
LaunchConfigurationName: !Ref SbcRTPConfig
MinSize: 1
MaxSize: 4
DesiredCapacity: 1
TerminationPolicies:
- OldestInstance
VPCZoneIdentifier:
- !Ref PublicSubnet1
- !Ref PublicSubnet2
Tags:
-
Key: Name
Value: !Sub '${Prefix}-rtp-server'
PropagateAtLaunch: 'true'
SbcRTPServerSNSTopic:
Type: AWS::SNS::Topic
Properties:
TopicName: !Sub '${Prefix}-${AWS::Region}-rtp-lifecycle-events'
SbcRTPServerSNSPublishRole:
Type: "AWS::IAM::Role"
Properties:
AssumeRolePolicyDocument:
Version: 2012-10-17
Statement:
- Effect: Allow
Principal:
Service:
- autoscaling.amazonaws.com
Action:
- "sts:AssumeRole"
ManagedPolicyArns:
- "arn:aws:iam::aws:policy/service-role/AutoScalingNotificationAccessRole"
SbcRTPServerLifecycleHook:
Type: AWS::AutoScaling::LifecycleHook
Properties:
LifecycleHookName: !Sub '${Prefix}-rtp-scale-in'
AutoScalingGroupName: !Ref SbcRTPServerAutoScalingGroup
LifecycleTransition: "autoscaling:EC2_INSTANCE_TERMINATING"
NotificationTargetARN: !Ref SbcRTPServerSNSTopic
RoleARN: !GetAtt SbcRTPServerSNSPublishRole.Arn
###########################################
#
# WebServer Instance
#
###########################################
WebServerEIP1:
Type: AWS::EC2::EIP
Properties:
Domain: vpc
Tags:
-
Key: Name
Value: !Sub '${Prefix}-webserver'
-
Key: Environment
Value: !Sub '${Prefix}-webserver'
# --- Web server EC2 IAM role
WebServerIamRole:
Type: AWS::IAM::Role
Properties:
Description: Webserver EC2 service role
RoleName: !Sub '${Prefix}-webserver-ec2-role'
AssumeRolePolicyDocument:
Statement:
- Effect: Allow
Principal:
Service: [ec2.amazonaws.com]
Action: ['sts:AssumeRole']
Path: /
Policies:
- PolicyName: root
PolicyDocument:
Version: "2012-10-17"
Statement:
- Effect: Allow
Action:
- 'cloudwatch:PutMetricData'
- 'ec2:DescribeVolumes'
- 'ec2:DescribeTags'
- 'logs:PutLogEvents'
- 'logs:DescribeLogStreams'
- 'logs:DescribeLogGroups'
- 'logs:CreateLogStream'
- 'logs:CreateLogGroup'
Resource: '*'
- Effect: Allow
Action:
- 'ssm:GetParameter'
Resource: 'arn:aws:ssm:*:*:parameter/AmazonCloudWatch-*'
ManagedPolicyArns:
- arn:aws:iam::aws:policy/AmazonEC2FullAccess
- arn:aws:iam::aws:policy/AutoScalingReadOnlyAccess
# --- Webserver EC2 Role Instance profile
WebServerInstanceProfile:
Type: 'AWS::IAM::InstanceProfile'
Properties:
InstanceProfileName: !Sub '${Prefix}-webserver-ec2-role'
Path: /
Roles:
- !Ref WebServerIamRole
WebServerConfig:
Type: AWS::AutoScaling::LaunchConfiguration
Properties:
ImageId: !FindInMap [ "AWSRegion2AMI", !Ref AWS::Region, "WebserverAmi"]
SecurityGroups:
- Ref: SshSecurityGroup
- Ref: WebserverSecurityGroup
IamInstanceProfile: !Ref WebServerInstanceProfile
InstanceType: !Ref InstanceTypeWebserver
KeyName: !Ref KeyName
AssociatePublicIpAddress: true
UserData:
Fn::Base64:
Fn::Sub:
- |
#!/bin/bash
PRE_PUBLIC_IP=`curl -s http://169.254.169.254/latest/meta-data/public-ipv4`
echo "before retrieving EIP for web server, public IP is $PRE_PUBLIC_IP"
/usr/local/bin/auto-assign-elastic-ip.sh
sleep 15
PUBLIC_IP=`curl -s http://169.254.169.254/latest/meta-data/public-ipv4`
echo "after retrieving EIP for web server, public IP is $PUBLIC_IP"
echo "running jambonz webserver user data script"
# seed database
mysql -h ${JAMBONES_MYSQL_HOST} -u admin -D jambones -p${JAMBONES_MYSQL_PASSWORD} -e "select count(*) from accounts"
ret=$?
if [ $ret -ne 0 ]; then
mysql -h ${JAMBONES_MYSQL_HOST} -u admin -D jambones -p${JAMBONES_MYSQL_PASSWORD} < /home/admin/apps/jambonz-api-server/db/jambones-sql.sql
mysql -h ${JAMBONES_MYSQL_HOST} -u admin -D jambones -p${JAMBONES_MYSQL_PASSWORD} < /home/admin/apps/jambonz-api-server/db/seed-production-database-open-source.sql
JAMBONES_MYSQL_HOST=${JAMBONES_MYSQL_HOST} JAMBONES_MYSQL_USER=admin JAMBONES_MYSQL_PASSWORD=${JAMBONES_MYSQL_PASSWORD} JAMBONES_MYSQL_DATABASE=jambones /home/admin/apps/jambonz-api-server/db/reset_admin_password.js
fi
# jambonz webapp
echo "configuring webapp.."
echo "VITE_API_BASE_URL=http://${URLPortal}/api/v1" > /home/admin/apps/jambonz-webapp/.env
API_BASE_URL=http://${URLPortal}/api/v1 TAG="<script>window.JAMBONZ = { API_BASE_URL: '$API_BASE_URL'};</script>"
sed -i -e "\@</head>@i\ $TAG" /home/admin/apps/jambonz-webapp/dist/index.html
echo "writing /home/admin/apps/ecosystem.config.js.."
cat << EOF > /home/admin/apps/ecosystem.config.js
module.exports = {
apps : [
{
name: 'jambonz-api-server',
cwd: '/home/admin/apps/jambonz-api-server',
script: 'app.js',
out_file: '/home/admin/.pm2/logs/jambonz-api-server.log',
err_file: '/home/admin/.pm2/logs/jambonz-api-server.log',
combine_logs: true,
instance_var: 'INSTANCE_ID',
exec_mode: 'fork',
instances: 1,
autorestart: true,
watch: false,
max_memory_restart: '1G',
env: {
NODE_ENV: 'production',
JAMBONES_MYSQL_REFRESH_TTL: ${DbCachingTTS},
JAMBONES_MYSQL_HOST: '${JAMBONES_MYSQL_HOST}',
JAMBONES_MYSQL_USER: '${JAMBONES_MYSQL_USER}',
JAMBONES_MYSQL_PASSWORD: '${JAMBONES_MYSQL_PASSWORD}',
JAMBONES_MYSQL_DATABASE: 'jambones',
JAMBONES_MYSQL_CONNECTION_LIMIT: 10,
JAMBONES_REDIS_HOST: '${JAMBONES_REDIS_HOST}',
JAMBONES_REDIS_PORT: 6379,
JAMBONES_LOGLEVEL: 'info',
JAMBONE_API_VERSION: 'v1',
AWS_REGION: '${AWS_REGION}',
JAMBONES_CLUSTER_ID: '${JAMBONES_CLUSTER_ID}',
JAMBONES_TIME_SERIES_HOST: '${JAMBONES_TIME_SERIES_HOST}',
ENABLE_METRICS: 1,
STATS_HOST: '127.0.0.1',
STATS_PORT: 8125,
STATS_PROTOCOL: 'tcp',
STATS_TELEGRAF: 1,
STATS_SAMPLE_RATE: ${JAMBONES_SAMPLE_RATE},
HTTP_PORT: 3000,
HOMER_BASE_URL: 'http://${MONITORING_SERVER_IP}:9080',
HOMER_USERNAME: 'admin',
HOMER_PASSWORD: 'sipcapture',
JWT_SECRET: '${JWT_SECRET}'
},
},
{
name: 'jambonz-webapp',
script: 'npm',
cwd: '/home/admin/apps/jambonz-webapp',
args: 'run serve'
},
{
name: 'public-apps',
cwd: '/home/admin/apps/public-apps',
script: 'app.js',
out_file: '/home/admin/.pm2/logs/public-apps',
err_file: '/home/admin/.pm2/logs/public-apps',
combine_logs: true,
instance_var: 'INSTANCE_ID',
exec_mode: 'fork',
instances: 1,
autorestart: true,
watch: false,
max_memory_restart: '1G',
env: {
NODE_ENV: 'production',
LOGLEVEL: 'info',
NRC_TIME_SERVICE_DID: '+16137451576'
}
}]
};
EOF
echo "finished writing config file"
echo "building jambonz-api-server"
sudo -u admin bash -c "cd /home/admin/apps/jambonz-api-server && npm ci"
sudo -u admin bash -c "pm2 start /home/admin/apps/ecosystem.config.js"
sudo env PATH=$PATH:/usr/bin /usr/lib/node_modules/pm2/bin/pm2 startup systemd -u admin --hp /home/admin
sudo -u admin bash -c "pm2 save"
sudo systemctl enable pm2-admin.service
# configure telegraph to send to the monitoring server
sudo sed -i -e "s/influxdb:8086/${MONITORING_SERVER_IP}:8086/g" /etc/telegraf/telegraf.conf
sudo systemctl restart telegraf
# configure nginx for homer and grafana on the monitoring server
#Add BasicAuth password for Jaeger
sudo htpasswd -b -c /etc/nginx/.htpasswd ${JaegerUsername} "${JaegerPassword}"
sudo cat << EOF > /etc/nginx/sites-available/default
server {
listen 80;
server_name ${URLPortal};
location /api/ {
rewrite ^/api/(.*)$ /\$1 break;
proxy_pass http://localhost:3000;
proxy_set_header Host \$host;
}
location / {
proxy_pass http://localhost:3001;
proxy_set_header Host \$host;
}
}
server {
listen 80;
server_name api.${URLPortal};
location / {
proxy_pass http://localhost:3000;
proxy_set_header Host \$host;
}
}
server {
listen 80;
server_name grafana.${URLPortal};
location / {
proxy_pass http://${MONITORING_SERVER_IP}:3000;
proxy_http_version 1.1;
proxy_set_header Upgrade \$http_upgrade;
proxy_set_header Connection 'upgrade';
proxy_set_header Host \$host;
proxy_cache_bypass \$http_upgrade;
}
}
server {
listen 80;
server_name homer.${URLPortal};
location / {
proxy_pass http://${MONITORING_SERVER_IP}:9080;
proxy_http_version 1.1;
proxy_set_header Upgrade \$http_upgrade;
proxy_set_header Connection 'upgrade';
proxy_set_header Host \$host;
proxy_cache_bypass \$http_upgrade;
}
}
server {
listen 80;
server_name jaeger.${URLPortal};
location / {
proxy_pass http://${MONITORING_SERVER_IP}:16686;
proxy_http_version 1.1;
proxy_set_header Upgrade \$http_upgrade;
proxy_set_header Connection 'upgrade';
proxy_set_header Host \$host;
proxy_cache_bypass \$http_upgrade;
auth_basic "Secured Endpoint";
auth_basic_user_file /etc/nginx/.htpasswd;
}
}
EOF
sudo systemctl restart nginx
echo "enabling cloudwatch"
sudo sed -i -e "s/retention_in_days\": 3/retention_in_days\": ${CloudwatchLogRetention}/g" /opt/aws/amazon-cloudwatch-agent/bin/config.json
sudo /opt/aws/amazon-cloudwatch-agent/bin/amazon-cloudwatch-agent-ctl -a fetch-config -m ec2 -s -c file:/opt/aws/amazon-cloudwatch-agent/bin/config.json
echo "webserver user data script completed"
- VPC_CIDR: !Ref VpcCIDR
JAMBONES_MYSQL_HOST: !GetAtt DatabaseCluster.Endpoint.Address
JAMBONES_MYSQL_USER: !Ref MySQLUsername
JAMBONES_MYSQL_PASSWORD: !Ref MySQLPassword
JAMBONES_REDIS_HOST: !GetAtt ElastiCacheCluster.RedisEndpoint.Address
JAMBONES_CLUSTER_ID: !Ref Prefix
JAMBONES_SAMPLE_RATE: !Ref StatsSampleRate
MONITORING_SERVER_IP: !GetAtt MonitoringServerEC2.PrivateIp
AWS_REGION: !Ref AWS::Region
JAMBONES_TIME_SERIES_HOST: !GetAtt MonitoringServerEC2.PrivateIp
JWT_SECRET: !Ref EncryptionSecret
URLPortal: !Ref URLPortal
JaegerUsername: !Ref JaegerUsername
JaegerPassword: !Ref JaegerPassword
CloudwatchLogRetention: !Ref CloudwatchLogRetention
DbCachingTTS: !Ref DbCachingTTS
WebServerPlacementGroup:
Type: AWS::EC2::PlacementGroup
Properties:
Strategy: spread
WebServerAutoScalingGroup:
Type: AWS::AutoScaling::AutoScalingGroup
Properties:
AutoScalingGroupName: !Sub '${Prefix}-webserver-autoscaling-group'
LaunchConfigurationName: !Ref WebServerConfig
MinSize: 1
MaxSize: 1
DesiredCapacity: 1
TerminationPolicies:
- OldestInstance
VPCZoneIdentifier:
- !Ref PublicSubnet1
- !Ref PublicSubnet2
Tags:
-
Key: Name
Value: !Sub '${Prefix}-webserver'
PropagateAtLaunch: 'true'
-
Key: Environment
Value: !Sub '${Prefix}-webserver'
PropagateAtLaunch: 'true'
Outputs:
WebPortalURL:
Description: jambonz portal URL, log in with admin/admin and change password
Value: !Join [ "", [ "http://", !Ref "URLPortal" ] ]
Export:
Name: !Sub '${Prefix}-webserver-url'
VPC:
Description: "A reference to the created VPC"
Value: !Ref "VPC"
Export:
Name: !Sub "${Prefix}-VPC"
SelfiepopVpcCIDR:
Description: "A reference to the created VPC/CIDR"
Value: !Ref "VpcCIDR"
Export:
Name: !Sub "${Prefix}-SelfiepopVpcCIDR"
PublicSubnets:
Description: "A list of the public subnets"
Value: !Join [ ",", [ !Ref "PublicSubnet1", !Ref "PublicSubnet2" ]]
Export:
Name: !Sub "${Prefix}-PublicSubnets"
PublicSubnet1:
Description: "A reference to the public subnet in the 1st Availability Zone"
Value: !Ref "PublicSubnet1"
Export:
Name: !Sub "${Prefix}-PublicSubnet1"
PublicSubnet2:
Description: "A reference to the public subnet in the 2nd Availability Zone"
Value: !Ref "PublicSubnet2"
Export:
Name: !Sub "${Prefix}-PublicSubnet2"