Amazon S3 보안

Siyun·2025년 2월 27일

AWS

목록 보기
15/37

Amazon S3의 객체 암호화

네 가지 방법을 이용해서 S3 버킷의 객체를 암호화 한다.

1. 서버 측 암호화(SSE=Server-Side Encryption) :

- SSE-S3
Amazon S3에서 관리하는 키를 이용한 서버측 암호화. 사용자는 키에 접근할 수 없다.
만들어진 버킷과 객체에 대해 기본값으로 활성화되어 있다. 사용자가 데이터를 업로드하면 S3에서 소유한 키로 객체를 혼합해서 암호화를 한 다음 버킷에 저장된다.
암호화의 보안 유형은 AES-256이다. 이를 위해 헤더에 "x-amz-server-side-encryption":"AES256" 이라고 설정해야 한다.

- SSE KMS
AWS KMS(Key Management Service) 키를 이용해 암호화 키를 관리한다.
KMS를 사용할 경우 사용자가 키를 통제할 수 있다는 장점이 있다.
KMS에서 직접 키를 생성할 수 있고 CloudTrail을 이용해서 키 사용을 검사할 수 있다.
누군가 KMS에서 키를 사용할 때마다 AWS 안에서 일어나는 모든 것을 로깅하는 서비스인 CloudTrail에 로깅될 것이다.
헤더에 "x-amz-server-side-encryption":"aws:kms" 라고 설정해야 한다.
버킷에서 해당 파일을 읽으려면 객체 자체에 엑세스+ KMS 키 엑세스 두 가지가 이뤄져야 한다.
KMS키에는 GenerateDataKey같은 자체 API가 있고, 우리는 DecryptAPI를 사용해서 복호화한다. API 호출을 하게 되면 그 API호출 건은 모두 KMS의 초당 API 호출 쿼터에 합산된다.
리전에 따라 초당 5,000내지 30,000 건의 요청이 가능하다.
만약 S3 버킷의 처리량이 아주 많고 모든 게 KMS키로 암호화되어 있다면 그건 일종의 스로틀링(처리량 제한) 활용사례가 될 수 있다.

기본 aws/s3키를 선택하면 비용이 발생하지 않지만 직접 KMS키를 생성하면 비용발생
요금 참고 :https://aws.amazon.com/ko/kms/pricing/?utm_source=chatgpt.com

- SSE-C
고객이 제공한 키를 사용한다. 키가 AWS 외부에서 관리되지만 키를 AWS로 전송하고(HTTPS 사용) S3는 암호화 키를 저장하지 않고 사용 후에는 폐기한다.
사용자는 파일과 키를 업로드할 건데 사용자가 AWS외부에서 그 키를 관리한다.
S3는 클라이언트가 제공한 키와 객체를 사용해 암호화를 수행하고 암호화된 파일을 S3버킷에 넣는다.
파일을 읽으려면 암호화에 사용한 키가 있어야 한다.
SSE-C를 적용하려면 콘솔이 아닌 CLI에서 다뤄야 한다.

- DSSE-KMS
KMS를 기반으로 한 이중 암호화

2. 클라이언트 측 암호화(Client-Side Encryption) :

클라이언트 측의 모든 걸 암호화한 다음에 S3에 업로드한다.
클라이언트 라이브러리를 활용하면 더 쉽게 구현할 수 있다.
복호화도 S3 외부의 클라이언터측에서 이뤄진다.
클라이언트가 키와 암호화 사이클을 완전하게 관리하는 것이다.

S3 암호화 실습

1. 기본적으로 SSE-S3를 설정해 버킷을 만든다.

2. 만들어진 버킷 선택 > Server-side encryption settings > edit을 눌러 암호화 메커니즘 편집

서버측 암호화를 편집하면 업데이트된 세팅으로 새로운 버전의 객체가 생성된다.
여기서 SSE-S3가 아닌 SSE-KMS 혹은 DSSE-KMS 중에 선택할 수 있다.

3. 객체를 업로드할 때마다 해당 객체의 암호화 방식을 선택할 수 있다.

4. 기본값 암호화 편집하기

버킷을 선택 > Properties > Default encryption > edit으로 기본 암호화 방식을 변경할 수 있다.


