AHSS-1주차 [AWS Hacking & Security Study 1기 Study]

* cloudNet@ 팀의 가시다 님이 진행하는 AWS Hacking & Security Study 스터디 입니다.

환경 구성

  • 자기증명이 된 PC와 자기증명이 안된 EC2로 실습합니다.
  • 실습 환경 (VPC, Public Subnet, EC2) – SSH Keypair 필요 : AWS CloudFormation 스택 배포 – 링크 클릭 후 생성 ⇒ 배포 후 EC2 Public IP로 접속 (ec2-user)
  • KeyNeame만 사용하시는 Key 설정 후 다음 눌러서 스택 생성 합니다.
  • 완료 후 출력 부분 클릭하면 IP 나오며 해당 IP를 접속하며 실습을 하겠습니다 (EC2 탭으로 가서 확인 가능합니다.)

S3 취약점

  1. 객체 & 버킷 액세스 제어 목록 ACL : 액세스 제어 목록(ACL)을 사용하여 버킷 및 객체 각각에 대한 액세스를 제어할 수 있습니다 ← 사용 비권장 함 , 이유는: 개체별 acl은 관리가 안되서
  2. 버킷 정책 : 버킷 정책은 S3 작업, 요청자, 리소스 및 요청의 여러 측면(예: IP 주소)를 비롯한 다양한 조건을 기반으로 버킷 및 객체에 대한 중앙 집중식 액세스 제어를 제공
    • 정책은 액세스 정책 언어로 표현되며 중앙 집중식 권한 관리를 가능하게 합니다. 버킷에 연결되는 권한은 해당 버킷의 모든 객체에 적용됩니다.
    • 개별 객체에 대해서만 권한을 추가(부여) 할 수 있는 액세스 제어 목록과 달리, 정책은 버킷 내 모든 객체 또는 객체의 하위 세트에 대해 권한을 추가 또는 거부할 수 있습니다.
    • 또한 버킷에 포함된 임의 개수의 객체에 대한 권한을 설정 할 수도 있습니다.
    • 버킷 소유자만 정책을 버킷에 연결할 수 있습니다. 액세스 정책 언어로 작성되는 정책은 다음을 기반으로 요청을 허용 또는 거부 합니다.
      • S3 버킷 작업(예. PUT ?acl) 및 객체 작업(예: PUT Object 또는 GET Object)
      • 요청차
      • 정책에 지정된 조건
    • 계정은 GetObjectGetObjectVersionDeleteObject 또는 DeleteBucket과 같은 특정 Amazon S3 작업을 기반으로 액세스를 제어할 수 있습니다.
    • 조건은 IP 주소, IP 주소 범위(CIDR 표기법 사용), 날짜, 사용자 에이전트, HTTP 참조자 및 전송(HTTP 및 HTTPS) 등이 될 수 있습니다.
  3. IAM 정책 : IAM 을 사용하여 S3 리소스에 대한 액세스를 관리할 수 있습니다.

flaws.cloud

[EC2] nmap 도메인 조회


