├── firelens ├── parsers.conf ├── Dockerfile ├── stream_processor.conf ├── fluent-bit-custom.conf └── taskdef_logrouter.json ├── cicd ├── appspec.yaml ├── buildspec_before.yml ├── buildspec.yml └── taskdef.json ├── iam ├── secrets_policy.json ├── bastion_passrole_policy.json ├── cloud9_codecommit_policy.json ├── ecs_logrouter_policy.json └── cloud9_ecr_policy.json ├── fargate-bastion ├── Dockerfile └── run.sh ├── README.md ├── cloud9 └── resize.sh ├── scan └── buildspec.yml ├── cloudformations ├── frontend.cf.yml ├── appendix1.yml ├── network_step1.yml └── network_step2.yml └── LICENSE /firelens/parsers.conf: -------------------------------------------------------------------------------- 1 | [PARSER] 2 | Name json 3 | Format json 4 | 5 | -------------------------------------------------------------------------------- /cicd/appspec.yaml: -------------------------------------------------------------------------------- 1 | version: 1 2 | Resources: 3 | - TargetService: 4 | Type: AWS::ECS::Service 5 | Properties: 6 | TaskDefinition: 7 | LoadBalancerInfo: 8 | ContainerName: "app" 9 | ContainerPort: 80 10 | -------------------------------------------------------------------------------- /firelens/Dockerfile: -------------------------------------------------------------------------------- 1 | FROM amazon/aws-for-fluent-bit:2.16.1 2 | 3 | COPY ./fluent-bit-custom.conf /fluent-bit/custom.conf 4 | COPY ./myparsers.conf /fluent-bit/myparsers.conf 5 | COPY ./stream_processor.conf /fluent-bit/stream_processor.conf 6 | 7 | RUN ln -sf /usr/share/zoneinfo/Asia/Seoul /etc/localtime -------------------------------------------------------------------------------- /iam/secrets_policy.json: -------------------------------------------------------------------------------- 1 | { 2 | "Version": "2012-10-17", 3 | "Statement": [ 4 | { 5 | "Sid": "GetSecretForECS", 6 | "Effect": "Allow", 7 | "Action": [ 8 | "secretsmanager:GetSecretValue" 9 | ], 10 | "Resource": ["*"] 11 | } 12 | ] 13 | } 14 | -------------------------------------------------------------------------------- /firelens/stream_processor.conf: -------------------------------------------------------------------------------- 1 | [STREAM_TASK] 2 | Name access 3 | Exec CREATE STREAM access WITH (tag='access-log') AS SELECT * FROM TAG:'*-firelens-*' WHERE status >= 200 AND uri <> '/healthcheck'; 4 | 5 | [STREAM_TASK] 6 | Name error 7 | Exec CREATE STREAM error WITH (tag='error-log') AS SELECT * FROM TAG:'*-firelens-*' WHERE status >= 400 and status < 600; 8 | -------------------------------------------------------------------------------- /iam/bastion_passrole_policy.json: -------------------------------------------------------------------------------- 1 | { 2 | "Version": "2012-10-17", 3 | "Statement": [ 4 | { 5 | "Effect": "Allow", 6 | "Action": "iam:PassRole", 7 | "Resource": "*", 8 | "Condition": { 9 | "StringEquals": { "iam:PassedToService": "ssm.amazonaws.com" } 10 | } 11 | }, 12 | { 13 | "Effect": "Allow", 14 | "Action": [ 15 | "ssm:DeleteActivation", 16 | "ssm:RemoveTagsFromResource", 17 | "ssm:AddTagsToResource", 18 | "ssm:CreateActivation" 19 | ], 20 | "Resource": "*" 21 | } 22 | ] 23 | } 24 | -------------------------------------------------------------------------------- /iam/cloud9_codecommit_policy.json: -------------------------------------------------------------------------------- 1 | { 2 | "Version": "2012-10-17", 3 | "Statement": [ 4 | { 5 | "Effect": "Allow", 6 | "Action": [ 7 | "codecommit:BatchGet*", 8 | "codecommit:BatchDescribe*", 9 | "codecommit:Describe*", 10 | "codecommit:Get*", 11 | "codecommit:List*", 12 | "codecommit:Merge*", 13 | "codecommit:Put*", 14 | "codecommit:Post*", 15 | "codecommit:Update*", 16 | "codecommit:GitPull", 17 | "codecommit:GitPush" 18 | ], 19 | "Resource": "arn:aws:codecommit:ap-northeast-2:[aws_account_id]:sbcntr-backend" 20 | } 21 | ] 22 | } 23 | -------------------------------------------------------------------------------- /fargate-bastion/Dockerfile: -------------------------------------------------------------------------------- 1 | FROM amazonlinux:2 2 | RUN yum install -y sudo jq awscli shadow-utils htop lsof telnet bind-utils yum-utils && \ 3 | yum install -y https://s3.ap-northeast-2.amazonaws.com/amazon-ssm-ap-northeast-2/latest/linux_amd64/amazon-ssm-agent.rpm && \ 4 | yum install -y yum localinstall https://dev.mysql.com/get/mysql80-community-release-el7-3.noarch.rpm && \ 5 | yum-config-manager --disable mysql80-community && \ 6 | yum-config-manager --enable mysql57-community && \ 7 | yum install -y mysql-community-client && \ 8 | adduser ssm-user && echo "ssm-user ALL=(ALL) NOPASSWD:ALL" > /etc/sudoers.d/ssm-agent-users && \ 9 | mv /etc/amazon/ssm/amazon-ssm-agent.json.template /etc/amazon/ssm/amazon-ssm-agent.json && \ 10 | mv /etc/amazon/ssm/seelog.xml.template /etc/amazon/ssm/seelog.xml 11 | COPY run.sh /run.sh 12 | CMD ["sh", "/run.sh"] 13 | -------------------------------------------------------------------------------- /firelens/fluent-bit-custom.conf: -------------------------------------------------------------------------------- 1 | [SERVICE] 2 | Parsers_File /fluent-bit/myparsers.conf 3 | Streams_File /fluent-bit/stream_processor.conf 4 | 5 | [FILTER] 6 | Name parser 7 | Match *-firelens-* 8 | Key_Name log 9 | Parser json 10 | Reserve_Data true 11 | 12 | [OUTPUT] 13 | Name cloudwatch 14 | Match access-log 15 | region ${AWS_REGION} 16 | log_group_name ${LOG_GROUP_NAME} 17 | log_stream_prefix from-fluentbit/ 18 | auto_create_group true 19 | 20 | [OUTPUT] 21 | Name cloudwatch 22 | Match error-log 23 | region ${AWS_REGION} 24 | log_group_name ${LOG_GROUP_NAME} 25 | log_stream_prefix from-fluentbit/ 26 | auto_create_group true 27 | 28 | [OUTPUT] 29 | Name s3 30 | Match access-log 31 | region ${AWS_REGION} 32 | bucket ${LOG_BUCKET_NAME} 33 | total_file_size 1M 34 | upload_timeout 1m -------------------------------------------------------------------------------- /iam/ecs_logrouter_policy.json: -------------------------------------------------------------------------------- 1 | { 2 | "Version": "2012-10-17", 3 | "Statement": [ 4 | { 5 | "Effect": "Allow", 6 | "Action": [ 7 | "s3:AbortMultipartUpload", 8 | "s3:GetBucketLocation", 9 | "s3:GetObject", 10 | "s3:ListBucket", 11 | "s3:ListBucketMultipartUploads", 12 | "s3:PutObject" 13 | ], 14 | "Resource": ["arn:aws:s3:::[bucket_name]", "arn:aws:s3:::[bucket_name]/*"] 15 | }, 16 | { 17 | "Effect": "Allow", 18 | "Action": ["kms:Decrypt", "kms:GenerateDataKey"], 19 | "Resource": ["*"] 20 | }, 21 | { 22 | "Effect": "Allow", 23 | "Action": [ 24 | "logs:CreateLogGroup", 25 | "logs:CreateLogStream", 26 | "logs:DescribeLogGroups", 27 | "logs:DescribeLogStreams", 28 | "logs:PutLogEvents" 29 | ], 30 | "Resource": ["*"] 31 | } 32 | ] 33 | } 34 | -------------------------------------------------------------------------------- /fargate-bastion/run.sh: -------------------------------------------------------------------------------- 1 | #/bin/sh 2 | 3 | # Preparation 4 | SSM_SERVICE_ROLE_NAME="sbcntr-SSMServiceRole" 5 | SSM_ACTIVATION_FILE="code.json" 6 | AWS_REGION="ap-northeast-2" 7 | 8 | # Create Activation Code on Systems Manager 9 | aws ssm create-activation \ 10 | --description "Activation Code for Fargate Bastion" \ 11 | --default-instance-name bastion \ 12 | --iam-role ${SSM_SERVICE_ROLE_NAME} \ 13 | --registration-limit 1 \ 14 | --tags Key=Type,Value=Bastion \ 15 | --region ${AWS_REGION} | tee ${SSM_ACTIVATION_FILE} 16 | 17 | SSM_ACTIVATION_ID=`cat ${SSM_ACTIVATION_FILE} | jq -r .ActivationId` 18 | SSM_ACTIVATION_CODE=`cat ${SSM_ACTIVATION_FILE} | jq -r .ActivationCode` 19 | rm -f ${SSM_ACTIVATION_FILE} 20 | 21 | # Activate SSM Agent on Fargate Task 22 | amazon-ssm-agent -register -code "${SSM_ACTIVATION_CODE}" -id "${SSM_ACTIVATION_ID}" -region ${AWS_REGION} 23 | 24 | # Delete Activation Code 25 | aws ssm delete-activation --activation-id ${SSM_ACTIVATION_ID} 26 | 27 | # Execute SSM Agent 28 | amazon-ssm-agent 29 | -------------------------------------------------------------------------------- /cicd/buildspec_before.yml: -------------------------------------------------------------------------------- 1 | version: 0.2 2 | 3 | env: 4 | variables: 5 | AWS_REGION_NAME: ap-northeast-2 6 | ECR_REPOSITORY_NAME: sbcntr-backend 7 | DOCKER_BUILDKIT: "1" 8 | 9 | phases: 10 | install: 11 | runtime-versions: 12 | docker: 19 13 | 14 | pre_build: 15 | commands: 16 | - AWS_ACCOUNT_ID=$(aws sts get-caller-identity --query 'Account' --output text) 17 | - aws ecr --region ap-northeast-2 get-login-password | docker login --username AWS --password-stdin https://${AWS_ACCOUNT_ID}.dkr.ecr.ap-northeast-2.amazonaws.com/sbcntr-backend 18 | - REPOSITORY_URI=${AWS_ACCOUNT_ID}.dkr.ecr.${AWS_REGION_NAME}.amazonaws.com/${ECR_REPOSITORY_NAME} 19 | # 태그 이름에 Git 커밋 해시를 이용 20 | - IMAGE_TAG=$(echo ${CODEBUILD_RESOLVED_SOURCE_VERSION} | cut -c 1-7) 21 | 22 | build: 23 | commands: 24 | - docker image build -t ${REPOSITORY_URI}:${IMAGE_TAG} . 25 | 26 | post_build: 27 | commands: 28 | - docker push ${REPOSITORY_URI}:${IMAGE_TAG} -------------------------------------------------------------------------------- /cicd/buildspec.yml: -------------------------------------------------------------------------------- 1 | version: 0.2 2 | 3 | env: 4 | variables: 5 | AWS_REGION_NAME: ap-northeast-2 6 | ECR_REPOSITORY_NAME: sbcntr-backend 7 | DOCKER_BUILDKIT: "1" 8 | 9 | phases: 10 | install: 11 | runtime-versions: 12 | docker: 19 13 | 14 | pre_build: 15 | commands: 16 | - AWS_ACCOUNT_ID=$(aws sts get-caller-identity --query 'Account' --output text) 17 | - aws ecr --region ap-northeast-2 get-login-password | docker login --username AWS --password-stdin https://${AWS_ACCOUNT_ID}.dkr.ecr.ap-northeast-2.amazonaws.com/sbcntr-backend 18 | - REPOSITORY_URI=${AWS_ACCOUNT_ID}.dkr.ecr.${AWS_REGION_NAME}.amazonaws.com/${ECR_REPOSITORY_NAME} 19 | # 태그 이름에 Git 커밋 해시를 이용 20 | - IMAGE_TAG=$(echo ${CODEBUILD_RESOLVED_SOURCE_VERSION} | cut -c 1-7) 21 | build: 22 | commands: 23 | - docker image build -t ${REPOSITORY_URI}:${IMAGE_TAG} . 24 | post_build: 25 | commands: 26 | - docker image push ${REPOSITORY_URI}:${IMAGE_TAG} 27 | - printf '{"name":"%s","ImageURI":"%s"}' $ECR_REPOSITORY_NAME $REPOSITORY_URI:$IMAGE_TAG > imageDetail.json 28 | 29 | artifacts: 30 | files: 31 | - imageDetail.json 32 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # sbcntr-resources 2 | 3 | 서적용 각종 자원 다운로드 리포지토리다. 4 | 5 | ## 리포지토리 구성 6 | 7 | ```bash 8 | ❯ tree . -d 1 9 | . 10 | ├── cicd 11 | ├── cloudformations 12 | ├── cloud9 13 | ├── fargate-bastion 14 | ├── firelens 15 | ├── iam 16 | └── scan 17 | ``` 18 | 19 | 20 | 각 디렉토리와 책의 관계는 다음과 같다. 21 | 22 | | 디렉토리 | 관련된 부분 | 내용 | 23 | |-----------------|------------------------------------------------------------|--------------------------------------------------| 24 | | cicd | 5-2 운영 설계:Code 시리즈를 사용한 CI/CD | CI/CD설계에서 이용할 빌드 정의와 태스크 정의 등 | 25 | | cloudformations | 4-2 네트워크 구축, 4-4 컨테이너 레지스트리 구축, 4-5 오케스트레이터 구축, 부록 1| 실습 및 부록에서 이용하는 CloudFormation | 26 | | cloud9 | 4-4 컨테이너 레지스트리 구축 | resize.sh | 27 | | fargate-bastion | 5-7 운영 설계:Fargate를 이용한 Bastion 구축 | Fargate Bastion에서 이용하는Bastion컨테이너 설정| 28 | | firelens | 5-6 운영 설계 & 보안 설계: 로그 수집 기반 | 로그 수집 기반 FireLens 컨테이너에 설정할 로그 관련 설정| 29 | | iam | 4, 5장 전반 | 4장과 5장에서 이용하는 각종 IAM 정책의 JSON 내용 | 30 | | scan | 5-8 보안 설계: Trivy/Dockle 을 이용한 보안 확인 | DevSecOps 구현을 위한 CodeBuild 빌드 정의| 31 | 32 | -------------------------------------------------------------------------------- /cicd/taskdef.json: -------------------------------------------------------------------------------- 1 | { 2 | "executionRoleArn": "arn:aws:iam::[aws_account_id]:role/ecsTaskExecutionRole", 3 | "containerDefinitions": [ 4 | { 5 | "logConfiguration": { 6 | "logDriver": "awslogs", 7 | "secretOptions": null, 8 | "options": { 9 | "awslogs-group": "/ecs/sbcntr-backend-def", 10 | "awslogs-region": "ap-northeast-2", 11 | "awslogs-stream-prefix": "ecs" 12 | } 13 | }, 14 | "portMappings": [ 15 | { 16 | "hostPort": 80, 17 | "protocol": "tcp", 18 | "containerPort": 80 19 | } 20 | ], 21 | "cpu": 256, 22 | "readonlyRootFilesystem": true, 23 | "environment": [], 24 | "secrets": [ 25 | { 26 | "valueFrom": "[Secrets Manager 보안 암호 ARN]:host::", 27 | "name": "DB_HOST" 28 | }, 29 | { 30 | "valueFrom": "[Secrets Manager 보안 암호 ARN]:dbname::", 31 | "name": "DB_NAME" 32 | }, 33 | { 34 | "valueFrom": "[Secrets Manager 보안 암호 ARN]:password::", 35 | "name": "DB_PASSWORD" 36 | }, 37 | { 38 | "valueFrom": "[Secrets Manager 보안 암호 ARN]:username::", 39 | "name": "DB_USERNAME" 40 | } 41 | ], 42 | "memory": null, 43 | "memoryReservation": 512, 44 | "image": "", 45 | "essential": true, 46 | "name": "app" 47 | } 48 | ], 49 | "memory": "1024", 50 | "taskRoleArn": null, 51 | "family": "sbcntr-backend-def", 52 | "requiresCompatibilities": ["FARGATE"], 53 | "networkMode": "awsvpc", 54 | "cpu": "512" 55 | } 56 | -------------------------------------------------------------------------------- /iam/cloud9_ecr_policy.json: -------------------------------------------------------------------------------- 1 | { 2 | "Version": "2012-10-17", 3 | "Statement": [ 4 | { 5 | "Sid": "ListImagesInRepository", 6 | "Effect": "Allow", 7 | "Action": [ 8 | "ecr:ListImages" 9 | ], 10 | "Resource": [ 11 | "arn:aws:ecr:ap-northeast-2:[aws_account_id]:repository/sbcntr-backend", 12 | "arn:aws:ecr:ap-northeast-2:[aws_account_id]:repository/sbcntr-frontend" 13 | ] 14 | }, 15 | { 16 | "Sid": "GetAuthorizationToken", 17 | "Effect": "Allow", 18 | "Action": [ 19 | "ecr:GetAuthorizationToken" 20 | ], 21 | "Resource": "*" 22 | }, 23 | { 24 | "Sid": "ManageRepositoryContents", 25 | "Effect": "Allow", 26 | "Action": [ 27 | "ecr:BatchCheckLayerAvailability", 28 | "ecr:GetDownloadUrlForLayer", 29 | "ecr:GetRepositoryPolicy", 30 | "ecr:DescribeRepositories", 31 | "ecr:ListImages", 32 | "ecr:DescribeImages", 33 | "ecr:BatchGetImage", 34 | "ecr:InitiateLayerUpload", 35 | "ecr:UploadLayerPart", 36 | "ecr:CompleteLayerUpload", 37 | "ecr:PutImage" 38 | ], 39 | "Resource": [ 40 | "arn:aws:ecr:ap-northeast-2:[aws_account_id]:repository/sbcntr-backend", 41 | "arn:aws:ecr:ap-northeast-2:[aws_account_id]:repository/sbcntr-frontend" 42 | ] 43 | } 44 | ] 45 | } 46 | -------------------------------------------------------------------------------- /cloud9/resize.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | # Specify the desired volume size in GiB as a command line argument. If not specified, default to 20 GiB. 4 | SIZE=${1:-20} 5 | 6 | # Get the ID of the environment host Amazon EC2 instance. 7 | INSTANCEID=$(curl http://169.254.169.254/latest/meta-data/instance-id) 8 | REGION=$(curl -s http://169.254.169.254/latest/meta-data/placement/availability-zone | sed 's/\(.*\)[a-z]/\1/') 9 | 10 | # Get the ID of the Amazon EBS volume associated with the instance. 11 | VOLUMEID=$(aws ec2 describe-instances \ 12 | --instance-id $INSTANCEID \ 13 | --query "Reservations[0].Instances[0].BlockDeviceMappings[0].Ebs.VolumeId" \ 14 | --output text \ 15 | --region $REGION) 16 | 17 | # Resize the EBS volume. 18 | aws ec2 modify-volume --volume-id $VOLUMEID --size $SIZE 19 | 20 | # Wait for the resize to finish. 21 | while [ \ 22 | "$(aws ec2 describe-volumes-modifications \ 23 | --volume-id $VOLUMEID \ 24 | --filters Name=modification-state,Values="optimizing","completed" \ 25 | --query "length(VolumesModifications)"\ 26 | --output text)" != "1" ]; do 27 | sleep 1 28 | done 29 | 30 | #Check if we're on an NVMe filesystem 31 | if [[ -e "/dev/xvda" && $(readlink -f /dev/xvda) = "/dev/xvda" ]] 32 | then 33 | # Rewrite the partition table so that the partition takes up all the space that it can. 34 | sudo growpart /dev/xvda 1 35 | 36 | # Expand the size of the file system. 37 | # Check if we're on AL2 38 | STR=$(cat /etc/os-release) 39 | SUB="VERSION_ID=\"2\"" 40 | if [[ "$STR" == *"$SUB"* ]] 41 | then 42 | sudo xfs_growfs -d / 43 | else 44 | sudo resize2fs /dev/xvda1 45 | fi 46 | 47 | else 48 | # Rewrite the partition table so that the partition takes up all the space that it can. 49 | sudo growpart /dev/nvme0n1 1 50 | 51 | # Expand the size of the file system. 52 | # Check if we're on AL2 53 | STR=$(cat /etc/os-release) 54 | SUB="VERSION_ID=\"2\"" 55 | if [[ "$STR" == *"$SUB"* ]] 56 | then 57 | sudo xfs_growfs -d / 58 | else 59 | sudo resize2fs /dev/nvme0n1p1 60 | fi 61 | fi -------------------------------------------------------------------------------- /scan/buildspec.yml: -------------------------------------------------------------------------------- 1 | version: 0.2 2 | 3 | env: 4 | variables: 5 | AWS_REGION_NAME: ap-northeast-2 6 | ECR_REPOSITORY_NAME: sbcntr-backend 7 | DOCKER_BUILDKIT: "1" 8 | 9 | phases: 10 | install: 11 | runtime-versions: 12 | docker: 19 13 | 14 | pre_build: 15 | commands: 16 | - AWS_ACCOUNT_ID=$(aws sts get-caller-identity --query 'Account' --output text) 17 | - aws ecr --region ap-northeast-2 get-login-password | docker login --username AWS --password-stdin https://${AWS_ACCOUNT_ID}.dkr.ecr.ap-northeast-2.amazonaws.com/sbcntr-backend 18 | - REPOSITORY_URI=${AWS_ACCOUNT_ID}.dkr.ecr.${AWS_REGION_NAME}.amazonaws.com/${ECR_REPOSITORY_NAME} 19 | # 태그 이름으로 Git 커밋 해시를 이용 20 | - IMAGE_TAG=$(echo ${CODEBUILD_RESOLVED_SOURCE_VERSION} | cut -c 1-7) 21 | # 사전 준비: trivy를 설치 22 | # 주석 처리된 curl 명령을 이용해 최신 버전을 취득하도록 구성할 수 있음 23 | #- TRIVY_VERSION=$(curl -sS https://api.github.com/repos/aquasecurity/trivy/releases/latest | grep '"tag_name":' | sed -E 's/.*"v([^"]+)".*/\1/') 24 | - TRIVY_VERSION=0.19.2 25 | - rpm -ivh https://github.com/aquasecurity/trivy/releases/download/v${TRIVY_VERSION}/trivy_${TRIVY_VERSION}_Linux-64bit.rpm 26 | # 사전 준비: dockle 설치 27 | # 주석 처리된 curl 명령을 이용해 최신 버전을 취득하도록 구성할 수 있음 28 | #- DOCKLE_VERSION=$(curl -sS https://api.github.com/repos/goodwithtech/dockle/releases/latest | grep '"tag_name":' | sed -E 's/.*"v([^"]+)".*/\1/') 29 | - DOCKLE_VERSION=0.3.15 30 | - rpm -ivh https://github.com/goodwithtech/dockle/releases/download/v${DOCKLE_VERSION}/dockle_${DOCKLE_VERSION}_Linux-64bit.rpm 31 | 32 | build: 33 | commands: 34 | - docker image build -t ${REPOSITORY_URI}:${IMAGE_TAG} . 35 | 36 | post_build: 37 | commands: 38 | # trivy를 이용한 이미지 스캔(결과 저장용) 39 | - trivy --no-progress -f json -o trivy_results.json --exit-code 0 ${REPOSITORY_URI}:${IMAGE_TAG} 40 | # trivy를 이용한 이미지 스캔(취약점 수준이 CRITICAL인 경우는 빌드를 강제 종료) 41 | - trivy --no-progress --exit-code 1 --severity CRITICAL ${REPOSITORY_URI}:${IMAGE_TAG} 42 | - exit `echo $?` 43 | # dockle를 이용한 이미지 확인(취약점 수준이 FATAL인 경우는 빌드를 강제 종료) 44 | - dockle --format json -o dockle_results.json --exit-code 1 --exit-level "FATAL" ${REPOSITORY_URI}:${IMAGE_TAG} 45 | - exit `echo $?` 46 | # Docker이미지를 ECR에 푸시 47 | - docker image push ${REPOSITORY_URI}:${IMAGE_TAG} 48 | # 이미지 URL을 기록한 JSON 생성 49 | - printf '{"name":"%s","ImageURI":"%s"}' $ECR_REPOSITORY_NAME $REPOSITORY_URI:$IMAGE_TAG > imageDetail.json 50 | 51 | artifacts: 52 | files: 53 | - imageDetail.json 54 | - trivy_results.json 55 | - dockle_results.json -------------------------------------------------------------------------------- /firelens/taskdef_logrouter.json: -------------------------------------------------------------------------------- 1 | { 2 | "executionRoleArn": "arn:aws:iam::[aws_account_id]:role/ecsTaskExecutionRole", 3 | "containerDefinitions": [ 4 | { 5 | "logConfiguration": { 6 | "logDriver": "awsfirelens", 7 | "secretOptions": null, 8 | "options": null 9 | }, 10 | "portMappings": [ 11 | { 12 | "hostPort": 80, 13 | "protocol": "tcp", 14 | "containerPort": 80 15 | } 16 | ], 17 | "cpu": 256, 18 | "environment": [], 19 | "secrets": [ 20 | { 21 | "valueFrom": "arn:aws:secretsmanager:ap-northeast-2:[aws_account_id]:secret:[mysql_secret_alias]:host::", 22 | "name": "DB_HOST" 23 | }, 24 | { 25 | "valueFrom": "arn:aws:secretsmanager:ap-northeast-2:[aws_account_id]:secret:[mysql_secret_alias]:dbname::", 26 | "name": "DB_NAME" 27 | }, 28 | { 29 | "valueFrom": "arn:aws:secretsmanager:ap-northeast-2:[aws_account_id]:secret:[mysql_secret_alias]:password::", 30 | "name": "DB_PASSWORD" 31 | }, 32 | { 33 | "valueFrom": "arn:aws:secretsmanager:ap-northeast-2:[aws_account_id]:secret:[mysql_secret_alias]:username::", 34 | "name": "DB_USERNAME" 35 | } 36 | ], 37 | "memory": null, 38 | "memoryReservation": 512, 39 | "image": "", 40 | "readonlyRootFilesystem": true, 41 | "essential": true, 42 | "name": "app" 43 | }, 44 | { 45 | "logConfiguration": { 46 | "logDriver": "awslogs", 47 | "options": { 48 | "awslogs-group": "/aws/ecs/sbcntr-firelens-container", 49 | "awslogs-region": "ap-northeast-2", 50 | "awslogs-stream-prefix": "firelens" 51 | } 52 | }, 53 | "cpu": 64, 54 | "environment": [ 55 | { 56 | "name": "APP_ID", 57 | "value": "backend-def" 58 | }, 59 | { 60 | "name": "AWS_ACCOUNT_ID", 61 | "value": "[aws_account_id]" 62 | }, 63 | { 64 | "name": "AWS_REGION", 65 | "value": "ap-northeast-2" 66 | }, 67 | { 68 | "name": "LOG_BUCKET_NAME", 69 | "value": "sbcntr-[aws_account_id]" 70 | }, 71 | { 72 | "name": "LOG_GROUP_NAME", 73 | "value": "/aws/ecs/sbcntr-backend-def" 74 | } 75 | ], 76 | "memoryReservation": 128, 77 | "image": "[aws_account_id].dkr.ecr.ap-northeast-2.amazonaws.com/sbcntr-base:log-router", 78 | "firelensConfiguration": { 79 | "type": "fluentbit", 80 | "options": { 81 | "config-file-type": "file", 82 | "config-file-value": "/fluent-bit/custom.conf" 83 | } 84 | }, 85 | "name": "log_router" 86 | } 87 | ], 88 | "memory": "1024", 89 | "taskRoleArn": null, 90 | "family": "sbcntr-backend-def", 91 | "requiresCompatibilities": ["FARGATE"], 92 | "networkMode": "awsvpc", 93 | "cpu": "512" 94 | } 95 | -------------------------------------------------------------------------------- /cloudformations/frontend.cf.yml: -------------------------------------------------------------------------------- 1 | AWSTemplateFormatVersion: "2010-09-09" 2 | Description: Create frontend base 3 | 4 | ################# Input parameters ############### 5 | Parameters: 6 | Prefix: 7 | Default: sbcntr 8 | Type: String 9 | VpcId: 10 | Description : Input 'sbcntr' VPC ID 11 | Type: AWS::EC2::VPC::Id 12 | # ALB 13 | ALBSecurityGroupId: 14 | Description: Input 'ingress' SecurityGroup ID 15 | Type: AWS::EC2::SecurityGroup::Id 16 | ALBSubnetId1: 17 | Description : Input 'ingress' Subnet ID for ap-northeast-2a 18 | Type : AWS::EC2::Subnet::Id 19 | ALBSubnetId2: 20 | Description : Input 'ingress' Subnet ID for ap-northeast-2c 21 | Type : AWS::EC2::Subnet::Id 22 | # Backend loadbalancer 23 | BackendHost: 24 | Description : Input DNS A record of backend ALB 25 | Type: String 26 | Default: internal-sbcntr-alb-internal-XXXXXXXXX.ap-northeast-2.elb.amazonaws.com 27 | 28 | 29 | Resources: 30 | ############### ECS ############### 31 | sbcntrECSClusterFrontend: 32 | Type: AWS::ECS::Cluster 33 | Properties: 34 | ClusterName: !Sub "${Prefix}-frontend-cluster" 35 | sbcntrTaskDefinitionFrontend: 36 | Type: AWS::ECS::TaskDefinition 37 | Properties: 38 | Family: !Sub "${Prefix}-frontend-def" 39 | ContainerDefinitions: 40 | - Name: app 41 | Image: !Sub "${AWS::AccountId}.dkr.ecr.${AWS::Region}.amazonaws.com/sbcntr-frontend:v1" 42 | Essential: true 43 | Cpu: 256 44 | MemoryReservation: 512 45 | PortMappings: 46 | - ContainerPort: 80 47 | HostPort: 80 48 | Protocol: tcp 49 | Environment: 50 | - Name: SESSION_SECRET_KEY 51 | Value: 41b678c65b37bf99c37bcab522802760 52 | - Name: APP_SERVICE_HOST 53 | Value: !Sub "http://${BackendHost}" 54 | - Name: NOTIF_SERVICE_HOST 55 | Value: !Sub "http://${BackendHost}" 56 | LogConfiguration: 57 | LogDriver: awslogs 58 | Options: 59 | awslogs-group: !Sub "/ecs/${Prefix}-frontend-def" 60 | awslogs-region: !Ref AWS::Region 61 | awslogs-stream-prefix: ecs 62 | Cpu: 512 63 | Memory: 1024 64 | ExecutionRoleArn: !Sub "arn:aws:iam::${AWS::AccountId}:role/ecsTaskExecutionRole" 65 | NetworkMode: awsvpc 66 | RequiresCompatibilities: 67 | - FARGATE 68 | sbcntrCloudWatchLogsFrontend: 69 | Type: AWS::Logs::LogGroup 70 | Properties: 71 | LogGroupName: /ecs/sbcntr-frontend-def 72 | RetentionInDays: 14 73 | UpdateReplacePolicy: Retain 74 | 75 | ############### Application Load Balancer ############### 76 | sbcntrAlbFrontend: 77 | Type: AWS::ElasticLoadBalancingV2::LoadBalancer 78 | Properties: 79 | Name: !Sub "${Prefix}-alb-ingress-frontend" 80 | Type: application 81 | Scheme: internet-facing 82 | SecurityGroups: 83 | - !Ref ALBSecurityGroupId 84 | Subnets: 85 | - !Ref ALBSubnetId1 86 | - !Ref ALBSubnetId2 87 | LoadBalancerAttributes: 88 | - Key: deletion_protection.enabled 89 | Value: false 90 | sbcntrTargetGroupFrontend: 91 | Type: AWS::ElasticLoadBalancingV2::TargetGroup 92 | Properties: 93 | Name: !Sub "${Prefix}-tg-frontend" 94 | Port: 80 95 | Protocol: HTTP 96 | TargetType: ip 97 | HealthCheckIntervalSeconds: 15 98 | HealthCheckPath: /healthcheck 99 | HealthCheckTimeoutSeconds: 5 100 | HealthyThresholdCount: 3 101 | UnhealthyThresholdCount: 2 102 | Matcher: 103 | HttpCode: 200 104 | VpcId: !Ref VpcId 105 | sbcntrFrontendListener1: 106 | Type: AWS::ElasticLoadBalancingV2::Listener 107 | Properties: 108 | DefaultActions: 109 | - TargetGroupArn: !Ref sbcntrTargetGroupFrontend 110 | Type: forward 111 | LoadBalancerArn: !Ref sbcntrAlbFrontend 112 | Port: 80 113 | Protocol: HTTP 114 | 115 | -------------------------------------------------------------------------------- /cloudformations/appendix1.yml: -------------------------------------------------------------------------------- 1 | AWSTemplateFormatVersion: 2010-09-09 2 | Description: 'Appendix1 cloudformation. IAM group and user, password policy and CloudTrail.' 3 | Parameters: 4 | AdminUserName: 5 | Type: String 6 | Description: Admin name 7 | Default: sbcntr-user 8 | InitialIAMPassword: 9 | Type: String 10 | Description: Initial login password 11 | NoEcho: true 12 | Resources: 13 | # CloudTrail용 KMS 키 생성 14 | cloudtrailKey: 15 | Type: AWS::KMS::Key 16 | Properties: 17 | KeyPolicy: 18 | Version: 2012-10-17 19 | Id: key-cloudtrail 20 | Statement: 21 | - Sid: Enable IAM User Permissions 22 | Effect: Allow 23 | Principal: 24 | AWS: !Join 25 | - '' 26 | - - 'arn:aws:iam::' 27 | - !Ref 'AWS::AccountId' 28 | - ':root' 29 | Action: 'kms:*' 30 | Resource: '*' 31 | - Sid: Allow CloudTrail to encrypt logs 32 | Effect: Allow 33 | Principal: 34 | Service: 35 | - cloudtrail.amazonaws.com 36 | Action: 'kms:GenerateDataKey*' 37 | Resource: '*' 38 | Condition: 39 | StringLike: 40 | 'kms:EncryptionContext:aws:cloudtrail:arn': !Sub 'arn:aws:cloudtrail:*:${AWS::AccountId}:trail/*' 41 | - Sid: Allow CloudTrail to describe key 42 | Effect: Allow 43 | Principal: 44 | Service: 45 | - cloudtrail.amazonaws.com 46 | Action: 'kms:DescribeKey' 47 | Resource: '*' 48 | - Sid: Allow principals in the account to decrypt log files 49 | Effect: Allow 50 | Principal: 51 | AWS: '*' 52 | Action: 53 | - 'kms:Decrypt' 54 | - 'kms:ReEncryptFrom' 55 | Resource: '*' 56 | Condition: 57 | StringEquals: 58 | 'kms:CallerAccount': !Sub '${AWS::AccountId}' 59 | StringLike: 60 | 'kms:EncryptionContext:aws:cloudtrail:arn': !Sub 'arn:aws:cloudtrail:*:${AWS::AccountId}:trail/*' 61 | - Sid: Allow alias creation during setup 62 | Effect: Allow 63 | Principal: 64 | AWS: '*' 65 | Action: 'kms:CreateAlias' 66 | Resource: '*' 67 | Condition: 68 | StringEquals: 69 | 'kms:ViaService': ec2.region.amazonaws.com 70 | 'kms:CallerAccount': !Sub '${AWS::AccountId}' 71 | - Sid: Enable cross account log decryption 72 | Effect: Allow 73 | Principal: 74 | AWS: '*' 75 | Action: 76 | - 'kms:Decrypt' 77 | - 'kms:ReEncryptFrom' 78 | Resource: '*' 79 | Condition: 80 | StringEquals: 81 | 'kms:CallerAccount': !Sub '${AWS::AccountId}' 82 | StringLike: 83 | 'kms:EncryptionContext:aws:cloudtrail:arn': !Sub 'arn:aws:cloudtrail:*:${AWS::AccountId}:trail/*' 84 | 85 | cloudtrailKeyAlias: 86 | Type: AWS::KMS::Alias 87 | Properties: 88 | AliasName: alias/cloudtrail 89 | TargetKeyId: 90 | Ref: cloudtrailKey 91 | 92 | # CloudTrail을 저장할 S3 암호화 키용 KSM 키 생성 93 | s3cloudtrailKey: 94 | Type: AWS::KMS::Key 95 | Properties: 96 | KeyPolicy: 97 | Version: 2012-10-17 98 | Id: key-cloudtrails3 99 | Statement: 100 | - Sid: Enable IAM User Permissions 101 | Effect: Allow 102 | Principal: 103 | AWS: !Join 104 | - '' 105 | - - 'arn:aws:iam::' 106 | - !Ref 'AWS::AccountId' 107 | - ':root' 108 | Action: 'kms:*' 109 | Resource: '*' 110 | - Sid: Allow VPC Flow Logs to use the key 111 | Effect: Allow 112 | Principal: 113 | Service: 114 | - delivery.logs.amazonaws.com 115 | Action: 'kms:GenerateDataKey*' 116 | Resource: '*' 117 | 118 | s3cloudtrailKeyAlias: 119 | Type: AWS::KMS::Alias 120 | Properties: 121 | AliasName: alias/cloudtrails3 122 | TargetKeyId: 123 | Ref: s3cloudtrailKey 124 | 125 | # CloudTrail용 S3 버킷 생성 126 | CloudTrailS3Bucket: 127 | DependsOn: 128 | - s3cloudtrailKey 129 | - s3cloudtrailKeyAlias 130 | Type: AWS::S3::Bucket 131 | DeletionPolicy: Retain 132 | Properties: 133 | BucketEncryption: 134 | ServerSideEncryptionConfiguration: 135 | - ServerSideEncryptionByDefault: 136 | KMSMasterKeyID: !Sub 'arn:aws:kms:${AWS::Region}:${AWS::AccountId}:${s3cloudtrailKeyAlias}' 137 | SSEAlgorithm: 'aws:kms' 138 | # CloudTrail용 S3 버킷 정책 생성 139 | CloudTrailBucketPolicy: 140 | DependsOn: 141 | - CloudTrailS3Bucket 142 | Type: AWS::S3::BucketPolicy 143 | Properties: 144 | Bucket: !Ref CloudTrailS3Bucket 145 | PolicyDocument: 146 | Version: "2012-10-17" 147 | Statement: 148 | - Sid: "AWSCloudTrailAclCheck" 149 | Effect: Allow 150 | Principal: 151 | Service: 'cloudtrail.amazonaws.com' 152 | Action: "s3:GetBucketAcl" 153 | Resource: !Sub arn:aws:s3:::${CloudTrailS3Bucket} 154 | - Sid: "AWSCloudTrailWrite" 155 | Effect: Allow 156 | Principal: 157 | Service: 'cloudtrail.amazonaws.com' 158 | Action: "s3:PutObject" 159 | Resource: !Sub arn:aws:s3:::${CloudTrailS3Bucket}/AWSLogs/${AWS::AccountId}/* 160 | Condition: 161 | StringEquals: 162 | 's3:x-amz-acl': 'bucket-owner-full-control' 163 | 164 | # CloudTrail 활성화 165 | MyCloudTrail: 166 | DependsOn: 167 | - CloudTrailS3Bucket 168 | - CloudTrailBucketPolicy 169 | - cloudtrailKey 170 | Type: AWS::CloudTrail::Trail 171 | Properties: 172 | S3BucketName: !Ref CloudTrailS3Bucket 173 | IsLogging: true 174 | IsMultiRegionTrail: true 175 | IncludeGlobalServiceEvents: true 176 | KMSKeyId: !GetAtt cloudtrailKey.Arn 177 | 178 | # 패스워드 정책 생성 Lambda용 IAM 역할 및 정책 생성 179 | LambdaRole: 180 | Type: 'AWS::IAM::Role' 181 | Properties: 182 | AssumeRolePolicyDocument: 183 | Version: '2012-10-17' 184 | Statement: 185 | - Effect: Allow 186 | Principal: 187 | Service: 'lambda.amazonaws.com' 188 | Action: 'sts:AssumeRole' 189 | Policies: 190 | - PolicyName: iam 191 | PolicyDocument: 192 | Statement: 193 | - Effect: Allow 194 | Action: 195 | - 'iam:UpdateAccountPasswordPolicy' 196 | - 'iam:DeleteAccountPasswordPolicy' 197 | Resource: '*' 198 | LambdaPolicy: 199 | Type: 'AWS::IAM::Policy' 200 | Properties: 201 | Roles: 202 | - !Ref LambdaRole 203 | PolicyName: lambda 204 | PolicyDocument: 205 | Statement: 206 | - Effect: Allow 207 | Action: 208 | - 'logs:CreateLogStream' 209 | - 'logs:PutLogEvents' 210 | Resource: !GetAtt 'LambdaLogGroup.Arn' 211 | 212 | # 패스워드 정책 생성 Lambda 213 | LambdaFunctionV2: 214 | Type: 'AWS::Lambda::Function' 215 | Properties: 216 | Code: 217 | ZipFile: | 218 | 'use strict'; 219 | const AWS = require('aws-sdk'); 220 | const response = require('cfn-response'); 221 | const iam = new AWS.IAM({apiVersion: '2010-05-08'}); 222 | exports.handler = (event, context, cb) => { 223 | console.log(`Invoke: ${JSON.stringify(event)}`); 224 | function done(err) { 225 | if (err) { 226 | console.log(`Error: ${JSON.stringify(err)}`); 227 | response.send(event, context, response.FAILED, {}); 228 | } else { 229 | response.send(event, context, response.SUCCESS, {}); 230 | } 231 | } 232 | if (event.RequestType === 'Delete') { 233 | iam.deleteAccountPasswordPolicy({}, done); 234 | } else if (event.RequestType === 'Create' || event.RequestType === 'Update') { 235 | const params = { 236 | MinimumPasswordLength: parseInt(event.ResourceProperties.MinimumPasswordLength, 10), 237 | RequireSymbols: event.ResourceProperties.RequireSymbols === 'true', 238 | RequireNumbers: event.ResourceProperties.RequireNumbers === 'true', 239 | RequireUppercaseCharacters: event.ResourceProperties.RequireUppercaseCharacters === 'true', 240 | RequireLowercaseCharacters: event.ResourceProperties.RequireLowercaseCharacters === 'true', 241 | AllowUsersToChangePassword: event.ResourceProperties.AllowUsersToChangePassword === 'true', 242 | HardExpiry: event.ResourceProperties.HardExpiry === 'true' 243 | }; 244 | if (parseInt(event.ResourceProperties.MaxPasswordAge, 10) > 0) { 245 | params.MaxPasswordAge = parseInt(event.ResourceProperties.MaxPasswordAge, 10); 246 | } 247 | if (parseInt(event.ResourceProperties.PasswordReusePrevention, 10) > 0) { 248 | params.PasswordReusePrevention = parseInt(event.ResourceProperties.PasswordReusePrevention, 10); 249 | } 250 | iam.updateAccountPasswordPolicy(params, done); 251 | } else { 252 | cb(new Error(`unsupported RequestType: ${event.RequestType}`)); 253 | } 254 | }; 255 | Handler: 'index.handler' 256 | MemorySize: 128 257 | Role: !GetAtt 'LambdaRole.Arn' 258 | Runtime: 'nodejs12.x' 259 | Timeout: 60 260 | LambdaLogGroup: 261 | Type: 'AWS::Logs::LogGroup' 262 | Properties: 263 | LogGroupName: !Sub '/aws/lambda/${LambdaFunctionV2}' 264 | RetentionInDays: 14 265 | PasswordPolicy: 266 | Type: 'Custom::PasswordPolicy' 267 | DependsOn: 268 | - LambdaLogGroup 269 | - LambdaPolicy 270 | Version: '1.0' 271 | Properties: 272 | AllowUsersToChangePassword: true 273 | # CIS AWS Foundations 1.5 274 | RequireUppercaseCharacters: true 275 | # CIS AWS Foundations 1.6 276 | RequireLowercaseCharacters: true 277 | # CIS AWS Foundations 1.7 278 | RequireSymbols: true 279 | # CIS AWS Foundations 1.8 280 | RequireNumbers: true 281 | # CIS AWS Foundations 1.9 282 | MinimumPasswordLength: 14 283 | # CIS AWS Foundations 1.10 284 | PasswordReusePrevention: 24 285 | # CIS AWS Foundations 1.11 286 | HardExpiry: true 287 | MaxPasswordAge: 90 288 | ServiceToken: !GetAtt 'LambdaFunctionV2.Arn' 289 | 290 | # IAM그룹 생성 291 | IAMGroupAdmin: 292 | Type: AWS::IAM::Group 293 | DeletionPolicy: Retain 294 | Properties: 295 | GroupName: Administrator 296 | ManagedPolicyArns: 297 | - arn:aws:iam::aws:policy/AdministratorAccess 298 | 299 | # 이 책에서 이용할 실습용 이용자 생성 300 | IAMSbcntrContainerHandsonUser: 301 | DependsOn: 302 | - IAMGroupAdmin 303 | Type: AWS::IAM::User 304 | DeletionPolicy: Retain 305 | Properties: 306 | UserName: !Ref AdminUserName 307 | Groups: 308 | - !Ref IAMGroupAdmin 309 | LoginProfile: 310 | Password: !Ref InitialIAMPassword 311 | PasswordResetRequired: true 312 | 313 | # 314 | Outputs: 315 | CloudTrailKMSKeyAlias: 316 | Value: 317 | Ref: 'cloudtrailKeyAlias' 318 | S3KMSKeyAlias: 319 | Value: 320 | Ref: 's3cloudtrailKeyAlias' 321 | CloudTrailS3Bucket: 322 | Value: 323 | Ref: 'CloudTrailS3Bucket' 324 | CloudTrailS3BucketPolicy: 325 | Value: 326 | Ref: 'CloudTrailBucketPolicy' 327 | CloudTrail: 328 | Value: 329 | Ref: 'MyCloudTrail' 330 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | Apache License 2 | Version 2.0, January 2004 3 | http://www.apache.org/licenses/ 4 | 5 | TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION 6 | 7 | 1. Definitions. 8 | 9 | "License" shall mean the terms and conditions for use, reproduction, 10 | and distribution as defined by Sections 1 through 9 of this document. 11 | 12 | "Licensor" shall mean the copyright owner or entity authorized by 13 | the copyright owner that is granting the License. 14 | 15 | "Legal Entity" shall mean the union of the acting entity and all 16 | other entities that control, are controlled by, or are under common 17 | control with that entity. For the purposes of this definition, 18 | "control" means (i) the power, direct or indirect, to cause the 19 | direction or management of such entity, whether by contract or 20 | otherwise, or (ii) ownership of fifty percent (50%) or more of the 21 | outstanding shares, or (iii) beneficial ownership of such entity. 22 | 23 | "You" (or "Your") shall mean an individual or Legal Entity 24 | exercising permissions granted by this License. 25 | 26 | "Source" form shall mean the preferred form for making modifications, 27 | including but not limited to software source code, documentation 28 | source, and configuration files. 29 | 30 | "Object" form shall mean any form resulting from mechanical 31 | transformation or translation of a Source form, including but 32 | not limited to compiled object code, generated documentation, 33 | and conversions to other media types. 34 | 35 | "Work" shall mean the work of authorship, whether in Source or 36 | Object form, made available under the License, as indicated by a 37 | copyright notice that is included in or attached to the work 38 | (an example is provided in the Appendix below). 39 | 40 | "Derivative Works" shall mean any work, whether in Source or Object 41 | form, that is based on (or derived from) the Work and for which the 42 | editorial revisions, annotations, elaborations, or other modifications 43 | represent, as a whole, an original work of authorship. For the purposes 44 | of this License, Derivative Works shall not include works that remain 45 | separable from, or merely link (or bind by name) to the interfaces of, 46 | the Work and Derivative Works thereof. 47 | 48 | "Contribution" shall mean any work of authorship, including 49 | the original version of the Work and any modifications or additions 50 | to that Work or Derivative Works thereof, that is intentionally 51 | submitted to Licensor for inclusion in the Work by the copyright owner 52 | or by an individual or Legal Entity authorized to submit on behalf of 53 | the copyright owner. For the purposes of this definition, "submitted" 54 | means any form of electronic, verbal, or written communication sent 55 | to the Licensor or its representatives, including but not limited to 56 | communication on electronic mailing lists, source code control systems, 57 | and issue tracking systems that are managed by, or on behalf of, the 58 | Licensor for the purpose of discussing and improving the Work, but 59 | excluding communication that is conspicuously marked or otherwise 60 | designated in writing by the copyright owner as "Not a Contribution." 61 | 62 | "Contributor" shall mean Licensor and any individual or Legal Entity 63 | on behalf of whom a Contribution has been received by Licensor and 64 | subsequently incorporated within the Work. 65 | 66 | 2. Grant of Copyright License. Subject to the terms and conditions of 67 | this License, each Contributor hereby grants to You a perpetual, 68 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable 69 | copyright license to reproduce, prepare Derivative Works of, 70 | publicly display, publicly perform, sublicense, and distribute the 71 | Work and such Derivative Works in Source or Object form. 72 | 73 | 3. Grant of Patent License. Subject to the terms and conditions of 74 | this License, each Contributor hereby grants to You a perpetual, 75 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable 76 | (except as stated in this section) patent license to make, have made, 77 | use, offer to sell, sell, import, and otherwise transfer the Work, 78 | where such license applies only to those patent claims licensable 79 | by such Contributor that are necessarily infringed by their 80 | Contribution(s) alone or by combination of their Contribution(s) 81 | with the Work to which such Contribution(s) was submitted. If You 82 | institute patent litigation against any entity (including a 83 | cross-claim or counterclaim in a lawsuit) alleging that the Work 84 | or a Contribution incorporated within the Work constitutes direct 85 | or contributory patent infringement, then any patent licenses 86 | granted to You under this License for that Work shall terminate 87 | as of the date such litigation is filed. 88 | 89 | 4. Redistribution. You may reproduce and distribute copies of the 90 | Work or Derivative Works thereof in any medium, with or without 91 | modifications, and in Source or Object form, provided that You 92 | meet the following conditions: 93 | 94 | (a) You must give any other recipients of the Work or 95 | Derivative Works a copy of this License; and 96 | 97 | (b) You must cause any modified files to carry prominent notices 98 | stating that You changed the files; and 99 | 100 | (c) You must retain, in the Source form of any Derivative Works 101 | that You distribute, all copyright, patent, trademark, and 102 | attribution notices from the Source form of the Work, 103 | excluding those notices that do not pertain to any part of 104 | the Derivative Works; and 105 | 106 | (d) If the Work includes a "NOTICE" text file as part of its 107 | distribution, then any Derivative Works that You distribute must 108 | include a readable copy of the attribution notices contained 109 | within such NOTICE file, excluding those notices that do not 110 | pertain to any part of the Derivative Works, in at least one 111 | of the following places: within a NOTICE text file distributed 112 | as part of the Derivative Works; within the Source form or 113 | documentation, if provided along with the Derivative Works; or, 114 | within a display generated by the Derivative Works, if and 115 | wherever such third-party notices normally appear. The contents 116 | of the NOTICE file are for informational purposes only and 117 | do not modify the License. You may add Your own attribution 118 | notices within Derivative Works that You distribute, alongside 119 | or as an addendum to the NOTICE text from the Work, provided 120 | that such additional attribution notices cannot be construed 121 | as modifying the License. 122 | 123 | You may add Your own copyright statement to Your modifications and 124 | may provide additional or different license terms and conditions 125 | for use, reproduction, or distribution of Your modifications, or 126 | for any such Derivative Works as a whole, provided Your use, 127 | reproduction, and distribution of the Work otherwise complies with 128 | the conditions stated in this License. 129 | 130 | 5. Submission of Contributions. Unless You explicitly state otherwise, 131 | any Contribution intentionally submitted for inclusion in the Work 132 | by You to the Licensor shall be under the terms and conditions of 133 | this License, without any additional terms or conditions. 134 | Notwithstanding the above, nothing herein shall supersede or modify 135 | the terms of any separate license agreement you may have executed 136 | with Licensor regarding such Contributions. 137 | 138 | 6. Trademarks. This License does not grant permission to use the trade 139 | names, trademarks, service marks, or product names of the Licensor, 140 | except as required for reasonable and customary use in describing the 141 | origin of the Work and reproducing the content of the NOTICE file. 142 | 143 | 7. Disclaimer of Warranty. Unless required by applicable law or 144 | agreed to in writing, Licensor provides the Work (and each 145 | Contributor provides its Contributions) on an "AS IS" BASIS, 146 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or 147 | implied, including, without limitation, any warranties or conditions 148 | of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A 149 | PARTICULAR PURPOSE. You are solely responsible for determining the 150 | appropriateness of using or redistributing the Work and assume any 151 | risks associated with Your exercise of permissions under this License. 152 | 153 | 8. Limitation of Liability. In no event and under no legal theory, 154 | whether in tort (including negligence), contract, or otherwise, 155 | unless required by applicable law (such as deliberate and grossly 156 | negligent acts) or agreed to in writing, shall any Contributor be 157 | liable to You for damages, including any direct, indirect, special, 158 | incidental, or consequential damages of any character arising as a 159 | result of this License or out of the use or inability to use the 160 | Work (including but not limited to damages for loss of goodwill, 161 | work stoppage, computer failure or malfunction, or any and all 162 | other commercial damages or losses), even if such Contributor 163 | has been advised of the possibility of such damages. 164 | 165 | 9. Accepting Warranty or Additional Liability. While redistributing 166 | the Work or Derivative Works thereof, You may choose to offer, 167 | and charge a fee for, acceptance of support, warranty, indemnity, 168 | or other liability obligations and/or rights consistent with this 169 | License. However, in accepting such obligations, You may act only 170 | on Your own behalf and on Your sole responsibility, not on behalf 171 | of any other Contributor, and only if You agree to indemnify, 172 | defend, and hold each Contributor harmless for any liability 173 | incurred by, or claims asserted against, such Contributor by reason 174 | of your accepting any such warranty or additional liability. 175 | 176 | END OF TERMS AND CONDITIONS 177 | 178 | APPENDIX: How to apply the Apache License to your work. 179 | 180 | To apply the Apache License to your work, attach the following 181 | boilerplate notice, with the fields enclosed by brackets "[]" 182 | replaced with your own identifying information. (Don't include 183 | the brackets!) The text should be enclosed in the appropriate 184 | comment syntax for the file format. We also recommend that a 185 | file or class name and description of purpose be included on the 186 | same "printed page" as the copyright notice for easier 187 | identification within third-party archives. 188 | 189 | Copyright 2021 uma-arai 190 | 191 | Licensed under the Apache License, Version 2.0 (the "License"); 192 | you may not use this file except in compliance with the License. 193 | You may obtain a copy of the License at 194 | 195 | http://www.apache.org/licenses/LICENSE-2.0 196 | 197 | Unless required by applicable law or agreed to in writing, software 198 | distributed under the License is distributed on an "AS IS" BASIS, 199 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 200 | See the License for the specific language governing permissions and 201 | limitations under the License. 202 | -------------------------------------------------------------------------------- /cloudformations/network_step1.yml: -------------------------------------------------------------------------------- 1 | AWSTemplateFormatVersion: "2010-09-09" 2 | Description: Network resource template part1 3 | Resources: 4 | # VPC 설정 5 | sbcntrVpc: 6 | Type: AWS::EC2::VPC 7 | Properties: 8 | CidrBlock: 10.0.0.0/16 9 | EnableDnsHostnames: true 10 | EnableDnsSupport: true 11 | InstanceTenancy: default 12 | Tags: 13 | - Key: Name 14 | Value: sbcntrVpc 15 | 16 | ############### Subnet, RouteTable, IGW ############### 17 | # 컨테이너 관련 설정 18 | ## 컨테이너 애플리케이션용 프라이빗 서브넷 19 | sbcntrSubnetPrivateContainer1A: 20 | Type: AWS::EC2::Subnet 21 | Properties: 22 | CidrBlock: 10.0.8.0/24 23 | VpcId: 24 | Ref: sbcntrVpc 25 | AvailabilityZone: 26 | Fn::Select: 27 | - 0 28 | - Fn::GetAZs: "" 29 | MapPublicIpOnLaunch: false 30 | Tags: 31 | - Key: Name 32 | Value: sbcntr-subnet-private-container-1a 33 | - Key: Type 34 | Value: Isolated 35 | sbcntrSubnetPrivateContainer1C: 36 | Type: AWS::EC2::Subnet 37 | Properties: 38 | CidrBlock: 10.0.9.0/24 39 | VpcId: 40 | Ref: sbcntrVpc 41 | AvailabilityZone: 42 | Fn::Select: 43 | - 1 44 | - Fn::GetAZs: "" 45 | MapPublicIpOnLaunch: false 46 | Tags: 47 | - Key: Name 48 | Value: sbcntr-subnet-private-container-1c 49 | - Key: Type 50 | Value: Isolated 51 | ## 컨테이너 애플리케이션용 라우팅 테이블 52 | sbcntrRouteApp: 53 | Type: AWS::EC2::RouteTable 54 | Properties: 55 | VpcId: 56 | Ref: sbcntrVpc 57 | Tags: 58 | - Key: Name 59 | Value: sbcntr-route-app 60 | ## 컨테이너 서브넷과 라우팅 연결 61 | sbcntrRouteAppAssociation1A: 62 | Type: AWS::EC2::SubnetRouteTableAssociation 63 | Properties: 64 | RouteTableId: 65 | Ref: sbcntrRouteApp 66 | SubnetId: 67 | Ref: sbcntrSubnetPrivateContainer1A 68 | sbcntrRouteAppAssociation1C: 69 | Type: AWS::EC2::SubnetRouteTableAssociation 70 | Properties: 71 | RouteTableId: 72 | Ref: sbcntrRouteApp 73 | SubnetId: 74 | Ref: sbcntrSubnetPrivateContainer1C 75 | 76 | # DB관련 설정 77 | ## DB용 프라이빗 서브넷 78 | sbcntrSubnetPrivateDb1A: 79 | Type: AWS::EC2::Subnet 80 | Properties: 81 | CidrBlock: 10.0.16.0/24 82 | VpcId: 83 | Ref: sbcntrVpc 84 | AvailabilityZone: 85 | Fn::Select: 86 | - 0 87 | - Fn::GetAZs: "" 88 | MapPublicIpOnLaunch: false 89 | Tags: 90 | - Key: Name 91 | Value: sbcntr-subnet-private-db-1a 92 | - Key: Type 93 | Value: Isolated 94 | sbcntrSubnetPrivateDb1C: 95 | Type: AWS::EC2::Subnet 96 | Properties: 97 | CidrBlock: 10.0.17.0/24 98 | VpcId: 99 | Ref: sbcntrVpc 100 | AvailabilityZone: 101 | Fn::Select: 102 | - 1 103 | - Fn::GetAZs: "" 104 | MapPublicIpOnLaunch: false 105 | Tags: 106 | - Key: Name 107 | Value: sbcntr-subnet-private-db-1c 108 | - Key: Type 109 | Value: Isolated 110 | ## DB용 라우팅 테이블 111 | sbcntrRouteDb: 112 | Type: AWS::EC2::RouteTable 113 | Properties: 114 | VpcId: 115 | Ref: sbcntrVpc 116 | Tags: 117 | - Key: Name 118 | Value: sbcntr-route-db 119 | ## DB 서브넷에 라우팅 연결 120 | sbcntrRouteDbAssociation1A: 121 | Type: AWS::EC2::SubnetRouteTableAssociation 122 | Properties: 123 | RouteTableId: 124 | Ref: sbcntrRouteDb 125 | SubnetId: 126 | Ref: sbcntrSubnetPrivateDb1A 127 | sbcntrRouteDbAssociation1C: 128 | Type: AWS::EC2::SubnetRouteTableAssociation 129 | Properties: 130 | RouteTableId: 131 | Ref: sbcntrRouteDb 132 | SubnetId: 133 | Ref: sbcntrSubnetPrivateDb1C 134 | 135 | # Ingress 관련 설정 136 | ## Ingress용 퍼블릭 서브넷 137 | sbcntrSubnetPublicIngress1A: 138 | Type: AWS::EC2::Subnet 139 | Properties: 140 | CidrBlock: 10.0.0.0/24 141 | VpcId: 142 | Ref: sbcntrVpc 143 | AvailabilityZone: 144 | Fn::Select: 145 | - 0 146 | - Fn::GetAZs: "" 147 | MapPublicIpOnLaunch: true 148 | Tags: 149 | - Key: Name 150 | Value: sbcntr-subnet-public-ingress-1a 151 | - Key: Type 152 | Value: Public 153 | sbcntrSubnetPublicIngress1C: 154 | Type: AWS::EC2::Subnet 155 | Properties: 156 | CidrBlock: 10.0.1.0/24 157 | VpcId: 158 | Ref: sbcntrVpc 159 | AvailabilityZone: 160 | Fn::Select: 161 | - 1 162 | - Fn::GetAZs: "" 163 | MapPublicIpOnLaunch: true 164 | Tags: 165 | - Key: Name 166 | Value: sbcntr-subnet-public-ingress-1c 167 | - Key: Type 168 | Value: Public 169 | ## Ingress용 라우팅 테이블 170 | sbcntrRouteIngress: 171 | Type: AWS::EC2::RouteTable 172 | Properties: 173 | VpcId: 174 | Ref: sbcntrVpc 175 | Tags: 176 | - Key: Name 177 | Value: sbcntr-route-ingress 178 | ## Ingress용 서브넷에 라우팅 연결 179 | sbcntrRouteIngressAssociation1A: 180 | Type: AWS::EC2::SubnetRouteTableAssociation 181 | Properties: 182 | RouteTableId: 183 | Ref: sbcntrRouteIngress 184 | SubnetId: 185 | Ref: sbcntrSubnetPublicIngress1A 186 | sbcntrRouteIngressAssociation1C: 187 | Type: AWS::EC2::SubnetRouteTableAssociation 188 | Properties: 189 | RouteTableId: 190 | Ref: sbcntrRouteIngress 191 | SubnetId: 192 | Ref: sbcntrSubnetPublicIngress1C 193 | ## Ingress용 라우팅 테이블의 기본 라우팅 194 | sbcntrRouteIngressDefault: 195 | Type: AWS::EC2::Route 196 | Properties: 197 | RouteTableId: 198 | Ref: sbcntrRouteIngress 199 | DestinationCidrBlock: 0.0.0.0/0 200 | GatewayId: 201 | Ref: sbcntrIgw 202 | DependsOn: 203 | - sbcntrVpcgwAttachment 204 | 205 | # 관리 서버 관련 설정 206 | ## 관리용 퍼블릭 서브넷 207 | sbcntrSubnetPublicManagement1A: 208 | Type: AWS::EC2::Subnet 209 | Properties: 210 | CidrBlock: 10.0.240.0/24 211 | VpcId: 212 | Ref: sbcntrVpc 213 | AvailabilityZone: 214 | Fn::Select: 215 | - 0 216 | - Fn::GetAZs: "" 217 | MapPublicIpOnLaunch: true 218 | Tags: 219 | - Key: Name 220 | Value: sbcntr-subnet-public-management-1a 221 | - Key: Type 222 | Value: Public 223 | sbcntrSubnetPublicManagement1C: 224 | Type: AWS::EC2::Subnet 225 | Properties: 226 | CidrBlock: 10.0.241.0/24 227 | VpcId: 228 | Ref: sbcntrVpc 229 | AvailabilityZone: 230 | Fn::Select: 231 | - 1 232 | - Fn::GetAZs: "" 233 | MapPublicIpOnLaunch: true 234 | Tags: 235 | - Key: Name 236 | Value: sbcntr-subnet-public-management-1c 237 | - Key: Type 238 | Value: Public 239 | ## 관리용 서브넷의 라우팅은 Ingress와 동일하게 생성 240 | sbcntrRouteManagementAssociation1A: 241 | Type: AWS::EC2::SubnetRouteTableAssociation 242 | Properties: 243 | RouteTableId: 244 | Ref: sbcntrRouteIngress 245 | SubnetId: 246 | Ref: sbcntrSubnetPublicManagement1A 247 | sbcntrRouteManagementAssociation1C: 248 | Type: AWS::EC2::SubnetRouteTableAssociation 249 | Properties: 250 | RouteTableId: 251 | Ref: sbcntrRouteIngress 252 | SubnetId: 253 | Ref: sbcntrSubnetPublicManagement1C 254 | 255 | # 인터넷 접속을 위한 게이트웨이 생성 256 | sbcntrIgw: 257 | Type: AWS::EC2::InternetGateway 258 | Properties: 259 | Tags: 260 | - Key: Name 261 | Value: sbcntr-igw 262 | sbcntrVpcgwAttachment: 263 | Type: AWS::EC2::VPCGatewayAttachment 264 | Properties: 265 | VpcId: 266 | Ref: sbcntrVpc 267 | InternetGatewayId: 268 | Ref: sbcntrIgw 269 | 270 | ############### Security groups ############### 271 | # 보안 그룹 생성 272 | ## 인터넷 공개용 보안 그룹 생성 273 | sbcntrSgIngress: 274 | Type: AWS::EC2::SecurityGroup 275 | Properties: 276 | GroupDescription: Security group for ingress 277 | GroupName: ingress 278 | SecurityGroupEgress: 279 | - CidrIp: 0.0.0.0/0 280 | Description: Allow all outbound traffic by default 281 | IpProtocol: "-1" 282 | SecurityGroupIngress: 283 | - CidrIp: 0.0.0.0/0 284 | Description: from 0.0.0.0/0:80 285 | FromPort: 80 286 | IpProtocol: tcp 287 | ToPort: 80 288 | - CidrIpv6: ::/0 289 | Description: from ::/0:80 290 | FromPort: 80 291 | IpProtocol: tcp 292 | ToPort: 80 293 | Tags: 294 | - Key: Name 295 | Value: sbcntr-sg-ingress 296 | VpcId: 297 | Ref: sbcntrVpc 298 | ## 관리 서버용 보안 그룹 생성 299 | sbcntrSgManagement: 300 | Type: AWS::EC2::SecurityGroup 301 | Properties: 302 | GroupDescription: Security Group of management server 303 | GroupName: management 304 | SecurityGroupEgress: 305 | - CidrIp: 0.0.0.0/0 306 | Description: Allow all outbound traffic by default 307 | IpProtocol: "-1" 308 | Tags: 309 | - Key: Name 310 | Value: sbcntr-sg-management 311 | VpcId: 312 | Ref: sbcntrVpc 313 | ## 백엔드 컨테이너 애플리케이션용 보안 그룹 생성 314 | sbcntrSgContainer: 315 | Type: AWS::EC2::SecurityGroup 316 | Properties: 317 | GroupDescription: Security Group of backend app 318 | GroupName: container 319 | SecurityGroupEgress: 320 | - CidrIp: 0.0.0.0/0 321 | Description: Allow all outbound traffic by default 322 | IpProtocol: "-1" 323 | Tags: 324 | - Key: Name 325 | Value: sbcntr-sg-container 326 | VpcId: 327 | Ref: sbcntrVpc 328 | ## 프론트엔드 컨테이너 애플리케이션용 보안 그룹 생성 329 | sbcntrSgFrontContainer: 330 | Type: AWS::EC2::SecurityGroup 331 | Properties: 332 | GroupDescription: Security Group of front container app 333 | GroupName: front-container 334 | SecurityGroupEgress: 335 | - CidrIp: 0.0.0.0/0 336 | Description: Allow all outbound traffic by default 337 | IpProtocol: "-1" 338 | Tags: 339 | - Key: Name 340 | Value: sbcntr-sg-front-container 341 | VpcId: 342 | Ref: sbcntrVpc 343 | ## 내부용 로드밸런서의 보안 그룹 생성 344 | sbcntrSgInternal: 345 | Type: AWS::EC2::SecurityGroup 346 | Properties: 347 | GroupDescription: Security group for internal load balancer 348 | GroupName: internal 349 | SecurityGroupEgress: 350 | - CidrIp: 0.0.0.0/0 351 | Description: Allow all outbound traffic by default 352 | IpProtocol: "-1" 353 | Tags: 354 | - Key: Name 355 | Value: sbcntr-sg-internal 356 | VpcId: 357 | Ref: sbcntrVpc 358 | ## DB용 보안 그룹 생성 359 | sbcntrSgDb: 360 | Type: AWS::EC2::SecurityGroup 361 | Properties: 362 | GroupDescription: Security Group of database 363 | GroupName: database 364 | SecurityGroupEgress: 365 | - CidrIp: 0.0.0.0/0 366 | Description: Allow all outbound traffic by default 367 | IpProtocol: "-1" 368 | Tags: 369 | - Key: Name 370 | Value: sbcntr-sg-db 371 | VpcId: 372 | Ref: sbcntrVpc 373 | 374 | # 역할 연결 375 | ## Internet LB -> Front Container 376 | sbcntrSgFrontContainerFromsSgIngress: 377 | Type: AWS::EC2::SecurityGroupIngress 378 | Properties: 379 | IpProtocol: tcp 380 | Description: HTTP for Ingress 381 | FromPort: 80 382 | GroupId: 383 | Fn::GetAtt: 384 | - sbcntrSgFrontContainer 385 | - GroupId 386 | SourceSecurityGroupId: 387 | Fn::GetAtt: 388 | - sbcntrSgIngress 389 | - GroupId 390 | ToPort: 80 391 | ## Front Container -> Internal LB 392 | sbcntrSgInternalFromSgFrontContainer: 393 | Type: AWS::EC2::SecurityGroupIngress 394 | Properties: 395 | IpProtocol: tcp 396 | Description: HTTP for front container 397 | FromPort: 80 398 | GroupId: 399 | Fn::GetAtt: 400 | - sbcntrSgInternal 401 | - GroupId 402 | SourceSecurityGroupId: 403 | Fn::GetAtt: 404 | - sbcntrSgFrontContainer 405 | - GroupId 406 | ToPort: 80 407 | ## Internal LB -> Back Container 408 | sbcntrSgContainerFromSgInternal: 409 | Type: AWS::EC2::SecurityGroupIngress 410 | Properties: 411 | IpProtocol: tcp 412 | Description: HTTP for internal lb 413 | FromPort: 80 414 | GroupId: 415 | Fn::GetAtt: 416 | - sbcntrSgContainer 417 | - GroupId 418 | SourceSecurityGroupId: 419 | Fn::GetAtt: 420 | - sbcntrSgInternal 421 | - GroupId 422 | ToPort: 80 423 | ## Back container -> DB 424 | sbcntrSgDbFromSgContainerTCP: 425 | Type: AWS::EC2::SecurityGroupIngress 426 | Properties: 427 | IpProtocol: tcp 428 | Description: MySQL protocol from backend App 429 | FromPort: 3306 430 | GroupId: 431 | Fn::GetAtt: 432 | - sbcntrSgDb 433 | - GroupId 434 | SourceSecurityGroupId: 435 | Fn::GetAtt: 436 | - sbcntrSgContainer 437 | - GroupId 438 | ToPort: 3306 439 | ## Front container -> DB 440 | sbcntrSgDbFromSgFrontContainerTCP: 441 | Type: AWS::EC2::SecurityGroupIngress 442 | Properties: 443 | IpProtocol: tcp 444 | Description: MySQL protocol from frontend App 445 | FromPort: 3306 446 | GroupId: 447 | Fn::GetAtt: 448 | - sbcntrSgDb 449 | - GroupId 450 | SourceSecurityGroupId: 451 | Fn::GetAtt: 452 | - sbcntrSgFrontContainer 453 | - GroupId 454 | ToPort: 3306 455 | ## Management server -> DB 456 | sbcntrSgDbFromSgManagementTCP: 457 | Type: AWS::EC2::SecurityGroupIngress 458 | Properties: 459 | IpProtocol: tcp 460 | Description: MySQL protocol from management server 461 | FromPort: 3306 462 | GroupId: 463 | Fn::GetAtt: 464 | - sbcntrSgDb 465 | - GroupId 466 | SourceSecurityGroupId: 467 | Fn::GetAtt: 468 | - sbcntrSgManagement 469 | - GroupId 470 | ToPort: 3306 471 | ## Management server -> Internal LB 472 | sbcntrSgInternalFromSgManagementTCP: 473 | Type: AWS::EC2::SecurityGroupIngress 474 | Properties: 475 | IpProtocol: tcp 476 | Description: HTTP for management server 477 | FromPort: 80 478 | GroupId: 479 | Fn::GetAtt: 480 | - sbcntrSgInternal 481 | - GroupId 482 | SourceSecurityGroupId: 483 | Fn::GetAtt: 484 | - sbcntrSgManagement 485 | - GroupId 486 | ToPort: 80 487 | -------------------------------------------------------------------------------- /cloudformations/network_step2.yml: -------------------------------------------------------------------------------- 1 | AWSTemplateFormatVersion: "2010-09-09" 2 | Description: Network resource template part1 3 | Resources: 4 | # VPC설정 5 | sbcntrVpc: 6 | Type: AWS::EC2::VPC 7 | Properties: 8 | CidrBlock: 10.0.0.0/16 9 | EnableDnsHostnames: true 10 | EnableDnsSupport: true 11 | InstanceTenancy: default 12 | Tags: 13 | - Key: Name 14 | Value: sbcntrVpc 15 | 16 | ############### Subnet, RouteTable, IGW ############### 17 | # 컨테이너 관련 설정 18 | ## 컨테이너 애플리케이션용 프라이빗 서브넷 19 | sbcntrSubnetPrivateContainer1A: 20 | Type: AWS::EC2::Subnet 21 | Properties: 22 | CidrBlock: 10.0.8.0/24 23 | VpcId: 24 | Ref: sbcntrVpc 25 | AvailabilityZone: 26 | Fn::Select: 27 | - 0 28 | - Fn::GetAZs: "" 29 | MapPublicIpOnLaunch: false 30 | Tags: 31 | - Key: Name 32 | Value: sbcntr-subnet-private-container-1a 33 | - Key: Type 34 | Value: Isolated 35 | sbcntrSubnetPrivateContainer1C: 36 | Type: AWS::EC2::Subnet 37 | Properties: 38 | CidrBlock: 10.0.9.0/24 39 | VpcId: 40 | Ref: sbcntrVpc 41 | AvailabilityZone: 42 | Fn::Select: 43 | - 1 44 | - Fn::GetAZs: "" 45 | MapPublicIpOnLaunch: false 46 | Tags: 47 | - Key: Name 48 | Value: sbcntr-subnet-private-container-1c 49 | - Key: Type 50 | Value: Isolated 51 | ## 컨테이너 애플리케이션용 라우팅 테이블 52 | sbcntrRouteApp: 53 | Type: AWS::EC2::RouteTable 54 | Properties: 55 | VpcId: 56 | Ref: sbcntrVpc 57 | Tags: 58 | - Key: Name 59 | Value: sbcntr-route-app 60 | ## 컨테이너 서브넷과 라우팅 연결 61 | sbcntrRouteAppAssociation1A: 62 | Type: AWS::EC2::SubnetRouteTableAssociation 63 | Properties: 64 | RouteTableId: 65 | Ref: sbcntrRouteApp 66 | SubnetId: 67 | Ref: sbcntrSubnetPrivateContainer1A 68 | sbcntrRouteAppAssociation1C: 69 | Type: AWS::EC2::SubnetRouteTableAssociation 70 | Properties: 71 | RouteTableId: 72 | Ref: sbcntrRouteApp 73 | SubnetId: 74 | Ref: sbcntrSubnetPrivateContainer1C 75 | 76 | # DB관련 설정 77 | ## DB용 프라이빗 서브넷 78 | sbcntrSubnetPrivateDb1A: 79 | Type: AWS::EC2::Subnet 80 | Properties: 81 | CidrBlock: 10.0.16.0/24 82 | VpcId: 83 | Ref: sbcntrVpc 84 | AvailabilityZone: 85 | Fn::Select: 86 | - 0 87 | - Fn::GetAZs: "" 88 | MapPublicIpOnLaunch: false 89 | Tags: 90 | - Key: Name 91 | Value: sbcntr-subnet-private-db-1a 92 | - Key: Type 93 | Value: Isolated 94 | sbcntrSubnetPrivateDb1C: 95 | Type: AWS::EC2::Subnet 96 | Properties: 97 | CidrBlock: 10.0.17.0/24 98 | VpcId: 99 | Ref: sbcntrVpc 100 | AvailabilityZone: 101 | Fn::Select: 102 | - 1 103 | - Fn::GetAZs: "" 104 | MapPublicIpOnLaunch: false 105 | Tags: 106 | - Key: Name 107 | Value: sbcntr-subnet-private-db-1c 108 | - Key: Type 109 | Value: Isolated 110 | ## DB용 라우팅 테이블 111 | sbcntrRouteDb: 112 | Type: AWS::EC2::RouteTable 113 | Properties: 114 | VpcId: 115 | Ref: sbcntrVpc 116 | Tags: 117 | - Key: Name 118 | Value: sbcntr-route-db 119 | ## DB 서브넷에 라우팅 연결 120 | sbcntrRouteDbAssociation1A: 121 | Type: AWS::EC2::SubnetRouteTableAssociation 122 | Properties: 123 | RouteTableId: 124 | Ref: sbcntrRouteDb 125 | SubnetId: 126 | Ref: sbcntrSubnetPrivateDb1A 127 | sbcntrRouteDbAssociation1C: 128 | Type: AWS::EC2::SubnetRouteTableAssociation 129 | Properties: 130 | RouteTableId: 131 | Ref: sbcntrRouteDb 132 | SubnetId: 133 | Ref: sbcntrSubnetPrivateDb1C 134 | 135 | # Ingress 관련 설정 136 | ## Ingress용 퍼블릭 서브넷 137 | sbcntrSubnetPublicIngress1A: 138 | Type: AWS::EC2::Subnet 139 | Properties: 140 | CidrBlock: 10.0.0.0/24 141 | VpcId: 142 | Ref: sbcntrVpc 143 | AvailabilityZone: 144 | Fn::Select: 145 | - 0 146 | - Fn::GetAZs: "" 147 | MapPublicIpOnLaunch: true 148 | Tags: 149 | - Key: Name 150 | Value: sbcntr-subnet-public-ingress-1a 151 | - Key: Type 152 | Value: Public 153 | sbcntrSubnetPublicIngress1C: 154 | Type: AWS::EC2::Subnet 155 | Properties: 156 | CidrBlock: 10.0.1.0/24 157 | VpcId: 158 | Ref: sbcntrVpc 159 | AvailabilityZone: 160 | Fn::Select: 161 | - 1 162 | - Fn::GetAZs: "" 163 | MapPublicIpOnLaunch: true 164 | Tags: 165 | - Key: Name 166 | Value: sbcntr-subnet-public-ingress-1c 167 | - Key: Type 168 | Value: Public 169 | ## Ingress용 라우팅 테이블 170 | sbcntrRouteIngress: 171 | Type: AWS::EC2::RouteTable 172 | Properties: 173 | VpcId: 174 | Ref: sbcntrVpc 175 | Tags: 176 | - Key: Name 177 | Value: sbcntr-route-ingress 178 | ## Ingress용 서브넷에 라우팅 연결 179 | sbcntrRouteIngressAssociation1A: 180 | Type: AWS::EC2::SubnetRouteTableAssociation 181 | Properties: 182 | RouteTableId: 183 | Ref: sbcntrRouteIngress 184 | SubnetId: 185 | Ref: sbcntrSubnetPublicIngress1A 186 | sbcntrRouteIngressAssociation1C: 187 | Type: AWS::EC2::SubnetRouteTableAssociation 188 | Properties: 189 | RouteTableId: 190 | Ref: sbcntrRouteIngress 191 | SubnetId: 192 | Ref: sbcntrSubnetPublicIngress1C 193 | ## Ingress용 라우팅 테이블의 기본 라우팅 194 | sbcntrRouteIngressDefault: 195 | Type: AWS::EC2::Route 196 | Properties: 197 | RouteTableId: 198 | Ref: sbcntrRouteIngress 199 | DestinationCidrBlock: 0.0.0.0/0 200 | GatewayId: 201 | Ref: sbcntrIgw 202 | DependsOn: 203 | - sbcntrVpcgwAttachment 204 | 205 | # 관리 서버 관련 설정 206 | ## 관리용 퍼블릭 서브넷 207 | sbcntrSubnetPublicManagement1A: 208 | Type: AWS::EC2::Subnet 209 | Properties: 210 | CidrBlock: 10.0.240.0/24 211 | VpcId: 212 | Ref: sbcntrVpc 213 | AvailabilityZone: 214 | Fn::Select: 215 | - 0 216 | - Fn::GetAZs: "" 217 | MapPublicIpOnLaunch: true 218 | Tags: 219 | - Key: Name 220 | Value: sbcntr-subnet-public-management-1a 221 | - Key: Type 222 | Value: Public 223 | sbcntrSubnetPublicManagement1C: 224 | Type: AWS::EC2::Subnet 225 | Properties: 226 | CidrBlock: 10.0.241.0/24 227 | VpcId: 228 | Ref: sbcntrVpc 229 | AvailabilityZone: 230 | Fn::Select: 231 | - 1 232 | - Fn::GetAZs: "" 233 | MapPublicIpOnLaunch: true 234 | Tags: 235 | - Key: Name 236 | Value: sbcntr-subnet-public-management-1c 237 | - Key: Type 238 | Value: Public 239 | ## 관리용 서브넷의 라우팅은 Ingress와 동일하게 생성 240 | sbcntrRouteManagementAssociation1A: 241 | Type: AWS::EC2::SubnetRouteTableAssociation 242 | Properties: 243 | RouteTableId: 244 | Ref: sbcntrRouteIngress 245 | SubnetId: 246 | Ref: sbcntrSubnetPublicManagement1A 247 | sbcntrRouteManagementAssociation1C: 248 | Type: AWS::EC2::SubnetRouteTableAssociation 249 | Properties: 250 | RouteTableId: 251 | Ref: sbcntrRouteIngress 252 | SubnetId: 253 | Ref: sbcntrSubnetPublicManagement1C 254 | 255 | # 인터넷 접속을 위한 게이트웨이 생성 256 | sbcntrIgw: 257 | Type: AWS::EC2::InternetGateway 258 | Properties: 259 | Tags: 260 | - Key: Name 261 | Value: sbcntr-igw 262 | sbcntrVpcgwAttachment: 263 | Type: AWS::EC2::VPCGatewayAttachment 264 | Properties: 265 | VpcId: 266 | Ref: sbcntrVpc 267 | InternetGatewayId: 268 | Ref: sbcntrIgw 269 | 270 | # VPC 엔드포인트 관련 설정 271 | ## VPC 엔드포인트(Egress통신)용 프라이빗 서브넷 272 | sbcntrSubnetPrivateEgress1A: 273 | Type: AWS::EC2::Subnet 274 | Properties: 275 | CidrBlock: 10.0.248.0/24 276 | VpcId: 277 | Ref: sbcntrVpc 278 | AvailabilityZone: 279 | Fn::Select: 280 | - 0 281 | - Fn::GetAZs: "" 282 | MapPublicIpOnLaunch: false 283 | Tags: 284 | - Key: Name 285 | Value: sbcntr-subnet-private-egress-1a 286 | - Key: Type 287 | Value: Isolated 288 | sbcntrSubnetPrivateEgress1C: 289 | Type: AWS::EC2::Subnet 290 | Properties: 291 | CidrBlock: 10.0.249.0/24 292 | VpcId: 293 | Ref: sbcntrVpc 294 | AvailabilityZone: 295 | Fn::Select: 296 | - 1 297 | - Fn::GetAZs: "" 298 | MapPublicIpOnLaunch: false 299 | Tags: 300 | - Key: Name 301 | Value: sbcntr-subnet-private-egress-1c 302 | - Key: Type 303 | Value: Isolated 304 | 305 | ############### Security groups ############### 306 | # 보안 그룹 생성 307 | ## 인터넷 공개용 보안 그룹 생성 308 | sbcntrSgIngress: 309 | Type: AWS::EC2::SecurityGroup 310 | Properties: 311 | GroupDescription: Security group for ingress 312 | GroupName: ingress 313 | SecurityGroupEgress: 314 | - CidrIp: 0.0.0.0/0 315 | Description: Allow all outbound traffic by default 316 | IpProtocol: "-1" 317 | SecurityGroupIngress: 318 | - CidrIp: 0.0.0.0/0 319 | Description: from 0.0.0.0/0:80 320 | FromPort: 80 321 | IpProtocol: tcp 322 | ToPort: 80 323 | - CidrIpv6: ::/0 324 | Description: from ::/0:80 325 | FromPort: 80 326 | IpProtocol: tcp 327 | ToPort: 80 328 | Tags: 329 | - Key: Name 330 | Value: sbcntr-sg-ingress 331 | VpcId: 332 | Ref: sbcntrVpc 333 | ## 관리 서버용 보안 그룹 생성 334 | sbcntrSgManagement: 335 | Type: AWS::EC2::SecurityGroup 336 | Properties: 337 | GroupDescription: Security Group of management server 338 | GroupName: management 339 | SecurityGroupEgress: 340 | - CidrIp: 0.0.0.0/0 341 | Description: Allow all outbound traffic by default 342 | IpProtocol: "-1" 343 | Tags: 344 | - Key: Name 345 | Value: sbcntr-sg-management 346 | VpcId: 347 | Ref: sbcntrVpc 348 | ## 백엔드 컨테이너 애플리케이션용 보안 그룹 생성 349 | sbcntrSgContainer: 350 | Type: AWS::EC2::SecurityGroup 351 | Properties: 352 | GroupDescription: Security Group of backend app 353 | GroupName: container 354 | SecurityGroupEgress: 355 | - CidrIp: 0.0.0.0/0 356 | Description: Allow all outbound traffic by default 357 | IpProtocol: "-1" 358 | Tags: 359 | - Key: Name 360 | Value: sbcntr-sg-container 361 | VpcId: 362 | Ref: sbcntrVpc 363 | ## 프론트엔드 컨테이너 애플리케이션용 보안 그룹 생성 364 | sbcntrSgFrontContainer: 365 | Type: AWS::EC2::SecurityGroup 366 | Properties: 367 | GroupDescription: Security Group of front container app 368 | GroupName: front-container 369 | SecurityGroupEgress: 370 | - CidrIp: 0.0.0.0/0 371 | Description: Allow all outbound traffic by default 372 | IpProtocol: "-1" 373 | Tags: 374 | - Key: Name 375 | Value: sbcntr-sg-front-container 376 | VpcId: 377 | Ref: sbcntrVpc 378 | ## 내부용 로드밸런서의 보안 그룹 생성 379 | sbcntrSgInternal: 380 | Type: AWS::EC2::SecurityGroup 381 | Properties: 382 | GroupDescription: Security group for internal load balancer 383 | GroupName: internal 384 | SecurityGroupEgress: 385 | - CidrIp: 0.0.0.0/0 386 | Description: Allow all outbound traffic by default 387 | IpProtocol: "-1" 388 | Tags: 389 | - Key: Name 390 | Value: sbcntr-sg-internal 391 | VpcId: 392 | Ref: sbcntrVpc 393 | ## DB용 보안 그룹 생성 394 | sbcntrSgDb: 395 | Type: AWS::EC2::SecurityGroup 396 | Properties: 397 | GroupDescription: Security Group of database 398 | GroupName: database 399 | SecurityGroupEgress: 400 | - CidrIp: 0.0.0.0/0 401 | Description: Allow all outbound traffic by default 402 | IpProtocol: "-1" 403 | Tags: 404 | - Key: Name 405 | Value: sbcntr-sg-db 406 | VpcId: 407 | Ref: sbcntrVpc 408 | ## VPC 엔드포인트용 보안 그룹 설정 409 | sbcntrSgEgress: 410 | Type: AWS::EC2::SecurityGroup 411 | Properties: 412 | GroupDescription: Security Group of VPC Endpoint 413 | GroupName: egress 414 | SecurityGroupEgress: 415 | - CidrIp: 0.0.0.0/0 416 | Description: Allow all outbound traffic by default 417 | IpProtocol: "-1" 418 | Tags: 419 | - Key: Name 420 | Value: sbcntr-sg-vpce 421 | VpcId: 422 | Ref: sbcntrVpc 423 | 424 | # 역할 연결 425 | ## Internet LB -> Front Container 426 | sbcntrSgFrontContainerFromsSgIngress: 427 | Type: AWS::EC2::SecurityGroupIngress 428 | Properties: 429 | IpProtocol: tcp 430 | Description: HTTP for Ingress 431 | FromPort: 80 432 | GroupId: 433 | Fn::GetAtt: 434 | - sbcntrSgFrontContainer 435 | - GroupId 436 | SourceSecurityGroupId: 437 | Fn::GetAtt: 438 | - sbcntrSgIngress 439 | - GroupId 440 | ToPort: 80 441 | ## Front Container -> Internal LB 442 | sbcntrSgInternalFromSgFrontContainer: 443 | Type: AWS::EC2::SecurityGroupIngress 444 | Properties: 445 | IpProtocol: tcp 446 | Description: HTTP for front container 447 | FromPort: 80 448 | GroupId: 449 | Fn::GetAtt: 450 | - sbcntrSgInternal 451 | - GroupId 452 | SourceSecurityGroupId: 453 | Fn::GetAtt: 454 | - sbcntrSgFrontContainer 455 | - GroupId 456 | ToPort: 80 457 | ## Internal LB -> Back Container 458 | sbcntrSgContainerFromSgInternal: 459 | Type: AWS::EC2::SecurityGroupIngress 460 | Properties: 461 | IpProtocol: tcp 462 | Description: HTTP for internal lb 463 | FromPort: 80 464 | GroupId: 465 | Fn::GetAtt: 466 | - sbcntrSgContainer 467 | - GroupId 468 | SourceSecurityGroupId: 469 | Fn::GetAtt: 470 | - sbcntrSgInternal 471 | - GroupId 472 | ToPort: 80 473 | ## Back container -> DB 474 | sbcntrSgDbFromSgContainerTCP: 475 | Type: AWS::EC2::SecurityGroupIngress 476 | Properties: 477 | IpProtocol: tcp 478 | Description: MySQL protocol from backend App 479 | FromPort: 3306 480 | GroupId: 481 | Fn::GetAtt: 482 | - sbcntrSgDb 483 | - GroupId 484 | SourceSecurityGroupId: 485 | Fn::GetAtt: 486 | - sbcntrSgContainer 487 | - GroupId 488 | ToPort: 3306 489 | ## Front container -> DB 490 | sbcntrSgDbFromSgFrontContainerTCP: 491 | Type: AWS::EC2::SecurityGroupIngress 492 | Properties: 493 | IpProtocol: tcp 494 | Description: MySQL protocol from frontend App 495 | FromPort: 3306 496 | GroupId: 497 | Fn::GetAtt: 498 | - sbcntrSgDb 499 | - GroupId 500 | SourceSecurityGroupId: 501 | Fn::GetAtt: 502 | - sbcntrSgFrontContainer 503 | - GroupId 504 | ToPort: 3306 505 | ## Management server -> DB 506 | sbcntrSgDbFromSgManagementTCP: 507 | Type: AWS::EC2::SecurityGroupIngress 508 | Properties: 509 | IpProtocol: tcp 510 | Description: MySQL protocol from management server 511 | FromPort: 3306 512 | GroupId: 513 | Fn::GetAtt: 514 | - sbcntrSgDb 515 | - GroupId 516 | SourceSecurityGroupId: 517 | Fn::GetAtt: 518 | - sbcntrSgManagement 519 | - GroupId 520 | ToPort: 3306 521 | ## Management server -> Internal LB 522 | sbcntrSgInternalFromSgManagementTCP: 523 | Type: AWS::EC2::SecurityGroupIngress 524 | Properties: 525 | IpProtocol: tcp 526 | Description: HTTP for management server 527 | FromPort: 80 528 | GroupId: 529 | Fn::GetAtt: 530 | - sbcntrSgInternal 531 | - GroupId 532 | SourceSecurityGroupId: 533 | Fn::GetAtt: 534 | - sbcntrSgManagement 535 | - GroupId 536 | ToPort: 80 537 | ### Back container -> VPC endpoint 538 | sbcntrSgVpceFromSgContainerTCP: 539 | Type: AWS::EC2::SecurityGroupIngress 540 | Properties: 541 | IpProtocol: tcp 542 | Description: HTTPS for Container App 543 | FromPort: 443 544 | GroupId: 545 | Fn::GetAtt: 546 | - sbcntrSgEgress 547 | - GroupId 548 | SourceSecurityGroupId: 549 | Fn::GetAtt: 550 | - sbcntrSgContainer 551 | - GroupId 552 | ToPort: 443 553 | ### Front container -> VPC endpoint 554 | sbcntrSgVpceFromSgFrontContainerTCP: 555 | Type: AWS::EC2::SecurityGroupIngress 556 | Properties: 557 | IpProtocol: tcp 558 | Description: HTTPS for Front Container App 559 | FromPort: 443 560 | GroupId: 561 | Fn::GetAtt: 562 | - sbcntrSgEgress 563 | - GroupId 564 | SourceSecurityGroupId: 565 | Fn::GetAtt: 566 | - sbcntrSgFrontContainer 567 | - GroupId 568 | ToPort: 443 569 | ### Management Server -> VPC endpoint 570 | sbcntrSgVpceFromSgManagementTCP: 571 | Type: AWS::EC2::SecurityGroupIngress 572 | Properties: 573 | IpProtocol: tcp 574 | Description: HTTPS for management server 575 | FromPort: 443 576 | GroupId: 577 | Fn::GetAtt: 578 | - sbcntrSgEgress 579 | - GroupId 580 | SourceSecurityGroupId: 581 | Fn::GetAtt: 582 | - sbcntrSgManagement 583 | - GroupId 584 | ToPort: 443 --------------------------------------------------------------------------------