S3 전송 중 암호화(SSL,TLS)

  • 기본적으로 S3 버킷에는 암호화 되지 않는 HTTP엔드포인트와 전송 중 암호화가 제공되는 HTTPS 엔드포인트가 있다.
  • HTTPS를 사용하는 것을 권고하고 만약 SSE-C타입의 매커니즘을 사용한다면 반드시 HTTPS 프로토콜을 사용해야 한다.
  • 모든 클라이언트가 기본값으로서 HTTPS 엔드포인트를 사용한다.
  • 전송 중 암호화를 강제하기 위해 버킷정책을 사용할 수 있다.
{
  "Version": "2012-10-17",
  "Statement": [
    {
      "Effect": "Deny",
      "Principal": "*",
      "Action": "s3:GetObject",
      "Resource": "arn:aws:s3:::your-bucket-name/*",
      "Condition": {
        "Bool": {
          "aws:SecureTransport": "false"
        }
      }
    }
  ]
}

이런 버킷정책 구문을 적용하면 HTTPS를 사용할 경우 SecureTransport는 true이고 암호화 연결을 사용하고 있지 않다면 false라서 HTTPS를 사용하지 않는 경우 오브젝트 열람이 거절된다.


S3 기본값 암호화 vs 버킷 정책

  • 기본 암호화를 SSE-S3나 SSE-KMS로 변경해서 암호화 할 수 있다.
  • 혹은 버킷정책을 사용해서 암호화를 강제하고 올바른 암호화 헤더가 없는 경우 S3 객체를 PUT하는 API호출을 거절할 수 있다.
{
  "Version": "2012-10-17",
  "Statement": [
    {
      "Effect": "Deny",
      "Principal": "*",
      "Action": "s3:PutObject",
      "Resource": "arn:aws:s3:::your-bucket-name/*",
      "Condition": {
        "StringNotEquals": {
          "s3:x-amz-server-side-encryption": "aws:kms"
        }
      }
    }
  ]
}

이 버킷 정책은 kms 헤더가 없으면 PutObject를 거절한다.

버킷 정책은 항상 기본값 암호화 설정 이전에 평가된다. (우선순위가 더 높다)
버킷정책을 기본값 암호화 이전에 선제적으로 적용해 암호화를 강제할 수 있다.


CORS (Cross-Origin Resource Sharing)

오리진은 체계(프로토콜)와 호스트(도메인)와 포트로 구성된다.
CORS는 웹 브라우저 기반 보안 메커니즘으로 메인 오리진을 방문하는 동안 다른 오리진에 대한 요청을 허용하거나 거부한다.

예 : https://www.example.com
HTTPS의 포트는 443이다. 프로토콜은 HTTPS자체이고 도메인은 WWW.example.com이다.

👉🏻 오리진이 같다는 것은?
체계, 호스트, 포트가 동일할 때!
예시 : https://example.com/app1 , https://example.com/app2

👉🏻 오리진이 다른 예시 : www.example.com , other.example.com

다른 오리진의 웹사이트에 요청을 보낼 때 다른 오리진이 CORS 헤더를 사용해서 요청을 허용하지 않는 한 해당 요청은 이행되지 않는다.
이를 액세스 제어 허용 오리진 헤더(Access-Control-Allow-Origin)라고 한다.

클라이언트가 S3 버킷에서 교차 오리진 요청을 하면 정확한 CORS 헤더를 활성화해야 한다.
이 작업을 빠르게 수행하려면 특정 오리진을 허용하거나 *로 모든 오리진을 허용한다.

만약 정적 웹사이트 호스팅이 활성화된 bucket-web1이 index.html을 클라이언트의 요청에 반환할 때, 사이트에 필요한 이미지가 또다른 웹사이트 호스팅이 활성화된 bucket-web2에서 불러온다면?
bucket-web2에서 CORS요청의 오리진(bucket-web1)을 확인하고, Access-Control-Allow-Origin에서 bucket-web1을 허용하지 않았다면 요청을 거부한다.
요청을 허용한 경우라면 정확한 헤더를 갖고 요청이 처리되어 이미지를 얻을 수 있다.

CORS 실습

정적 웹 호스팅 버킷 두개가 있다.
버킷1에서 버킷2의 html파일을 불러와서 innerhtml로 띄울 것이다.

1. 버킷2의 Permissions > CORS 설정 > Edit

JSON형식으로 정의
아래는 예시

