Files
jambonz-infrastructure/cloudformation/jambonz-mini.yaml
2023-11-15 09:46:40 -05:00

476 lines
17 KiB
YAML

AWSTemplateFormatVersion: 2010-09-09
Parameters:
InstanceType:
Description: jambonzMini EC2 instance type
Type: String
Default: t2.medium
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
ConstraintDescription: must be a valid EC2 instance type.
KeyName:
Description: Name of an EC2 KeyPair to enable SSH access to the instance.
Type: 'AWS::EC2::KeyPair::KeyName'
ConstraintDescription: must be the name of an existing EC2 KeyPair.
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
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}
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}
VpcCidr:
Description: CIDR range for the VPC.
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: 10.0.0.0/16
Cloudwatch:
Description: Send jambonz logs to cloudwatch
Type: String
Default: true
AllowedValues: [true, false]
CloudwatchLogRetention:
Description: "Number of days to retain cloudwatch logs"
Type: Number
Default: 3
AllowedValues:
- 1
- 3
- 5
- 7
- 14
- 30
- 60
- 90
- 120
- 150
URLPortal:
Type: String
Description: "(Optional) A DNS name for the server (note: you must add a DNS A record in your DNS provider)"
Default: ""
Conditions:
ShouldEnableCloudWatch: !Equals
- true
- !Ref Cloudwatch
DontCreateDNS: !Equals
- !Ref URLPortal
- ""
CreateDNS: !Not
- !Equals
- !Ref URLPortal
- ""
Mappings:
AWSRegion2AMI:
us-east-1:
Ami: ami-0525a66f4301a6e6d
us-east-2:
Ami: ami-0e45caebe3e25580c
Resources:
IamCloudwatchRole:
Type: AWS::IAM::Role
Condition: ShouldEnableCloudWatch
Properties:
Description: jambonz mini IAM 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-*'
VPC:
Type: 'AWS::EC2::VPC'
Properties:
EnableDnsSupport: true
EnableDnsHostnames: true
CidrBlock: !Ref VpcCidr
PublicSubnet:
Type: 'AWS::EC2::Subnet'
Properties:
VpcId: !Ref VPC
CidrBlock: !Ref VpcCidr
jambonzInstanceProfile:
Type: 'AWS::IAM::InstanceProfile'
Condition: ShouldEnableCloudWatch
Properties:
Path: /
Roles:
- !Ref IamCloudwatchRole
jambonzInstance:
Type: 'AWS::EC2::Instance'
Properties:
InstanceType: !Ref InstanceType
IamInstanceProfile:
!If [ShouldEnableCloudWatch, !Ref jambonzInstanceProfile, !Ref "AWS::NoValue"]
ImageId: !FindInMap [ "AWSRegion2AMI", !Ref AWS::Region, "Ami"]
KeyName: !Ref KeyName
NetworkInterfaces:
- GroupSet:
- !Ref jambonzSecurityGroup
- !Ref sshSecurityGroup
AssociatePublicIpAddress: true
DeviceIndex: '0'
DeleteOnTermination: true
SubnetId: !Ref PublicSubnet
UserData:
Fn::Base64:
Fn::Sub:
- |
#!/bin/bash -xe
# Detecting the Linux distribution
if grep -q 'ID="rhel"' /etc/os-release; then
USER=ec2-user
HOME=/home/ec2-user
NGINX_CONFIG=/etc/nginx/conf.d/default.conf
echo restarting mysql and postgresql
systemctl restart mysqld
systemctl restart postgresql-12
echo disabling firewalld
sudo systemctl stop firewalld
sudo systemctl disable firewalld
sudo systemctl restart rtpengine
else
USER=admin
HOME=/home/admin
NGINX_CONFIG=/etc/nginx/sites-available/default
fi
# get instance metadata
PRIVATE_IPV4="$(curl -s http://169.254.169.254/latest/meta-data/local-ipv4)"
PUBLIC_IPV4="$(curl -s http://169.254.169.254/latest/meta-data/public-ipv4)"
INSTANCE_ID="$(curl -s http://169.254.169.254/latest/meta-data/instance-id)"
AWS_REGION_NAME="$(curl -s http://169.254.169.254/latest/meta-data/placement/region)"
# change the database password to a random id
#NEW_DB_PASSWD="$(cat /dev/urandom | tr -dc 'a-zA-Z0-9' | fold -w 32 | head -n 1)"
NEW_DB_PASSWD=$(< /dev/urandom tr -dc A-Z | head -c1; < /dev/urandom tr -dc a-z | head -c1; < /dev/urandom tr -dc 0-9 | head -c1; < /dev/urandom tr -dc _ | head -c1; < /dev/urandom tr -dc _A-Z-a-z-0-9 | head -c8; echo;)
echo "alter user 'admin'@'%' identified by '$NEW_DB_PASSWD'" | mysql -h 127.0.0.1 -u admin -D jambones -pJambonzR0ck$
sudo sed -i -e "s/\(.*\)JAMBONES_MYSQL_PASSWORD.*/\1JAMBONES_MYSQL_PASSWORD: '$NEW_DB_PASSWD',/g" $HOME/apps/ecosystem.config.js
# replace ip addresses in the ecosystem.config.js file
sudo sed -i -e "s/\(.*\)PRIVATE_IP\(.*\)/\1$PRIVATE_IPV4\2/g" $HOME/apps/ecosystem.config.js
sudo sed -i -e "s/\(.*\)AWS_REGION_NAME\(.*\)/\1$AWS_REGION_NAME\2/g" $HOME/apps/ecosystem.config.js
sudo sed -i -e "s/\(.*\)--JAMBONES_API_BASE_URL--\(.*\)/\1http:\/\/$PUBLIC_IPV4\/v1\2/g" $HOME/apps/ecosystem.config.js
# replace JWT_SECRET
uuid=$(uuidgen)
sudo sed -i -e "s/\(.*\)JWT-SECRET-GOES_HERE\(.*\)/\1$uuid\2/g" $HOME/apps/ecosystem.config.js
# reset the database
JAMBONES_ADMIN_INITIAL_PASSWORD=$INSTANCE_ID JAMBONES_MYSQL_USER=admin JAMBONES_MYSQL_PASSWORD=$NEW_DB_PASSWD JAMBONES_MYSQL_DATABASE=jambones JAMBONES_MYSQL_HOST=127.0.0.1 $HOME/apps/jambonz-api-server/db/reset_admin_password.js
# configure webapp
if [[ -z "${URLPortal}" ]]; then
# portals will be accessed by IP address of server
echo "VITE_API_BASE_URL=http://$PUBLIC_IPV4/api/v1" > $HOME/apps/jambonz-webapp/.env
API_BASE_URL=http://$PUBLIC_IPV4/api/v1 TAG="<script>window.JAMBONZ = { API_BASE_URL: '$API_BASE_URL'};</script>"
sed -i -e "\@</head>@i\ $TAG" $HOME/apps/jambonz-webapp/dist/index.html
else
# portals will be accessed by DNS name
echo "VITE_API_BASE_URL=http://${URLPortal}/api/v1" > $HOME/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/apps/jambonz-webapp/dist/index.html
# add row to system information table
mysql -h 127.0.0.1 -u admin -D jambones -p$NEW_DB_PASSWD -e $'insert into system_information (domain_name, sip_domain_name, monitoring_domain_name) values ('\'''"${URLPortal}"''\'', '\''sip.'"${URLPortal}"''\'', '\''grafana.'"${URLPortal}"''\'')'
sudo cat << EOF > $NGINX_CONFIG
server {
listen 80;
server_name ${URLPortal};
location /api/ {
rewrite ^/api/(.*)$ /\$1 break;
proxy_pass http://127.0.0.1:3002;
proxy_set_header Host \$host;
}
location / {
proxy_pass http://127.0.0.1:3001;
proxy_set_header Host \$host;
}
}
server {
listen 80;
server_name api.${URLPortal};
location / {
proxy_pass http://127.0.0.1:3002;
proxy_set_header Host \$host;
}
}
server {
listen 80;
server_name grafana.${URLPortal};
location / {
proxy_pass http://127.0.0.1:3010;
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://127.0.0.1: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;
}
}
EOF
sudo systemctl restart nginx
fi
# restart heplify-server
sudo systemctl restart heplify-server
# enable cloudwatch
if [[ "${Cloudwatch}" == "true" ]]; then
echo "Enabling Cloudwatch for jambonz logs"
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
else
echo "Cloudwatch is not enabled for jambonz logs"
sudo sed -i -e "s/combine_logs: true/combine_logs: false/g" $HOME/apps/ecosystem.config.js
fi
sudo -u $USER bash -c "pm2 restart $HOME/apps/ecosystem.config.js"
sudo -u $USER bash -c "pm2 save"
sudo env PATH=$PATH:/usr/bin /usr/lib/node_modules/pm2/bin/pm2 startup systemd -u $USER --hp $HOME
sudo systemctl restart cassandra.service
echo "waiting 60 secs for cassandra to start.."
sleep 60
echo "now start jaeger"
# restart jaeger
sudo systemctl restart jaeger-collector.service
sudo systemctl restart jaeger-query.service
# get an apiban key and install it
APIBANKEY=$(curl -X POST -u jambonz:1a074994242182a9e0b67eae93978826 -d "{\"client\": \"$INSTANCE_ID\"}" -s https://apiban.org/sponsor/newkey | jq -r '.ApiKey')
sudo sed -i -e "s/API-KEY-HERE/$APIBANKEY/g" /usr/local/bin/apiban/config.json
sudo /usr/local/bin/apiban/apiban-iptables-client FULL
- URLPortal: !Ref URLPortal
Cloudwatch: !Ref Cloudwatch
CloudwatchLogRetention: !Ref CloudwatchLogRetention
jambonzSecurityGroup:
Type: 'AWS::EC2::SecurityGroup'
Properties:
VpcId: !Ref VPC
GroupDescription: 'Allow sip, rtp, http and ssh access'
SecurityGroupIngress:
- Description: sip over udp
IpProtocol: udp
FromPort: 5060
ToPort: 5060
CidrIp: !Ref AllowedSipCidr
- Description: sip over tcp
IpProtocol: tcp
FromPort: 5060
ToPort: 5060
CidrIp: !Ref AllowedSipCidr
- Description: sip over tls
IpProtocol: tcp
FromPort: 5061
ToPort: 5061
CidrIp: !Ref AllowedSipCidr
- Description: sip over wss
IpProtocol: tcp
FromPort: 8443
ToPort: 8443
CidrIp: !Ref AllowedSipCidr
- Description: rtp
IpProtocol: udp
FromPort: 40000
ToPort: 60000
CidrIp: !Ref AllowedRtpCidr
- Description: http
IpProtocol: tcp
FromPort: 80
ToPort: 80
CidrIp: !Ref AllowedHttpCidr
- Description: https
IpProtocol: tcp
FromPort: 443
ToPort: 443
CidrIp: !Ref AllowedHttpCidr
- Description: homer
IpProtocol: tcp
FromPort: 9080
ToPort: 9080
CidrIp: !Ref AllowedHttpCidr
- Description: grafana
IpProtocol: tcp
FromPort: 3000
ToPort: 3000
CidrIp: !Ref AllowedHttpCidr
- Description: smpp
IpProtocol: tcp
FromPort: 3020
ToPort: 3020
CidrIp: !Ref VpcCidr
SecurityGroupEgress:
- IpProtocol: -1
FromPort: 0
ToPort: 0
CidrIp: 0.0.0.0/0
DependsOn:
- PublicRoute
sshSecurityGroup:
Type: 'AWS::EC2::SecurityGroup'
Properties:
VpcId: !Ref VPC
GroupDescription: 'Allow sip, rtp, http and ssh access'
SecurityGroupIngress:
- Description: ssh
IpProtocol: tcp
FromPort: 22
ToPort: 22
CidrIp: !Ref AllowedSshCidr
SecurityGroupEgress:
- IpProtocol: -1
FromPort: 0
ToPort: 0
CidrIp: 0.0.0.0/0
DependsOn:
- PublicRoute
InternetGateway:
Type: 'AWS::EC2::InternetGateway'
Properties: {}
PublicRouteTable:
Type: 'AWS::EC2::RouteTable'
Properties:
VpcId: !Ref VPC
PublicRoute:
Type: 'AWS::EC2::Route'
Properties:
DestinationCidrBlock: 0.0.0.0/0
RouteTableId: !Ref PublicRouteTable
GatewayId: !Ref InternetGateway
DependsOn:
- VPCGatewayAttachment
VPCGatewayAttachment:
Type: 'AWS::EC2::VPCGatewayAttachment'
Properties:
InternetGatewayId: !Ref InternetGateway
VpcId: !Ref VPC
PublicSubnetRouteTableAssociation:
Type: 'AWS::EC2::SubnetRouteTableAssociation'
Properties:
RouteTableId: !Ref PublicRouteTable
SubnetId: !Ref PublicSubnet
EIP:
Type: 'AWS::EC2::EIP'
Properties:
Domain: vpc
EIPAssociation:
Type: 'AWS::EC2::EIPAssociation'
Properties:
InstanceId: !Ref jambonzInstance
AllocationId: !GetAtt EIP.AllocationId
Outputs:
PortalHttpURL:
Value: !Join
- ''
- - 'http://'
- !GetAtt
- jambonzInstance
- PublicIp
Description: URL for the jambonz portal
Condition: DontCreateDNS
PortalURL:
Value: !Join
- ''
- - 'http://'
- !Ref URLPortal
Description: URL for the jambonz portal
Condition: CreateDNS
GrafanaURL:
Value: !Join
- ''
- - 'http://grafana.'
- !Ref URLPortal
Description: URL for the grafana portal
Condition: CreateDNS
HomerURL:
Value: !Join
- ''
- - 'http://homer.'
- !Ref URLPortal
Description: URL for the homer portal
Condition: CreateDNS
ServerIP:
Value: !GetAtt
- jambonzInstance
- PublicIp
Description: Server IP address - create a DNS record for this domain as well as subdomains grafana, homer, and jaeger
User:
Value: admin
Description: Login username for the jambonz portal
Password:
Value: !Ref jambonzInstance
Description: Initial password for jambonz portal. You will be forced to change it once you log in for the first time.