Files
strapi-elb/tempnotes.md
2020-05-03 00:23:34 +01:00

307 lines
14 KiB
Markdown

<!-- vscode-markdown-toc -->
* [Decoupling](#Decoupling)
* [Creating Database + VPC + Subnets in Cloudformation](#CreatingDatabaseVPCSubnetsinCloudformation)
* [Single instance (no load balancer)](#Singleinstancenoloadbalancer)
* [EC2::VPC](#EC2::VPC)
* [Enable DNS](#EnableDNS)
* [EC2::Subnet](#EC2::Subnet)
* [EC2::InternetGateway](#EC2::InternetGateway)
* [EC2::VPCGatewayAttachment](#EC2::VPCGatewayAttachment)
* [AWS::EC2::RouteTable](#AWS::EC2::RouteTable)
* [AWS::EC2::Route](#AWS::EC2::Route)
* [AWS::EC2::SubnetRouteTableAssociation](#AWS::EC2::SubnetRouteTableAssociation)
* [Running notes](#Runningnotes)
* [Database](#Database)
* [Work Commands](#WorkCommands)
* [tags](#tags)
* [deploy](#deploy)
* [delete](#delete)
* [describe-stack-resources](#describe-stack-resources)
* [Adding SSL to ELB](#AddingSSLtoELB)
* [With load balancer](#Withloadbalancer)
* [EB Templates/Resources](#EBTemplatesResources)
* [Configuring security groups](#Configuringsecuritygroups)
* [Elastic Load Balancer](#ElasticLoadBalancer)
* [Elastic Scaler](#ElasticScaler)
* [RDS](#RDS)
* [Security group to allow EC2 instances to talk to each other](#SecuritygrouptoallowEC2instancestotalktoeachother)
* [Custom VPC + Subnets in EB](#CustomVPCSubnetsinEB)
* [Using cloudformation functions in EB config files](#UsingcloudformationfunctionsinEBconfigfiles)
* [Creating a read replica RDS](#CreatingareadreplicaRDS)
* [Multiple security groups on the same resource](#Multiplesecuritygroupsonthesameresource)
* [Private subnets](#Privatesubnets)
<!-- vscode-markdown-toc-config
numbering=false
autoSave=true
/vscode-markdown-toc-config -->
<!-- /vscode-markdown-toc -->
# Temp Notes
## <a name='Decoupling'></a>Decoupling
When creating an EB instance with `--single` and `--database` the following is created as part of the EB deployment:
- security group
- EIP
- RDS database
Is the security group created without a databse? (probably yes...)
## <a name='CreatingDatabaseVPCSubnetsinCloudformation'></a>Creating Database + VPC + Subnets in Cloudformation
Template from AWS showing cross-stack referencing and creating and referencing a VPC: <https://s3.amazonaws.com/cloudformation-examples/user-guide/cross-stack/SampleNetworkCrossStack.template>.
Export these in the CF template with stackname (<https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/intrinsic-function-reference-importvalue.html>)
A security group is a resource that defines what IPs/Ports are allowed on inbound/outbound for an AWS resource. You can have one for EC2 instance, or RDS among others.
EB will create a VPC for your EC2 instances.
You should use this VPC for you RDS instance.
Creating a VPC for EB (with RDS) <https://docs.aws.amazon.com/elasticbeanstalk/latest/dg/vpc-rds.html>
## <a name='Singleinstancenoloadbalancer'></a>Single instance (no load balancer)
Example cloudformation template that EB uses: <https://raw.githubusercontent.com/awslabs/elastic-beanstalk-samples/master/cfn-templates/vpc-public.yaml>.
Create a VPC - this is an object that spans all availability zones in a region. You assign a VPC a CIDR block. This is a set of IP addresses that this VPC has access to.
You should create public subnets inside this VPC - these subnets should cover all availablility zones in your region. The CIDR block you specified in the VPC defines all the ips, you should create N subnets that equally contain these IP addresses for your region.
For example a VPC in `eu-west-1` has a CIDR block of `172.31.0.0/16`.
There are 3 availablity zones in `eu-west-1`: `eu-west-1a`, `eu-west-1b` and `eu-west-1c`.
To find other availablity zones you should go to the EC2 Dashboard for the region you want to work in, and scroll down to the Service health header. Here, a list of all availability zones will be shown.
You should create subnets with the following:
| Availability Zone | Subnet CIDR | Real IP Range |
| ----------------- | -------------- | --------------------------- |
| `eu-west-1a` | 172.31.0.0/20 | 172.31.0.0 - 172.31.15.255 |
| `eu-west-1b` | 172.31.16.0/20 | 172.31.16.0 - 172.31.31.255 |
| `eu-west-1c` | 172.31.32.0/20 | 172.31.32.0 - 172.31.47.255 |
This covers all IP addresses across all availability zones in the VPC.
To make these subnets actually public, you should associate them with an internet gateway.
An internet gateway is an object that allows communication to the internet. In Cloudformation you should create an internet gateway and a VPC Gateway attachment. This attachment should reference the VPC you have created and reference the internet gateway object you create as well. Then, in your subnets (which are public) you can use `MapPublicIpOnLaunch: true` in the `Properties` block for each subnet.
You should then create a public route table and associate it with the VPC you have created.
You should then create a public route. You can then attach the internet gateway attachment to this route and specify a list of IPs that will go out to the internet. To allow all trafic to the internet set a `DestinationCidrBlock` of `0.0.0.0/0`.
### <a name='EC2::VPC'></a>EC2::VPC
#### <a name='EnableDNS'></a>Enable DNS
Enable `EnableDnsHostnames` + `EnableDnsSupport` - this allows resources in the VPC to use DNS in AWS.
### <a name='EC2::Subnet'></a>EC2::Subnet
Go to the EC2 dashboard to find all availability zones. Create a subnet for each zone.
- `AvailabilityZone`
- `VpcId`
- `CidrBlock`
- `MapPublicIpOnLaunch`
### <a name='EC2::InternetGateway'></a>EC2::InternetGateway
### <a name='EC2::VPCGatewayAttachment'></a>EC2::VPCGatewayAttachment
- `VpcId`
- `InternetGatewayId`
### <a name='AWS::EC2::RouteTable'></a>AWS::EC2::RouteTable
- `VpcId`
### <a name='AWS::EC2::Route'></a>AWS::EC2::Route
- `RouteTableId`
- `DestinationCidrBlock`
- `GatewayId`
### <a name='AWS::EC2::SubnetRouteTableAssociation'></a>AWS::EC2::SubnetRouteTableAssociation
- `SubnetId`
- `RouteTableId`
## <a name='Runningnotes'></a>Running notes
If we specify the VPC + Subnets from Cloudformation in a config file, will it create the security groups automatically for the EC2 instances? - Yes
Database can use existing subnets.
Database needs a security group creating
EC2 security groups automatically created and associated with the VPC.
Use aws:ec2:vpc (https://docs.aws.amazon.com/elasticbeanstalk/latest/dg/command-options-general.html#command-options-general-ec2vpc)
### <a name='Database'></a>Database
Needs:
- `AWS::RDS::DBSubnetGroup`
- `AWS::EC2::SecurityGroupIngress`
- `AWS::RDS::DBInstance`
Default ports:
| Database Engine | Default Port |
| -------------------- | ------------ |
| Aurora/MySQL/MariaDB | 3306 |
| PostgreSQL | 5432 |
| Oracle | 1521 |
| SQL Server | 1433 |
| DynamoDB | 8000 |
## <a name='WorkCommands'></a>Work Commands
### <a name='tags'></a>tags
`--tags git=web-dev owner=home project=strapi-eb test=true deployment=cloudformation`
### <a name='deploy'></a>deploy
`aws --profile admin cloudformation deploy --template-file ./02-stack-vpc.yaml --stack-name strapi-vpc --tags git=web-dev owner=home project=strapi-eb test=true deployment=cloudformation`
`aws --profile admin cloudformation deploy --template-file ./03-stack-rdsinstance.yaml --stack-name strapi-rds --parameter-overrides StackName=strapi-vpc --tags git=web-dev owner=home project=strapi-eb test=true deployment=cloudformation`
### <a name='delete'></a>delete
`aws --profile admin cloudformation delete-stack --stack-name strapi-vpc`
`aws --profile admin cloudformation delete-stack --stack-name strapi-rds`
`aws --profile admin cloudformation delete-stack --stack-name temp`
List of all RDS Engines available under "Engine" header: <https://docs.aws.amazon.com/AmazonRDS/latest/APIReference/API_CreateDBInstance.html>.
### <a name='describe-stack-resources'></a>describe-stack-resources
Will print a json list of all resources in the stack
`aws --profile admin cloudformation describe-stack-resources --stack-name strapi-vpc`
Using `jq` for formatting:
`aws --profile admin cloudformation describe-stack-resources --stack-name strapi-vpc | jq -r '.StackResources[] | .ResourceType + ": " + .PhysicalResourceId'`
## <a name='AddingSSLtoELB'></a>Adding SSL to ELB
You should generate an SSL Certificate in Certificate Manager for your domain. To do this you will need to create a CNAME record to verify you have access to the DNS settings.
At the same time you should create a CNAME record that maps your subdomain (<strapi.panaetius.co.uk>) to the DNS name AWS has given your load balancer (<awseb-AWSEB-68CXGV0UTROU-1492520139.eu-west-1.elb.amazonaws.com>).
### <a name='Withloadbalancer'></a>With load balancer
A load balancer is not free! It costs ~£15 a month.
- Configure the load balancer listener in a EB `.config` file:
```yaml
option_settings:
aws:elbv2:listener:443:
Protocol: HTTPS
SSLCertificateArns: arn:aws:acm:eu-west-1:745437999005:certificate/218876af-7f8d-4022-97af-ad982aa540bc
```
## <a name='EBTemplatesResources'></a>EB Templates/Resources
Good repo for examples: <https://github.com/awsdocs/elastic-beanstalk-samples>
Creating a VPC for RDS in EB: <https://docs.aws.amazon.com/elasticbeanstalk/latest/dg/vpc-rds.html>
CF RDS EB template: <https://github.com/garystafford/aws-rds-postgres/blob/master/cfn-templates/rds.template>
Decouple an exisitng RDS instance from ELB to RDS: <https://aws.amazon.com/premiumsupport/knowledge-center/decouple-rds-from-beanstalk/>
## <a name='Configuringsecuritygroups'></a>Configuring security groups
## <a name='ElasticLoadBalancer'></a>Elastic Load Balancer
Should set: inbound/outbound 80/443 on 0.0.0.0/0
The option_settings: aws:elbv2:loadbalancer has two options for security groups.
| Option | Description |
| -------------------- | --------------------------------------------------------------------- |
| ManagedSecurityGroup | Defines the security group that is used for the load balancer itself. |
| SecurityGroups | Is a list of additional security groups you want to attach. |
If you define a ManagedSecurityGroup you should set SecurityGroups as well to the same one.
Load balancer needs a security group that allows incoming 80 + 443 from anywhere
It should also set the same for outbound as well
This security group should be set in `aws:elbv2:loadbalancer` under
`ManagedSecurityGroup` and `SecurityGroups`
### <a name='ElasticScaler'></a>Elastic Scaler
Should set inbound 80/443 from LBSG.
EB will create a security group for the EC2 instances. In addition to this, you can create a new security group that will be applied to EC2 instances the elastic scaler creates.
This is set under `aws:autoscaling:launchconfiguration`.
### <a name='RDS'></a>RDS
Should set: inbound 5432 from Scaling SG + home ip (change port and home ip).
The database should have a security group creating that allows incoming connections from the EC2 instances only.
### <a name='SecuritygrouptoallowEC2instancestotalktoeachother'></a>Security group to allow EC2 instances to talk to each other
Security group rule to allow instances in the same security group to talk to one another: <https://docs.aws.amazon.com/AWSEC2/latest/UserGuide/security-group-rules-reference.html#sg-rules-other-instances>.
## <a name='CustomVPCSubnetsinEB'></a>Custom VPC + Subnets in EB
In a `.config` file specify the subnets for each tier of your app:
```yaml
option_settings:
aws:ec2:vpc:
VPCId: "vpc-003597eb63a0a3efe"
Subnets: "subnet-02cd8f7981ddfe345,subnet-02d9e1338e8d92d09,subnet-0e07d4d35394db524"
DBSubnets: "subnet-02cd8f7981ddfe345,subnet-02d9e1338e8d92d09,subnet-0e07d4d35394db524"
```
## <a name='UsingcloudformationfunctionsinEBconfigfiles'></a>Using cloudformation functions in EB config files
Only certain CF functions can be used in EB config files. For anything more advanced you should use Terraform to deploy additional resources alongside an EB template.
Reddit discussion on the topic: <https://www.reddit.com/r/aws/comments/a2uoae/is_there_a_way_to_reference_an_elastic_beanstalk/>.
EB documentaion on what functions are supported: <https://docs.aws.amazon.com/elasticbeanstalk/latest/dg/ebextensions-functions.html#ebextensions-functions-getatt>.
You cannot use `FN::ImportValue` to reference a resource in another Cloudformation stack.
You can use join for resources that EB creates itself: `!Join [ ":", [ !Ref "AWS::StackName", AccountVPC ] ]`.
## <a name='CreatingareadreplicaRDS'></a>Creating a read replica RDS
To have a replica database you should create a new DB instance with same AllocatedStorage size and DBInstanceClass. You should set the SourceDBInstanceIdentifier to be a `!Ref` of your primary DB. You should also set the SourceRegion.
Read replica CF docs: <https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-rds-database-instance.html#cfn-rds-dbinstance-sourcedbinstanceidentifier>
## <a name='Multiplesecuritygroupsonthesameresource'></a>Multiple security groups on the same resource
Multiple security groups get squashed to determine what is and isn't allowed: <https://docs.aws.amazon.com/AWSEC2/latest/UserGuide/ec2-security-groups.html>.
## <a name='Privatesubnets'></a>Private subnets
You can create private subnets that do not have an internet gateway attached to them. An example of CF template is <https://github.com/awsdocs/elastic-beanstalk-samples/blob/master/cfn-templates/vpc-privatepublic.yaml>.
You need a nat gateway to allow private subnets to go out to the internet.
If you use private subnets, the nat gateway is not cheap - £30 a month.
You dont need the nat gateway, you can achieve the same thing with security groups (block all incoming) (explained <https://www.reddit.com/r/aws/comments/75bjei/private_subnets_nats_vs_simply_only_allowing/>).
An advantage to NAT is all outgoing requests to the internet come from a single IP.