{
  "CORSRules": [
    {
      "AllowedOrigins": ["Authorization"],
      "AllowedMethods": ["GET", "POST", "PUT"],
      "AllowedHeaders": ["*"],
      "ExposeHeaders": [],
      "MaxAgeSeconds": 3000
    }
  ]
}
  • AllowedOrigins → 허용할 도메인 목록
    ["*"] → 모든 도메인에서 접근 가능
    특정 도메인만 허용하려면 ["https://example.com"]처럼 설정. 뒤에 /는 없애야함.
  • AllowedMethods → 허용할 HTTP 메서드
    ["GET", "POST", "PUT"] → GET, POST, PUT 요청 가능
    필요에 따라 "DELETE", "HEAD" 추가 가능
  • AllowedHeaders → 허용할 요청 헤더
    ["*"] → 모든 요청 헤더 허용
    특정 헤더만 허용하려면 ["Authorization", "Content-Type"] 설정
  • ExposeHeaders → 클라이언트에서 접근할 수 있는 응답 헤더
    ["x-amz-request-id"] → 특정 응답 헤더를 클라이언트가 확인 가능
  • MaxAgeSeconds → 브라우저가 CORS 응답을 캐싱하는 시간(초)
    3000 → 3000초 동안 CORS 요청을 다시 보내지 않고 캐싱된 응답 사용

S3 MFA Delete

MFA는 객체 버전을 영구적으로 삭제할 때 필요하다.
영구 삭제에 대한 보호 설정이다.
버킷에서 버전 관리를 중단할 때도 필요하다.
루트 계정만이 MFA Delete를 활성화/비활성화할 수 있다.

S3 MFA Delete 실습

1. 버킷 > Bucket Versioning 에서 MFA삭제가 활성화인지 비활성화인지 확인 가능하다.

2. 활성화하려면 CLI를 사용해야 한다.

루트계정의 MFA를 설정하고 액세스키를 생성해 터미널에서 CLI로 아래 명령어를 입력한다.
프로필을 먼저 생성한다.

aws configure --profile <프로필 이름>

그 다음 엑세스 키ID와 엑세스 키를 입력하고 기본 리전 이름을 입력한다.
아래 내용을 입력해 정상적으로 버킷리스트가 뜨는지 확인한다.

asw s3 ls --profile <프로필 이름>

아래 내용을 입력해 MFA Delete를 활성화한다.

aws s3api put-bucket-versioning \
    --bucket <버킷이름> \
    --versioning-configuration Status=Enabled,MFADelete=Enabled \
    --mfa "<MFA장치의 ARN> <MFA코드>" --profile <프로필 이름>

이렇게 하면 영구 삭제를 하기 위해서는 CLI 명령을 사용하거나 MFA삭제를 비활성화해야 한다.
비활성화 명령어는 위에서 MFADelete=Disabled로 수정하기 다시 받은 MFA코드를 입력하는 것만 수정하면 된다.

aws s3api put-bucket-versioning \
    --bucket <버킷이름> \
    --versioning-configuration Status=Enabled,MFADelete=Disabled \
    --mfa "<MFA장치의 ARN> <MFA코드>" --profile <프로필 이름>

S3 엑세스 로그

  • 감사 목적으로 S3 버킷에 대한 모든 액세스를 기록할 수 있다.
  • 어떤 계정에서든 S3로 보낸 모든 요청은 승인 또는 거부 여부와 상관없이 다른 S3 버킷에 파일로 기록된다. 해당 데이터는 Amazon Athena 같은 데이터 분석 도구로 분석할 수 있다.
  • 대상 로깅 버킷은 같은 AWS 리전에 있어야 한다.
  • S3 버킷의 액세스 로그를 활성화해서 모든 요청이 로깅 버킷에 기록되도록 설정하면 된다.
  • 절대로 로깅 버킷을 모니터링하는 버킷과 동일하게 설정하면 안된다. 로깅 루프가 생성되어 버킷의 크기가 기하급수적으로 증가한다.

S3 엑세스 로그 실습

1. 버킷 > Properties > Edit Server access logging 선택

2. 로깅 버킷으로 쓸 목적지 버킷을 선택한다.

3. 로그형식을 정한다.

엑세스 로그를 활성화하면 버킷 정책이 수정된다.
로깅 버킷이 현재 버킷에 객체 업로드가 가능하게 바뀐다.


S3 미리 서명된 URLs (Pre-Signed URLs)

  • S3콘솔, CLI, SDK를 사용하여 생성할 수 있는 URL이다.
  • URL에는 만료 기한이 있는데 S3콘솔을 사용하면 최대 12시간, CLI를 사용하면 168시간까지 사용 가능
  • 미리 서명된 URL를 생성할 때 URL을 받는 사용자는 URL을 생성한 사용자의 GET 또는 PUT에 대한 권한을 상속한다.

🚗사용사례

프라이빗 S3 버킷이 있다.
AWS 외부의 사용자에게 한 파일에 대한 엑세스 권한을 부여하고 싶다.
하지만 퍼블릭 파일로 설정하고 싶지 않다.
이럴 때 해당 파일을 가지고 미리 서명된 URL을 생성한다.
URL이 자격 증명을 이어받아 해당 파일에 액세스 할 수 있는 권한을 부여한다.