# -A: OS 감지, 버전 감지, 스크립트 실행 및 traceroute 정보를 활성화
# -Pn: 호스트가 살아있음을 가정하고 핑 스캔을 건너 뜁니다.
nmap -A flaws.cloud -Pn
Starting Nmap 6.40 ( http://nmap.org ) at 2023-08-28 15:43 UTC
Nmap scan report for flaws.cloud (52.218.209.35)
Host is up (0.12s latency).
Other addresses for flaws.cloud (not scanned): 52.218.248.123 52.92.145.59 52.92.160.219 52.92.193.99 52.92.209.51 52.92.227.35 52.218.183.51
rDNS record for 52.218.209.35: s3-website-us-west-2.amazonaws.com   <- 해당 부분을 통하여 S3를 이용했다는 것을 알 수 있습니다.
Not shown: 999 filtered ports
PORT   STATE SERVICE VERSION
80/tcp open  http    Amazon S3 httpd
|_http-methods: No Allow or Public header in OPTIONS response (status code 400)
| http-robots.txt: 1 disallowed entry
|_/
|_http-title: flAWS

Service detection performed. Please report any incorrect results at http://nmap.org/submit/ .
Nmap done: 1 IP address (1 host up) scanned in 19.38 seconds

[EC2] 버킷 탐색

# aws cli 설치된 상태 + IAM 자격증명 설정 없는 상태
aws s3 ls s3://flaws.cloud
Unable to locate credentials. You can configure credentials by running "aws configure".

# aws cli 설치된 상태 + IAM 자격증명 설정 없는 상태 >> 출력 결과가 나오는 이유가 무엇인가?

# --no-sign-request: 이 옵션은 AWS 서명 요청 없이 익명으로 S3 서비스에 액세스하도록 합니다. 
    이 옵션을 사용하면, AWS 계정 자격 증명 없이도 퍼블릭으로 공개된 S3 버킷의 내용을 볼 수 있습니다.
# --recursive: 이 옵션은 지정된 경로 안에 있는 모든 파일과 하위 디렉터리를 나열합니다. 이 옵션이 없으면, 최상위 디렉터리만 보여줍니다.
# --human-readable: 파일 크기를 사람이 읽기 쉬운 형태(예: KiB, MiB 등)로 출력합니다.
# --summarize: 전체 개요(총 객체 수, 총 크기 등)를 마지막에 출력합니다.
aws s3 ls s3://flaws.cloud --no-sign-request --recursive --human-readable --summarize
2017-03-14 03:00:38    2.5 KiB hint1.html
2017-03-03 04:05:17    1.7 KiB hint2.html
2017-03-03 04:05:11    1.1 KiB hint3.html
2020-05-22 18:16:45    3.1 KiB index.html
2018-07-10 16:47:16   15.6 KiB logo.png
2017-02-27 01:59:28   46 Bytes robots.txt
2017-02-27 01:59:30    1.0 KiB secret-dd02c7c.html
Total Objects: 7
   Total Size: 25.0 KiB
 
# 객체 다운로드 >> 다운로드가 되는 이유가 무엇인가?
aws s3 cp s3://flaws.cloud/secret-dd02c7c.html . --no-sign-request

# 파일 내용 확인
file secret-dd02c7c.html
cat secret-dd02c7c.html ; echo

#텍스트 브라우저로 확인 
lynx secret-dd02c7c.html

# (옵션) 출력 결과의 링크 정보 확인 후 Level2 풀어 보자!
# Level2 는 해당 옵션으로 안된다.
aws s3 ls s3://level2-c8b217a33fcf1f839f6f1f73a00a9ae7.flaws.cloud --no-sign-request

아래의 실습을 통하여 직접 레벨1,2 실습을 만들어 봅니다.

S3 권한 설정 실습 & IAM Access Analyzer

  1. [AWS 콘솔] AWS S3 버킷 생성 : 서울 리전
    • (옵션) AWS CLI로 실행 : IAM 자격증명 설정 되어 있는 상태 ← AWS CloudShell에서 사용 가능(로그인한 사용자 인증 처리가 됩니다.)
# S3 버킷 생성
#aws s3 mb s3://버킷(유일한 이름) --region ap-northeast-2
NICKNAME=<자신의닉네임>
NICKNAME=sminho
aws s3 mb s3://ahss-$NICKNAME --region ap-northeast-2

# S3 버킷 조회
aws s3 ls
aws s3api get-public-access-block --bucket ahss-$NICKNAME
==
{
    "PublicAccessBlockConfiguration": {
        "BlockPublicAcls": true,
        "IgnorePublicAcls": true,
        "BlockPublicPolicy": true,
        "RestrictPublicBuckets": true
    }
}
==
  • 생성된 퍼블릭 액세스 차단 기본 설정 확인
aws s3api get-public-access-block --bucket ahss-$NICKNAME | jq
{
  "PublicAccessBlockConfiguration": {
    "BlockPublicAcls": true,
    "IgnorePublicAcls": true,
    "BlockPublicPolicy": true,
    "RestrictPublicBuckets": true
  }
}
#아래의 이미지에서 각 줄이랑 매칭 됩니다.

2. [AWS 콘솔] 퍼블릭 액세스 차단 편집 : (Uncheck) 모든 퍼블릭 액세스 차단 → ‘변경 사항 저장’ 클릭 ⇒ ‘확인’ 입력

aws s3api get-public-access-block --bucket ahss-$NICKNAME
{
    "PublicAccessBlockConfiguration": {
        "BlockPublicAcls": false,
        "IgnorePublicAcls": false,
        "BlockPublicPolicy": false,
        "RestrictPublicBuckets": false
    }
}

3. [AWS 콘솔] 버킷에 텍스트 파일 3개 객체 파일 업로드

  • (옵션) AWS CLI로 실행 : IAM 자격증명 설정 되어 있는 상태
# 파일 생성
echo "memo1" > memo1.txt
echo "memo2" > memo2.txt
echo "memo3" > memo3.txt

# S3로 업로드
aws s3 cp memo1.txt s3://ahss-$NICKNAME
aws s3 cp memo2.txt s3://ahss-$NICKNAME
aws s3 cp memo3.txt s3://ahss-$NICKNAME

# 파일 확인
aws s3 ls s3://ahss-$NICKNAME --recursive --human-readable --summarize
===
2023-08-29 01:18:03    6 Bytes memo1.txt
2023-08-29 01:18:05    6 Bytes memo2.txt
2023-08-29 01:18:07    6 Bytes memo3.txt

Total Objects: 3
   Total Size: 18 Bytes
===
aws s3api list-objects --bucket ahss-$NICKNAME | jq
=======
{
  "Contents": [
    {
      "Key": "memo1.txt",
      "LastModified": "2023-08-28T16:18:03+00:00",
      "ETag": "\"e32fc8d8ec1c393cd8c8c384db18f8b8\"",
      "Size": 6,
      "StorageClass": "STANDARD",
      "Owner": {
        "ID": "d9a4415902c867d85aaf7bae074134a216919f6dab0d6f9089f845d1d003afa4"
      }
    },
    {
      "Key": "memo2.txt",
      "LastModified": "2023-08-28T16:18:05+00:00",
      "ETag": "\"aa4e7f68a7f12dee6ec03c4c0e6b5e02\"",
      "Size": 6,
      "StorageClass": "STANDARD",
      "Owner": {
        "ID": "d9a4415902c867d85aaf7bae074134a216919f6dab0d6f9089f845d1d003afa4"
      }
    },
    {
      "Key": "memo3.txt",
      "LastModified": "2023-08-28T16:18:07+00:00",
      "ETag": "\"3efcb16932fe5b4e308ba7954f8f812f\"",
      "Size": 6,
      "StorageClass": "STANDARD",
      "Owner": {
        "ID": "d9a4415902c867d85aaf7bae074134a216919f6dab0d6f9089f845d1d003afa4"
      }
    }
  ],
  "RequestCharged": null
}
========
  • [AWS 콘솔] 객체 URL 주소 확인해보자! → 버킷 액세스 방식 확인 : 가상 호스팅 방식, S3 액세스 포인트, S3://를 사용
    • 가상 호스팅 방식 : https://bucket-name.s3.Region.amazonaws.com/key-name

4. [EC2] 자신의 버킷 탐색 (자격증명 X)

# 출력 결과의 원인을 유추해보자!
NICKNAME=<자신의닉네임>
NICKNAME=sminho
aws s3 ls s3://ahss-$NICKNAME --human-readable
aws s3 ls s3://ahss-$NICKNAME --human-readable --no-sign-request
==
	#error 문구가 좀 다르게 나옵니다 아래의 설정을 통하여 레벨 1 맞춰 봅니다.
An error occurred (AccessDenied) when calling the ListObjectsV2 operation: Access Denied
==

5. [AWS 콘솔] 권한 → 객체 소유권 편집 : ‘ACL 활성화’ , ‘버킷 소유자 선호’

6. [AWS 콘솔] 권한 → ACL(액세스 제어 목록) 편집 : 모든사람(퍼블릭 액세스) – 객체 (Check 나열) → ‘변경 사항 저장’

ㄴ퍼블릭 확인 합니다.

1. 다시 명령어 입력 [EC2] 자신의 버킷 탐색

# 탐색 실행
#레벨 1 이랑 같은 결과 확인 => 모든 사람 나열 승인!
aws s3 ls s3://ahss-$NICKNAME --human-readable --no-sign-request
==
2023-08-28 16:18:03    6 Bytes memo1.txt
2023-08-28 16:18:05    6 Bytes memo2.txt
2023-08-28 16:18:07    6 Bytes memo3.txt
==

# 파일 복사 실행 : 출력 결과의 원인을 유추해보자!
aws s3 cp s3://ahss-$NICKNAME/memo1.txt . --no-sign-request
==
fatal error: An error occurred (403) when calling the HeadObject operation: Forbidden
==

2. [AWS 콘솔] 객체 별 권한 설정

  • memo1.txt : 모든사람(퍼블릭 액세스) – 객체 (Check 읽기) → ‘변경 사항 저장’
  • memo2.txt : 인증된 사용자 그룹(AWS 계정이 있는 모든 사용자) – 객체 (Check 읽기) → ‘변경 사항 저장’

3. [자신의 PC] IAM 자격증명 설정 되어 있는 상태 – 버킷에 객체 복사

# 자격증명이 되어 있어서 원래가능
aws s3 cp s3://ahss-$NICKNAME/memo2.txt . 

# flaws.cloud Level2
# 내 버킷이 아닌대도 나오는 이유는 유효한 크레덴셜이면 누구나 가능합니다. (=aws configure 설정만 되면)
aws s3 ls s3://level2-c8b217a33fcf1f839f6f1f73a00a9ae7.flaws.cloud --human-readable
aws s3 cp s3://level2-c8b217a33fcf1f839f6f1f73a00a9ae7.flaws.cloud/secret-e4443fc.html .
cat secret-e4443fc.html

4. [AWS 콘솔] 리소스 정책 : 버킷 정책 설정 – 편집 클릭 후 아래 내용 입력 후 ‘변경 사항 저장’ (사용 시 주석 제거)

{
    "Version": "2012-10-17",
    "Statement": [
        {
           "Sid": "PublicReadGetObject",  // 정책 문장의 식별자입니다. 이는 선택 사항이며, 관리 목적으로 사용됩니다.
"Effect": "Allow",  // 이 정책 문장이 허용되는지("Allow") 아니면 거부되는지("Deny")를 나타냅니다.
"Principal": "*",  // 이 정책 문장이 적용되는 주체를 나타냅니다. "*"은 모든 사용자를 의미합니다.
"Action": "s3:GetObject",  // 해당 권한에서 허용하거나 거부하는 작업을 나타냅니다. 여기서는 S3 객체를 가져오는(GetObject) 작업을 의미합니다.
"Resource": "arn:aws:s3:::ahss-닉네임/*"  // 이 정책 문장이 적용되는 리소스를 나타냅니다. 여기서는 'ahss-닉네임'라는 이름의 모든 S3 객체(*로 지정됨)가 해당됩니다.
        }
    ]
}
  • 설정 후 aws cli 로 S3 버킷 정책 확인
aws s3api get-bucket-policy --bucket ahss-$NICKNAME | jq -r .Policy | jq
==
{
  "Version": "2012-10-17",
  "Statement": [
    {
      "Sid": "PublicReadGetObject",
      "Effect": "Allow",
      "Principal": "*",
      "Action": "s3:GetObject",
      "Resource": "arn:aws:s3:::ahss-sminho/*"
    }
  ]
}
==

5. [EC2] 자신의 버킷 탐색 → 아래와 같은 (리소스 정책) 버킷 정책은 언제 필요할까?

# 파일 복사 실행 : 출력 결과의 원인을 유추해보자!
aws s3 cp s3://ahss-$NICKNAME/memo1.txt . --no-sign-request
==
download: s3://ahss-sminho/memo1.txt to ./memo1.txt
==

# 파일 복사 실행 : 출력 결과의 원인을 유추해보자!
aws s3 cp s3://ahss-$NICKNAME/memo2.txt . --no-sign-request
==
download: s3://ahss-sminho/memo2.txt to ./memo2.txt
==

# 파일 복사 실행 : 출력 결과의 원인을 유추해보자!
aws s3 cp s3://ahss-$NICKNAME/memo3.txt . --no-sign-request
==
download: s3://ahss-sminho/memo3.txt to ./memo3.txt
==

S3의 객체 ACL을 활성화하는 사례 요약 – 링크

IAM Access Analyzer 액세스 분석기

# 액세스 분석기 생성
# 자격증명 필요
#aws accessanalyzer create-analyzer --analyzer-name firstanalyzer --type ACCOUNT --output text --query arn
ANA_ARN=$(aws accessanalyzer create-analyzer --analyzer-name firstanalyzer --type ACCOUNT --output text --query arn)
echo $ANA_ARN
==
arn:aws:access-analyzer:ap-northeast-2:276281595736:analyzer/firstanalyzer
==

# S3 버킷 스캔 수행
# 기본적으로 자동으로 스캔 합니다.
aws accessanalyzer start-resource-scan --analyzer-arn $ANA_ARN --resource-arn arn:aws:s3:::ahss-$NICKNAME

# S3 버킷 스캔 결과 확인
aws accessanalyzer get-analyzed-resource --analyzer-arn $ANA_ARN --resource-arn arn:aws:s3:::ahss-$NICKNAME | jq
{
  "resource": {
    "resourceArn": "arn:aws:s3:::ahss-sminho",
    "resourceType": "AWS::S3::Bucket",
    "createdAt": "2023-08-28T17:05:46.790000+00:00",
    "analyzedAt": "2023-08-28T17:07:57.535000+00:00",
    "updatedAt": "2023-08-28T17:05:46.790000+00:00",
    "isPublic": true,
    "actions": [
      "s3:GetObject",
      "s3:ListBucket",
      "s3:ListBucketMultipartUploads",
      "s3:ListBucketVersions"
    ],
    "sharedVia": [
      "BUCKET_ACL",
      "POLICY"
    ],
    "status": "ACTIVE",
    "resourceOwnerAccount": "2.."
  }
}
  • 콘솔에서 [AWS 콘솔] IAM – IAM – 액세스 보고서 – 액세스 분석기 에서 확인 가능 합니다.
  • 버킷에 대한 퍼블릭 액세스 차단 설정
aws s3api put-public-access-block --bucket ahss-$NICKNAME --public-access-block-configuration \
"BlockPublicAcls=true,IgnorePublicAcls=true,BlockPublicPolicy=true,RestrictPublicBuckets=true"
  • 실습 완료 후 액세스 분석기 삭제하여 줍니다.
aws accessanalyzer delete-analyzer  --analyzer-name firstanalyzer
  • 버킷 삭제
# 버킷에 객체 모두 삭제
aws s3 rm s3://ahss-$NICKNAME --recursive

# 실습에 사용한 S3 버킷 삭제
aws s3 rb s3://ahss-$NICKNAME

# 확인
aws s3 ls

S3 보안 강화

S3 기능

Pre-signed URL & 버킷 생성 : 서명된 URL(만료 날짜)로 AWS 보안자격증명이나 권한이 없어도, 객체 업로드/다운로드 가능

  • [자신의 PC] IAM 자격증명 설정 되어 있는 상태
# S3 버킷 생성
NICKNAME=<자신의닉네임>
NICKNAME=sminho
aws s3 mb s3://ahss-$NICKNAME-presign --region ap-northeast-2

# 확인
aws s3 ls
==
2023-08-30 00:23:21 ahss-sminho-presign
2023-07-09 23:32:30 aws-waf-logs-minho
2023-06-28 20:36:00 elasticbeanstalk-ap-northeast-2-373523363156
2023-05-27 23:22:32 minho-wp-bucket
==
aws s3api get-public-access-block --bucket ahss-$NICKNAME-presign | jq
==
{
  "PublicAccessBlockConfiguration": {
    "BlockPublicAcls": true,
    "IgnorePublicAcls": true,
    "BlockPublicPolicy": true,
    "RestrictPublicBuckets": true
  }
}
==

# 그림파일 다운로드
curl https://www.nasa.gov/sites/default/files/thumbnails/image/main_image_star-forming_region_carina_nircam_final-5mb.jpg -o jameswebb.jpg

# S3로 업로드
aws s3 cp jameswebb.jpg s3://ahss-$NICKNAME-presign

# 파일 확인
aws s3 ls s3://ahss-$NICKNAME-presign --human-readable
==
2023-08-30 00:25:14    5.1 MiB jameswebb.jpg
==

aws s3api list-objects --bucket ahss-$NICKNAME-presign | jq
==
{
  "Contents": [
    {
      "Key": "jameswebb.jpg",
      "LastModified": "2023-08-29T15:25:14+00:00",
      "ETag": "\"3bae2c6845352e627516a529fd507ffb\"",
      "Size": 5310371,
      "StorageClass": "STANDARD",
      "Owner": {
        "ID": "78d3a894fc40d80020c8ff7ba28dbeeedc5acb79eb2305a78af4f740b3b87f96"
      }
    }
  ],
  "RequestCharged": null
}
==
  • [EC2] 자격증명 없는 상태
#
NICKNAME=<자신의닉네임>
NICKNAME=ssminho
aws s3 ls s3://ahss-$NICKNAME-presign --human-readable --no-sign-request
==
An error occurred (AccessDenied) when calling the ListObjectsV2 operation: Access Denied
==

# 객체URL로 웹 접근 시도
lynx --dump https://ahss-$NICKNAME-presign.s3.ap-northeast-2.amazonaws.com/jameswebb.jpg
==
AccessDeniedAccess
   DeniedVCB5AKNXD6X213PTkKXVCxaHOBYmStnBNsOTF1xuXkPBt63mo5VvUC3IrJ7d8Chj1
   9isulj9A42tECElxDQNqEkhquU=
==
  • [자신의 PC] IAM 자격증명 설정 되어 있는 상태
# 사전 서명된 URL 생성 : 600초(10분)
aws s3 presign s3://ahss-$NICKNAME-presign/jameswebb.jpg --expires-in 600
https://cass-s3bucket4-gasida.s3.ap-northeast-2.amazonaws.com/jameswebb.jpg
  • [EC2] 자격증명 없는 상태
# 변수 지정
URL='<서명된 URL>'
URL='https://ahss-gasida-presign.s3.ap-northeast-2.amazonaws.com/memo1.txt

# 서명된 URL 접속 확인
curl -O $URL
ls -al *.jpg
==
-rw-rw-r-- 1 ec2-user ec2-user 5310371 Aug 29 15:29 jameswebb.jpg
==
  • 서명된 URL 주소를 10분 이내에 아무 단말/PC의 웹 브라우저에서 접속 가능합니다.

AWS Workshop S3 Security Best Pratices & Configuring Amazon S3 security settings and access controls

Require HTTPS

  • [자신의 PC] IAM 자격증명 설정 되어 있는 상태
# object's metadata 정보 확인 : ServerSideEncryption 확인
aws s3api head-object help
aws s3api head-object --bucket ahss-$NICKNAME-presign --key jameswebb.jpg | jq
==
{
  "AcceptRanges": "bytes",
  "LastModified": "2023-08-29T16:03:22+00:00",
  "ContentLength": 5310371,
  "ETag": "\"3bae2c6845352e627516a529fd507ffb\"",
  "ContentType": "image/jpeg",
  "ServerSideEncryption": "AES256",  # 기본적으로 암호화 버킷이 설정됨을 확인 
  "Metadata": {}
}
==

# object's metadata 정보 확인 : endpoint-url 옵션 설정
aws s3api head-object --bucket ahss-$NICKNAME-presign --key jameswebb.jpg --endpoint-url http://s3.ap-northeast-2.amazonaws.com
aws s3api head-object --bucket ahss-$NICKNAME-presign --key jameswebb.jpg --endpoint-url https://s3.ap-northeast-2.amazonaws.com
  • [AWS 콘솔] 버킷 정책 설정 – 편집 클릭 후 아래 내용 입력 후 ‘변경 사항 저장’ (강제로 )
{
	"Id": "S3-Security-Deny-unless-HTTPS",
	"Version": "2012-10-17",
	"Statement": [{
		"Action": "s3:*",
		"Effect": "Deny",
		"Principal": "*",
		"Resource": "arn:aws:s3:::ahss-닉네임-presign/*",
		"Condition": {
			"Bool": {
				"aws:SecureTransport": false # http 연결일경우 차단입니다.
			}
		}
	}]
}
  • 설정 후 aws cli 로 S3 버킷 정책 확인
aws s3api get-bucket-policy --bucket ahss-$NICKNAME-presign | jq -r .Policy | jq
==
{
  "AcceptRanges": "bytes",
  "LastModified": "2023-08-29T16:03:22+00:00",
  "ContentLength": 5310371,
  "ETag": "\"3bae2c6845352e627516a529fd507ffb\"",
  "ContentType": "image/jpeg",
  "ServerSideEncryption": "AES256",
  "Metadata": {}
}
==
  • [자신의 PC] IAM 자격증명 설정 되어 있는 상태
# object's metadata 정보 확인 : endpoint-url 옵션 설정 >> http? https? 확인
# 아래의 결과와 같이 강제로 https로 가능합니다.
aws s3api head-object --bucket ahss-$NICKNAME-presign --key jameswebb.jpg --endpoint-url http://s3.ap-northeast-2.amazonaws.com
==
An error occurred (403) when calling the HeadObject operation: Forbidden
==

aws s3api head-object --bucket ahss-$NICKNAME-presign --key jameswebb.jpg --endpoint-url https://s3.ap-northeast-2.amazonaws.com
==
{
    "AcceptRanges": "bytes",
    "LastModified": "2023-08-29T16:03:22+00:00",
    "ContentLength": 5310371,
    "ETag": "\"3bae2c6845352e627516a529fd507ffb\"",
    "ContentType": "image/jpeg",
    "ServerSideEncryption": "AES256",
    "Metadata": {}
}
==

Require SSE-KMS Encryption

  • 서버 측 암호화는 S3 관리 키(SSE-S3)를 사용한 서버 측 암호화, KMS 관리키(SSE-KMS)를 사용한 서버 측 암호화, 고객 측에 제공된 키(SSE-C)를 사용한 서버 측 암호화가 있다. 클라이언트 측 암호화에서는 데이터가 클라이언트 측에서 암호화된 다음 서버로 전송된다.
  • [자신의 PC] IAM 자격증명 설정 되어 있는 상태
# 캑체 버킷에 업로드
# default bucket encryption to SSE-KMS(AES256) to encrypt your data at rest and enforce encryption with a bucket policy.
#'textfile'이라는 파일의 내용을 'text01'이라는 이름으로 S3 버킷에 업로드하고, 그 결과 해당 객체가 서버 측에서 AES256 방식으로 암호화되었음을 보여줍니다.
echo "123456789abcdefg" > textfile
aws s3api put-object --key text01 --body textfile --bucket ahss-$NICKNAME-presign
{
    "ETag": "\"3ca451faac980583cffaadf8b63e6820\"",
    "ServerSideEncryption": "AES256"
}

#
aws s3api head-object --bucket ahss-$NICKNAME-presign --key text01 | jq
  • [AWS 콘솔] 버킷 속성 → 기본 암호화 (편집) : AWS KMS(SSE-KMS), AWS KMS키 중 선택(s3), 버킷 키(활성화)

*사용가능한 키 선택 시 아래 이미지 처럼 회색으로 aws/s3 선택 합니다.

  • [자신의 PC] IAM 자격증명 설정 되어 있는 상태
# object's metadata 정보 확인 : ServerSideEncryption 확인
aws s3api head-object --bucket ahss-$NICKNAME-presign --key jameswebb.jpg | jq

# 캑체 버킷에 업로드
# default bucket encryption to SSE-KMS(AES256) to encrypt your data at rest and enforce encryption with a bucket policy.
echo "abcdef" > textfile2
aws s3api put-object --key text02 --body textfile2 --bucket ahss-$NICKNAME-presign | jq
{
  "ETag": "\"aceb2413d6d0a7837f2d775144ff010a\"",
  "ServerSideEncryption": "aws:kms",
  "SSEKMSKeyId": "arn:aws:kms:ap-northeast-2:276281595736:key/c790ffcd-72d7-48d0-9f97-a079d5aeb50e",
  "BucketKeyEnabled": true
}

# object's metadata 정보 확인 : ServerSideEncryption 확인
#kms 확인
aws s3api head-object --bucket ahss-$NICKNAME-presign --key text02 | jq
===
{
  "AcceptRanges": "bytes",
  "LastModified": "2023-08-29T16:39:02+00:00",
  "ContentLength": 7,
  "ETag": "\"aceb2413d6d0a7837f2d775144ff010a\"",
  "ContentType": "binary/octet-stream",
  "ServerSideEncryption": "aws:kms",
  "Metadata": {},
  "SSEKMSKeyId": "arn:aws:kms:ap-northeast-2:276281595736:key/c790ffcd-72d7-48d0-9f97-a079d5aeb50e",
  "BucketKeyEnabled": true
}
===

IAM 정책 실습

  • [자신의 PC] IAM 자격증명 설정 되어 있는 상태 : IAM User 생성 및 S3 권한 부여
  • 해당 계정 생성 부분은 선택 입니다.
# s3user 사용자 생성
aws iam create-user --user-name s3user

# iam 사용자 리스트 확인
aws iam list-users | jq

# 사용자에게 프로그래밍 방식 액세스 권한 부여
aws iam create-access-key --user-name s3user
{
    "AccessKey": {
        "UserName": "s3user",
        "AccessKeyId": "Y6X",
        "Status": "Active",
        "SecretAccessKey": "BlWqQ",
        "CreateDate": "2023-08-27T04:32:47+00:00"
    }
}

# s3user 사용자에 AWS관리형정책(AmazonS3FullAccess)을 추가
aws iam attach-user-policy --policy-arn arn:aws:iam::aws:policy/AmazonS3FullAccess --user-name s3user
  • [EC2] 자격증명 없는 상태 : s3user 사용자 자격증명 설정 후 확인 (만들었을 겨우)
# aws cli 명령 시도
aws s3 ls
aws ec2 describe-vpcs

# s3user 자격증명 profile
aws configure
AWS Access Key ID [None]: AKIA5I..
AWS Secret Access Key [None]: 2XpI+7efp8YGM..
Default region name [None]: ap-northeast-2
Default output format [None]:

# 자격 증명 정보 저장되는 파일 확인
cat ~/.aws/credentials

# aws cli 명령 시도
aws s3 ls
==
2023-08-29 16:38:23 ahss-ssminho-presign
==

aws ec2 describe-vpcs


# 퍼블릭 액세스 차단 비활성 설정
aws s3api put-public-access-block --bucket ahss-$NICKNAME-presign --public-access-block-configuration \
"BlockPublicAcls=false,IgnorePublicAcls=false,BlockPublicPolicy=false,RestrictPublicBuckets=false"

퍼블릭 버킷 설정 후 IP 기반 통제

  • [AWS 콘솔] 리소스 정책 : 버킷 정책 설정 – 편집 클릭 후 아래 내용 입력 후 ‘변경 사항 저장’
{
    "Version": "2012-10-17",
    "Statement": [
        {
            "Sid": "PublicReadGetObject",
            "Effect": "Allow",
            "Principal": "*",
						#모든 객체를 다운 가능하다. 누구나
            "Action": "s3:GetObject",
            "Resource": "arn:aws:s3:::ahss-닉네임-presign/*"
        }
    ]
}
  • 설정 후 aws cli 로 S3 버킷 정책 확인
aws s3api get-bucket-policy --bucket ahss-$NICKNAME-presign | jq -r .Policy | jq
==
{
  "Version": "2012-10-17",
  "Statement": [
    {
      "Sid": "PublicReadGetObject",
      "Effect": "Allow",
      "Principal": "*",
      "Action": "s3:GetObject",
      "Resource": "arn:aws:s3:::ahss-ssminho-presign/*"
    }
  ]
}
==
  • [자신의 PC] and [EC2] : 객체 다운로드 시도 (실습:EC2 에서는 다운 가능하게 하고 PC로는 다운 불가능하게 해보기)
# 파일 복사 실행
aws s3 cp s3://ahss-$NICKNAME-presign/jameswebb.jpg . 

# [EC2] 미리 자신의 공인 IP 확인 메모해두기
curl ipinfo.io
curl ipinfo.io/ip ;echo
  • [AWS 콘솔] 리소스 정책 : 버킷 정책 설정 – 편집 클릭 후 아래 내용 입력 후 ‘변경 사항 저장’ ← IP주소는 EC2의 공인 IP 입력
    • 부정의 부정은 긍정이라고 생각하시면 됩니다.
{
    "Statement": [
        {
            "Effect": "Deny",
            "Principal": "*",
            "Action": [
                "s3:PutObject",
                "s3:GetObject",
                "s3:ListBucket"
            ],
            "Resource": [
                "arn:aws:s3:::ahss-닉네임-presign",
                "arn:aws:s3:::ahss-닉네임-presign/*"
            ],
            "Condition": {
								#해당 IP를 제외한 업로드, 다운로드, 리스트 를 제안한다.
                "NotIpAddress": {
                    "aws:SourceIp": "X.X.X.X/32"     #EC2의 IP 입력 합니다.
                }
            }
        }
    ]
}
  • 설정 후 aws cli 로 S3 버킷 정책 확인
aws s3api get-bucket-policy --bucket ahss-$NICKNAME-presign | jq -r .Policy | jq
==
{
  "Version": "2008-10-17",
  "Statement": [
    {
      "Effect": "Deny",
      "Principal": "*",
      "Action": [
        "s3:PutObject",
        "s3:GetObject",
        "s3:ListBucket"
      ],
      "Resource": [
        "arn:aws:s3:::ahss-ssminho-presign",
        "arn:aws:s3:::ahss-ssminho-presign/*"
      ],
      "Condition": {
        "NotIpAddress": {
          "aws:SourceIp": "52.78.6.51/32"
        }
      }
    }
  ]
}
==
  • [자신의 PC] and [EC2]
# [자신의 PC] 파일 생성
echo "memo1" > memo1.txt

# [자신의 PC] S3로 업로드
aws s3 cp memo1.txt s3://ahss-$NICKNAME-presign
==
upload failed: ./memo1.txt to s3://ahss-ssminho-presign/memo1.txt An error occurred (AccessDenied) when calling the PutObject operation: Access Denied
==

# [자신의 PC] 버킷 조회
aws s3 ls s3://ahss-$NICKNAME-presign
==
An error occurred (AccessDenied) when calling the ListObjectsV2 operation: Access Denied
==

aws s3api list-objects --bucket ahss-$NICKNAME-presign | jq
==
An error occurred (AccessDenied) when calling the ListObjects operation: Access Denied
==


# [EC2] 파일 생성
echo "memo2" > memo2.txt

# [EC2] S3로 업로드
aws s3 cp memo2.txt s3://ahss-$NICKNAME-presign
==
upload: ./memo2.txt to s3://ahss-ssminho-presign/memo2.txt
==

# [EC2] 버킷 조회
aws s3 ls s3://ahss-$NICKNAME-presign
==
2023-08-29 16:03:22    5310371 jameswebb.jpg
2023-08-30 14:32:21          6 memo2.txt
2023-08-29 16:31:11         17 text01
2023-08-29 16:39:02          7 text02
==

aws s3api list-objects --bucket ahss-$NICKNAME-presign | jq

Auditing Amazon S3’s Default Encryption Configurations at Scale & AWS SDK(boto3)

# boto3 설치
# boto3 이용하여 버킷 조회 가능합니다.
sudo python3 -m pip install boto3

# 버킷 리스트 조회
cat <<EOT > bucket-all.py
import boto3

s3 = boto3.resource('s3')
for bucket in s3.buckets.all():
  print(bucket.name)
EOT
python3 bucket-all.py

관련 링크: https://aws.amazon.com/ko/blogs/storage/how-to-audit-an-amazon-s3-buckets-default-encryption-configuration-at-scale/

#
git clone https://github.com/aws-samples/amazon-s3-default-encryption-audit
cd amazon-s3-default-encryption-audit/
tree

#
python3 amazon-s3-default-encryption-audit.py
...
Output Location:  /home/ec2-user/
You can now access the report in the following location:  
/home/ec2-user/bucketEncryptionReport_20230827-054611.csv

#버킷이름, 암호화 적용, 버킷 키, 타입 등 확인 가능합니다.
cat bucketEncryptionReport_20230830-145755.csv
==
Bucket Name,Default Encryption Mode,SSE-KMS Key Type,Bucket Key
ahss-ssminho-presign, arn:aws:kms:ap-northeast-2:272..36:key/c.....eb50e, AWS, True
==

Use AWS Config Rules to Detect a Public Bucket

  • [AWS 콘솔] config 서비스 → 시작하기 → 단계1~3 설정 : 결과 저장용 신규 버킷(유일 이름)을 생성합니다.
  • 2~3분 정도 시간 후에 규정 점검 결과 확인

-실습 완료 후 자원삭제

  1. AWS Config → 생성된 규칙 삭제
  2. AWS IAM User (s3user) 삭제
  3. AWS 버킷 → 버킷 정책 삭제 → 비우기 → 삭제
  4. AWS CloudFormation 스택 삭제

위로 스크롤