{"id":18612443,"url":"https://github.com/alejandro945/aws-tree-tier-app","last_synced_at":"2026-04-16T08:37:43.493Z","repository":{"id":170162092,"uuid":"646221875","full_name":"alejandro945/aws-tree-tier-app","owner":"alejandro945","description":"A 3-Tier architecture provides a general framework for deploying traditional client/server applications into three logical tiers; the Web, Application, and Database tier.","archived":false,"fork":false,"pushed_at":"2023-05-28T22:31:59.000Z","size":1753,"stargazers_count":0,"open_issues_count":0,"forks_count":0,"subscribers_count":1,"default_branch":"main","last_synced_at":"2025-05-16T23:35:46.164Z","etag":null,"topics":["aws","ci-cd","cloudformation","codebuild","github-actions","lambda"],"latest_commit_sha":null,"homepage":"","language":"Shell","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":null,"status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/alejandro945.png","metadata":{"files":{"readme":"README.MD","changelog":null,"contributing":null,"funding":null,"license":null,"code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null}},"created_at":"2023-05-27T17:17:29.000Z","updated_at":"2023-05-28T04:29:22.000Z","dependencies_parsed_at":null,"dependency_job_id":"830b8664-db63-4ef3-b9cf-9a566df13d9d","html_url":"https://github.com/alejandro945/aws-tree-tier-app","commit_stats":null,"previous_names":["alejandro945/aws-tree-tier-app"],"tags_count":0,"template":false,"template_full_name":null,"purl":"pkg:github/alejandro945/aws-tree-tier-app","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/alejandro945%2Faws-tree-tier-app","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/alejandro945%2Faws-tree-tier-app/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/alejandro945%2Faws-tree-tier-app/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/alejandro945%2Faws-tree-tier-app/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/alejandro945","download_url":"https://codeload.github.com/alejandro945/aws-tree-tier-app/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/alejandro945%2Faws-tree-tier-app/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":31878413,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-04-16T07:36:03.521Z","status":"ssl_error","status_checked_at":"2026-04-16T07:35:53.576Z","response_time":69,"last_error":"SSL_connect returned=1 errno=0 peeraddr=140.82.121.5:443 state=error: unexpected eof while reading","robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":false,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["aws","ci-cd","cloudformation","codebuild","github-actions","lambda"],"created_at":"2024-11-07T03:17:14.170Z","updated_at":"2026-04-16T08:37:43.472Z","avatar_url":"https://github.com/alejandro945.png","language":"Shell","funding_links":[],"categories":[],"sub_categories":[],"readme":"# Challenge: CloudFormation, Serverless, CodeBuild and CI/CD 💥\n## Infrastructure provisioning\n\nA 3-Tier architecture provides a general framework for deploying traditional client/server applications into three logical tiers; the Web, Application, and Database tier. End users interact with the Web tier which provides them with a user interface they can use to view, modify, or submit information. The Application tier is responsible for handling the requests made by the user. The Application or Middle tier is the brains behind the operation. It assists in translating users actions into business logic that allow for data processing by programs. Lastly, the Database or Data tier is where the information processed by the application is stored and managed.\n\n### Design\n\n![Design](./assets/design.png)\n\nIn case you wonder why we will use availability zones?\n\n1. High Availability\n2. Disaster Recovery\n3. Data Sovereignty\n4. Scalability\n5. Fault Tolerance\n\n### Web Tier [Frontend]\n\nIn this layer, we will create a public load balancer and an auto-scaling group. The load balancer will be used to distribute traffic across the instances.\n\n**Resources:**\n\n- 2 public subnets\n- Public route table\n- Internet Gateway \u0026 NAT Gateway\n- Internet facing Application Load Balancer with a Security Group allowing inbound permission from the Internet.\n- Minimum of 2 EC2 instances in an Auto Scaling Group.\n- EC2 Security Group allowing inbound permission from the the Web Tier Application Load Balancer\n- Create a public route table and associate the 2 public subnets.\n\n### Application Tier [Backend]\n\nIn this layer, we will create an internal load balancer and an auto-scaling group. The load balancer will be used to distribute traffic across the application servers. The auto-scaling group will be used to scale the number of application servers up or down based on the demand.\n\n**Resources:**\n\n- 2 private subnets\n- Private route table\n- Internal Application Load Balancer with a Security Group allowing inbound permission from EC2 instances in the Web Tier.\n- Minimum of 2 EC2 instances in an Auto Scaling Group\n- EC2 Security Group allowing inbound permission from the Application Tier Application Load Balancer\n- Image host on docker hub \n- Associate with private route table\n\n### Database Tier [Data]\n\nIn this layer, we will create a Multi AZ RDS MySQL database. The database will be used to store the data for the application.\n\n**Resources:**\n\n- 2 private subnets\n- Public route table\n- MySql RDS Database with Multi AZ standby instance\n- The Database Security Group allowing inbound traffic for MySQL from the Application Server Security Group\n\n### Admin Tier [Ops]\n\nIn this layer, we will create a bastion host. The bastion host will be used to access compute services in private networks for administration purposes.\n\n**Resources:**\n\n- 2 private subnets\n- Public route table\n- MySql RDS Database with Multi AZ standby instance\n- The Database Security Group allowing inbound traffic for MySQL from the Application Server Security Group\n\n### Prerequisites\n\n- AWS Account\n- AWS CLI, for installation in linux operative system follow the next steps:\n\n    ```sh\n    curl \"https://awscli.amazonaws.com/awscli-exe-linux-x86_64.zip\" -o \"awscliv2.zip\"\n    unzip awscliv2.zip\n    sudo ./aws/install\n    ```\n\n- Configuring AWS CLI you need **access key and secret key**, you can create it in IAM service.\n\n    ```sh\n    aws configure\n    ```\n\n### Steps\n\n1. Creat an EC2 Key Pair used to SSH into the bastion host\n\n```bash\naws ec2 create-key-pair --key-name aws-tree-tier-app-varela --query 'KeyMaterial' --output text \u003e aws-tree-tier-app-varela.pem\n```\n\n2. Infrastructure as Code with CloudFormation\n\n- Parameters: Are a way to provide input values to a CloudFormation stack at the time of stack creation or update. Parameters allow you to customize the behavior and configuration of your stack templates without modifying the template itself.\n\n    1. KeyPair: The name of an existing EC2 KeyPair to enable SSH access to the instances\n    2. DatabaseUser\n    3. DatabasePassword\n\n- Mappings: Are a way to provide conditional parameters to your CloudFormation template based on region or environment. Mappings are a great way to keep your CloudFormation templates DRY.\n\n- Conditions: Are a way to control whether certain resources are created or whether certain resource properties are assigned a value during stack creation or update. Conditions are declared in the Conditions section of a CloudFormation template.\n\n- Resources: Are the core of your CloudFormation template. Resources are the AWS components that you want to deploy as part of your infrastructure such as EC2 instances, RDS databases, VPCs, and more. In our we will create the following resources.\n\n    1. VPC\n    2. Internet Gateway\n    3. NAT Gateway\n    4. Public Subnets [3]\n    5. Private Subnets [4]\n    6. Public Route Table\n    7. Private Route Table\n    8. Web Tier Security Group\n    9. Application Tier Security Group\n    10. Database Tier Security Group\n    11. Bastion Host Security Group\n    12. Web Tier Application Load Balancer\n    13. Application Tier Application Load Balancer\n    14. Web Tier Auto Scaling Group\n    15. Application Tier Auto Scaling Group\n    16. Database Tier RDS MySQL\n\n- Outputs: Are a way to return information about your AWS infrastructure stack after it has been created or updated. Outputs are declared in the Outputs section of a CloudFormation template.\n\n- Transform: Is a macro that processes your template in two phases. In the first phase, the macro processes all intrinsic functions except for Fn::Transform. In the second phase, the macro recursively expands macros. The following example shows a template that uses the AWS::Include transform to include a snippet of YAML-formatted template code from an Amazon S3 bucket.\n\n- Metadata: Is a section in a CloudFormation template that contains additional information for AWS CloudFormation to process but that is not strictly part of the template's AWS resources. Metadata is optional.\n\n3. Create a CloudFormation Stack\n\n```bash\naws cloudformation create-stack --stack-name aws-tree-tier-app-varela --template-body file://./iac/main.yml --parameters file://./iac/parameters.json\n```\n\n4. Check the status of the stack\n\n```bash\naws cloudformation describe-stacks --stack-name aws-tree-tier-app-varela --query 'Stacks[0].StackStatus'\n```\n\n5. Check the outputs of the stack\n\n    - Bastion Host Public IP\n    - Web Tier Application Load Balancer URL\n    - Application Tier Application Load Balancer URL\n    - Endpoint URL address for our RDS MySQL Database\n    - RDS MySQL Database TCP Port used\n\n    ```bash\n    aws cloudformation describe-stacks --stack-name aws-tree-tier-app-varela --query 'Stacks[0].Outputs'\n    ``` \n\n6. Delete the stack\n\n```bash\naws cloudformation delete-stack --stack-name aws-tree-tier-app-varela\n```\n\nRemarks in the process of the infrastructure as code creation we have the following error:\n\n- Resource handler returned message: \"Cannot find version 8.0.30 for mysql\n\nThis error is because the version of the mysql database is not available in the region where the stack is being created, to solve this problem we must see the engine versions available in the region where we are going to create the stack.\n\n```bash\naws rds describe-db-engine-versions --engine mysql --query \"*[].{Engine:Engine,EngineVersion:EngineVersion}\" --output text\n```\n\n# Configuration Management\n\nBefore we SSH into our Bastion Host let’s use SCP to copy our key pair file and config script to the Bastion Host. We can obtain the public IP address of the Bastion Host from the Outputs section of our stack deployment from earlier.\n\n```bash\nscp -i ./iac/aws-tree-tier-app-varela.pem -o StrictHostKeyChecking=no ./iac/aws-tree-tier-app-varela.pem ec2-user@\u003cBastion Host Public IP\u003e:/home/ec2-user\nscp -i ./iac/aws-tree-tier-app-varela.pem -o StrictHostKeyChecking=no ./configuration/config.sh ec2-user@\u003cBastion Host Public IP\u003e:/home/ec2-user\n```\n\nBefore execute the following command we need to change database host and server host in the config.sh file.\n\nNow let’s Run our configuration script.\n\n```bash\nssh -i ./iac/aws-tree-tier-app-varela.pem -o StrictHostKeyChecking=no ec2-user@\u003cBastion Host Public IP\u003e 'chmod 777 config.sh \u0026\u0026 chmod 400 aws-tree-tier-app-varela.pem \u0026\u0026 ./config.sh'\n```\n\nCheck the status of the **web tier**.\n\n```bash\ncurl external-alb-name\n```\n\n![Frontend](./assets/frontend.png)\n\nCheck the status of the **application tier server**.\n\n```bash\nssh -i ./iac/aws-tree-tier-app-varela.pem -o StrictHostKeyChecking=no ec2-user@\u003cBastion Host Public IP\u003e\nssh -i aws-tree-tier-app-varela.pem -o StrictHostKeyChecking=no ec2-user@\u003cWeb Tier Private IP\u003e\ncurl internal-alb-name\n```\n\n![Backend](./assets/backend.png)\n\nFrom app tier server we can check the status of the database server.\n\n![Container](./assets/backend-container.png)\n\n```bash\n mysql --host=demo-database.cbmn4afmh1uc.us-east-1.rds.amazonaws.com --user=admin --password=admin123\n CREATE DATABASE test;\n \\q\n```\n\n# Lambda AWS\n\n## What is Lambda?\n\nIs a serverless computing service provided by AWS, it runs your code in response to events and automatically manages the underlying compute resources for you. You can use AWS Lambda to extend other AWS services with custom logic, or create your own back-end services that operate at AWS scale, performance, and security.\n\n**Requirements:**\n\n- Create an IAM role for the AWS Lambda function and assign the necessary permissions to perform the task.\n\n    IAM Role creation:\n\n    ```bash\n    aws iam create-role --role-name LambdaRole --assume-role-policy-document file://./serverless/trust-policy.json\n    {\n        \"Role\": {\n            \"Path\": \"/\",\n            \"RoleName\": \"LambdaRole\",\n            \"RoleId\": \"AROASMH5QOAHG56GJEXL4\",\n            \"Arn\": \"arn:aws:iam::163740413966:role/LambdaRole\",\n            \"CreateDate\": \"2023-05-28T03:27:27+00:00\",\n            \"AssumeRolePolicyDocument\": {\n                \"Version\": \"2012-10-17\",\n                \"Statement\": [\n                    {\n                        \"Effect\": \"Allow\",\n                        \"Principal\": {\n                            \"Service\": \"lambda.amazonaws.com\"\n                        },\n                        \"Action\": \"sts:AssumeRole\"\n                    }\n                ]\n            }\n        }\n    }\n    ```\n\n    Attach Policy to Role:\n\n    ```bash\n    aws iam attach-role-policy --role-name LambdaRole --policy-arn arn:aws:iam::aws:policy/AmazonS3FullAccess\n    ```\n\n    Create source-bucket and upload a local image file\n\n    ```bash\n    aws s3api create-bucket --bucket source-bucket-444 --region us-east-1\n    aws s3 cp ./assets/design.png s3://source-bucket-444/src/design.png\n    ```\n\n- Use the AWS CLI to create an AWS Lambda function that performs a simple task, such as copying a file from one Amazon S3 bucket to another bucket.\n\n    ```bash\n    aws lambda create-function --function-name MyLambdaFunction \\\n    --zip-file fileb://./serverless/basic.zip --handler s3-basic-operations.lambda_handler --runtime python3.8 \\\n    --role arn:aws:iam::163740413966:role/LambdaRole\n    ```\n\n    Invoke the AWS Lambda function to verify that it works correctly.\n\n    ```bash\n    aws lambda invoke --function-name MyLambdaFunction out --log-type Tail \\\n    --query 'LogResult' --output text |  base64 -d\n    ```\n\n    ![Buckets](./assets/buckets.png)\n\n    ![Lambda](./assets/lambda.png)\n\n    Clean up the AWS Lambda function and the IAM role.\n\n    ```bash\n    aws lambda delete-function --function-name MyLambdaFunction\n    aws iam detach-role-policy --role-name LambdaRole --policy-arn arn:aws:iam::aws:policy/AmazonS3FullAccess\n    aws iam delete-role --role-name LambdaRole\n    aws s3 rm s3://source-bucket-444/src --recursive\n    aws s3api delete-bucket --bucket source-bucket-444\n    aws s3 rm s3://destination-bucket-444/dest --recursive\n    aws s3api delete-bucket --bucket destination-bucket-444\n    ```\n\n# CodeBuild AWS\n\n**Requirements:**\n\nUse CodeBuild to build the CloudFormation deployment artifact from the CloudFormation template.\n\nA stack template file defines the resources that AWS CloudFormation provisions and configures. These files are the same template files that you use when you create or update stacks using AWS CloudFormation.\n\n1. Upload the CloudFormation template to the S3 bucket and the buildspec.yml\n\n    ```bash\n    aws s3 cp ./iac/main.yml s3://source-bucket-444/src/main.yml\n    aws s3 cp ./build/buildspec.yml s3://source-bucket-444/src/buildspec.yml\n    ```\n\n2. Create IAM role for CodeBuild\n\n    ```bash\n    aws iam create-role --role-name CodeBuildRole --assume-role-policy-document file://./build/trust-policy.json\n    aws iam attach-role-policy --role-name CodeBuildRole --policy-arn arn:aws:iam::aws:policy/AdministratorAccess\n    ```\n\n3. Create CodeBuild project\n\n    ```bash\n    aws codebuild create-project --cli-input-json file://./build/codebuild-project.json\n    ```\n\n4. Run the build\n    \n    ```bash\n    aws codebuild start-build --project-name codebuild-demo-varela\n    aws codebuild batch-get-builds --ids codebuild-demo-varela:4dba753c-d699-4b15-9e5b-b033a82fe83c\n    ```\n\n5. Check the result\n\n    ![CodeBuild](./assets/codebuild.png)\n\n    ```bash\n    {\n            \"id\": \"codebuild-demo-varela:4dba753c-d699-4b15-9e5b-b033a82fe83c\",\n            \"arn\": \"arn:aws:codebuild:us-east-1:163740413966:build/codebuild-demo-varela:4dba753c-d699-4b15-9e5b-b033a82fe83c\",\n            \"buildNumber\": 1,\n            \"startTime\": \"2023-05-28T05:53:16.050000+00:00\",\n            \"currentPhase\": \"PROVISIONING\",\n            \"buildStatus\": \"IN_PROGRESS\",\n            \"projectName\": \"codebuild-demo-varela\",\n            \"phases\": [\n                {\n                    \"phaseType\": \"SUBMITTED\",\n                    \"phaseStatus\": \"SUCCEEDED\",\n                    \"startTime\": \"2023-05-28T05:53:16.050000+00:00\",\n                    \"endTime\": \"2023-05-28T05:53:16.137000+00:00\",\n                    \"durationInSeconds\": 0\n                },\n                {\n                    \"phaseType\": \"QUEUED\",\n                    \"phaseStatus\": \"SUCCEEDED\",\n                    \"startTime\": \"2023-05-28T05:53:16.137000+00:00\",\n                    \"endTime\": \"2023-05-28T05:53:19.501000+00:00\",\n                    \"durationInSeconds\": 3\n                }\n    }\n    ```\n\n6. Clean up\n\n    ```bash\n    aws codebuild delete-project --name codebuild-demo-varela\n    aws iam detach-role-policy --role-name CodeBuildRole --policy-arn arn:aws:iam::aws:policy/AdministratorAccess\n    aws iam delete-role --role-name CodeBuildRole\n    aws s3 rm s3://source-bucket-444/src --recursive\n    aws s3api delete-bucket --bucket source-bucket-444\n    ```\n\n# CI/CD AWS\n\n**Requirements:**\nCreate a gtihub workflow with two jobs, one to set up the environment and simulate running automated unit tests, and another that only runs if tests pass to deploy to an EC2 instance, over SSH using a file deploy.sh\n\nCopy deploy.sh to the bastion host\n\n```bash\nscp -i ./iac/aws-tree-tier-app-varela.pem -o StrictHostKeyChecking=no ./deploy.sh ec2-user@\u003cBastion Host Public IP\u003e:/home/ec2-user\nchmod 777 deploy.sh\n```\n\nSecrets on github\n\n![git](./assets/git-secrets.png)\n\nProof of pipeline\n\n![pipeline](./assets/pipeline.png)\n\n![proof](./assets/proof.png)\n\n# Monitoring AWS\n\n**Requirements:**\nAdd a CloudWatch alert that sends an email notification when the RDS database exceeds 80% capacity\n\n1. Create a IAM policy for allow CloudWatch to send email notifications\n\n```bash\naws iam create-policy --policy-name CloudWatchEmailNotification --policy-document file://./monitoring/cloudwatch-email-notification-policy.json\n{\n    \"Policy\":\n        \"PolicyName\": \"CloudWatchEmailNotification\",\n        \"PolicyId\": \"ANPASMH5QOAHDUC57XQ4O\",\n        \"Arn\": \"arn:aws:iam::163740413966:policy/CloudWatchEmailNotification\",\n        \"Path\": \"/\",\n        \"DefaultVersionId\": \"v1\",\n        \"AttachmentCount\": 0,\n        \"PermissionsBoundaryUsageCount\": 0,\n        \"IsAttachable\": true,\n        \"CreateDate\": \"2023-05-28T04:41:20+00:00\",\n}\n```\n\n2. Get ARN of the policy\n\n```bash\naws iam list-policies --query 'Policies[?PolicyName==`CloudWatchEmailNotification`].Arn' --output text\n# arn:aws:iam::163740413966:policy/CloudWatchEmailNotification\n```\n\n3. Create a SNS topic\n\n```bash\naws sns create-topic --name RDS-Storage-Usage\n```\n\n4. Subscribe emails to the topic\n\n```bash\naws sns subscribe --topic-arn arn:aws:sns:us-east-1:163740413966:RDS-Storage-Usage --protocol email --notification-endpoint xxxx@gmail.com\n```\n\n5. Configure CloudWatch to send email notifications\n\n```bash\naws cloudwatch put-metric-alarm --alarm-name RDS-Storage-Usage --alarm-description \"RDS Storage Usage\" --metric-name CPUUtilization --namespace AWS/RDS --statistic Average --period 300 --threshold 80 --comparison-operator GreaterThanThreshold --dimensions Name=DBInstanceIdentifier,Value=demo-database --evaluation-periods 1 --alarm-actions arn:aws:sns:us-east-1:163740413966:RDS-Storage-Usage --unit Bytes\n```\n\n![alarms](./assets/alarm.png)\n\n6. Delete resources\n\n```bash\naws cloudwatch delete-alarms --alarm-names RDS-Storage-Usage\naws sns delete-topic --topic-arn arn:aws:sns:us-east-1:163740413966:RDS-Storage-Usage\naws iam delete-policy --policy-arn arn:aws:iam::163740413966:policy/CloudWatchEmailNotification\n``` ","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Falejandro945%2Faws-tree-tier-app","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Falejandro945%2Faws-tree-tier-app","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Falejandro945%2Faws-tree-tier-app/lists"}