S3 미리 서명된 URLs 실습

퍼블릭이 아닌 버킷에 있는 객체를 URL을 통해 열지말고 그냥 OPEN을 누르면 그게 미리 서명된 URL이다.

1. 객체 선택 > Object actions > Share with presigned URL 클릭

버킷과 객체가 프라이빗이라도 만료될 때까지 누구나 URL로 액세스 할 수 있다.
허용되는 시간을 정해주고 Create prsigned URL을 클릭하면 된다.


S3 Glacier 볼트 잠금 (Vault Lock)

  • WORM(한번 쓰고 여러번 읽는) 모델을 채용하기 위해 Glacier 볼트를 잠그는 것.
  • 객체를 가져와 S3 Glacier 볼트에 넣은 다음 수정, 삭제가 불가하도록 잠근다.
  • Glacier 위에 볼트 잠금 정책을 생성한 다음 정책을 잠근다. 볼트 잠금 정책을 설정하고 잠근 후에는 누구도 변경하거나 삭제할 수 없게 된다. (관리자도 삭제 불가)
  • 규정 준수와 데이터 보존에 아주 유용하다.

S3 객체 잠금 (Object Lock)

  • 버전관리를 활성화해야 사용 가능하다.
  • WORM채택 가능.
  • 객체 잠금은 S3 버킷 수준으로 잠그는게 아닌 객체마다 각각 적용할 수 있음.
  • 특정 객체 버전이 특정 시간 동안 삭제되는 걸 차단할 수 있다.

🔒 2가지 보존모드(Retention mode)
1) 규정 준수 모드(Compliance):

S3 Glacier 볼트 잠금과 비슷하게 누구도 객체 버전을 덮어쓰거나 삭제하거나 객체 변경을 할 수 없다.
보존 모드 자체 변경도 불가하고 보존 기간 단축도 하지 못함.
규정 준수를 엄격히 적용할 때 사용한다.

2) 거버넌스 보존 모드:
대부분의 사용자는 객체 버전 덮어쓰기, 삭제, 로그설정을 변경할 수 없음.
관리자나 일부 사용자는 IAM을 통해 부여받은 특별 권한으로 보존 기간을 변경하거나 객체를 바로 삭제할 수 있다. 규정 준수 모드 보다 유연함.

두가지 보존 모드 모두 보존 기간을 설정해서 그 기간 동안 객체를 보호할 수 있고 원하는 만큼 기간을 연장할 수 있다.

객체에 '법적 보존' 상태를 설정하면 S3 버킷 내 모든 객체를 무기한으로 보호한다. 보존 기간과는 무관하기 때문에 아주 중요한 (재판에서 사용될 수 있는) 객체에 법적 보존을 설정한다.
s3:PutObjectLegalHold IAM 권한을 가진 사용자는 어떤 객체에든 법적 보존을 설정하거나 제거할 수 있다.


S3 액세스 포인트

  • S3 버킷정책이 복잡해지면 관리하기가 어려워 진다.
  • 특정 접두사에 S3 액세스 포인트를 만들면 버킷의 접두사에 해당하는 데이터에 접근할 수 있다.
  • 액세스 포인트는 S3 버킷 정책과 똑같은 모습이다.
  • 액세스 포인트마다 액세스 포인트 정책을 정의해서 해당 접두사에 읽기와 쓰기 액세스 권한을 부여한다.
  • 액세스 포인트는 각자의 DNS 이름을 갖게 될 것이며 그걸로 액세스 포인트에 접속할 수 있다.
  • 액세스 포인트가 인터넷 오리진에 연결되거나 프라이빗 트래픽의 경우에 VPC 오리진에 연결되도록 할 수 있다. 그러기 위해 VPC 엔드포인트를 만들어야 한다.

S3 Object Lambda

  • S3 버킷을 호출자 애플리케이션이 객체를 받기 직전에 그 객체를 수정하려는 경우에 사용
  • 버킷을 복제해서 버킷에 각 객체의 다른 버전을 갖는 대신 S3 엑세스 포인트를 람다함수에 연결해 객체를 수정해서 반환할 수 있다.
  • 그리고 해당 람다함수를 호출하는 S3 객체 람다 액세스 포인트를 만들어 앱에서 원래 객체에서 조금 수정된 객체를 가져올 수 있다.
  • 활용 사례: 분석기나 비프로덕션 환경을 위해 PII데이터(개인식별정보)를 삭제하는 경우, 데이터형식을 XML에서 JSON으로 변환하는 경우, 즉석에서 이미지 크기를 조정하거나 워터마크를 추가하는 경우.
profile
공부 기록

0개의 댓글