AWS - 13 [S3]

_Block·2022년 9월 15일
0

AWS

목록 보기
14/27
post-thumbnail

🚀 버킷

S3는 기본적으로 객체를 저장하게 해주는 시스템이자 서비스 입니다.

즉 파일이 버킷 또는 디렉터리에 있고, 각.버킷은 전역적으로 고유한 이름을 가지게 됩니다.

이미 사용중인 이름을 사용하여 버킷을 만들 수는 없고, 리전 수준에서 정의가 되는 서비스 입니다.

  • 즉 S3는 전역 서비스 이지만, 버킷은 리전 리소스 입니다.
명명 규칙

1. 소문자 또는 숫자로 시작할 것

2. 밑줄을 사용하지 말 것

3. 길이는 3에서 63자일 것

4. IP 주소가 아닐 것

🐾 버킷 키 이름

S3버킷에서 객체를 만들어야 활용이 가능하며, 여기에서 객체의 키값은 파일의 전체 경로를 의미합니다.

만약 버킷 이름이 s3://my-bucket/my_file.txt이고 객체 이름이 my-file.txt라면 키는 my-file.txt가 됩니다.

만약 폴더가 있는 이러한 형태라면 s3://my-bucket/my_folder/another_folder/my_file.txt

키는 다음과 같습니다. my_folder/another_folder/my_file.txt

키는 접두어와 객체 이름이라는 2가지로 구성이 됩니다.

앞서 폴더가 있는 형태의 키에서 접두어는 my_folder/another_folder를 의미하며, 객체 이름은 my_file.txt가 됩니다.

  • 즉 버킷 내에는 디렉터리 개념 없이 키 이름만 매우 깁니다.

🐾 버킷 용량

버킷은 최대 5TB즉 5,000GB까지 업로드 가능합니다.

하지만 만약 5,000GB를 넘는 크기를 한번에는 업도르 할 수 없습니다.

그러기 떄문에 이러한 경우에는 나눠서 업로드 하는 방향으로 진행을 해야 하고 이것을 멀티파트 업로드라고 합니다.

🚀 버킷 실습

AWS CLI에 접속하여 S3버킷으로 이동하 버킷 만들기를 클릭합니다.

이후 이름을 설정해야 하는데 앞서 말했듯이 버킷의 이름은 AWS의 전역에서 다루기 떄문에 내가 가지고 있지 않아도 중복된 이름이 있을 수 있습니다.

그러니깐 최대한 중복이 되지 않을만한 이름을 설정 합니다.

이후 그냥 생성하면 됩니다.

  • 이외에 보안이나, 버전관리 등은 후에 추가로 다루어 보겠습니다.

이후 만들어진 버킷을 클릭후 업로드를 진행해 봅니다.

  • 이 페이지에 도착했다면 성공입니다.

이후 파일을 업로드 한후 업로드한 파일로 이동합니다.

해당 파일을 여는 방법은 두가지가 있습니다.

  1. 오른쪽 위에 있는 열기를 클릭한다.

  2. 객체 URL을 통해서 확인한다.

두 가지 방법으로 열어볼수 있는데 현재는 1번의 방법만 사용 가능합니다.

  • 2번쨰 방법을 사용해서 열어보면 알수 있듯이 Access Denied가 발생합니다.

해당 에러가 발생하는 이유는 버킷이 퍼블릭으로 동작하고 있지 않기 떄문입니다.

1번쨰 방법을 통해 파일을 열어보면 URL에 우리가 기존에 알고 있던 버켓 URL과 다르다는 것을 볼 수 있습니다.

왜냐하면 1번쨰 방법 같은 경우에는 AWS에서 직접 임시적으로 AUTH를 부여하기 떄문에 해당 AUTH가 추가되어 나오기 떄문입니다.

🚀 S3의 버전 관리

버킷에 다시 들어가서 속성 - 버킷 버전 관리 - 편집을 통해 버전를 활성화 해줍니다.

버킷의 버저닝 관리는 다음과 같습니다.

같은 키 파일을 다시 업로드 하는 경우에는 덮어쓰는것이 아니라 새로운 버전을 생성합니다.

즉 이러한 방법으로 인해서 이전 파일을 계속 가지고 있기 떄문에 복원이 용이합니다.

몇가지 알아두어야 할 것은 다음과 같습니다.

1. 버전닝을 활성화하기 전에 버전 관리되지 않은 파일은 null버전이 됩니다.
- 즉 버저닝 활성화 이전의 파일들의 버전은 모두 null입니다.

2. 버저닝을 중단하면 이전 버전을 삭제하는 것이 아니라 이후의 파일이 버전을 바지 못하도록 합니다.

3. 파일을 삭제하게 되면 실제로 삭제가 되는 것은 아니고 Delete marker로 설정이 됩니다.
- 잘못 삭제했을떄를 방지하기 위함입니다.

이러한 버전관리로 인해서 원하는 버전만을 삭제 가능하며, Delete marker가 있는 파일또한 취소 가능합니다.

  • 버저닝을 활성화하여 이전 파일의 버전이 null이 된 모습

🚀 S3 암호화

S3에 객체를 업로드 하면 이들은 AWS내의 서버가 되기 떄문에 객체로 접근이 불가능하게끔 보호합니다.

예를들면 누군가 AWS서버에 들어올 떄 특정한 규칙을 지켜야만 들어올 수 있는 것과 같습니다.

객체 암호화를 위한 방법은 총 4가지가 있습니다.

🐾 SSE-S3

AWS가 처리 및 관리하는 키를 사용해 S3객체를 암호화하는 방식입니다.

객체는 서버 측에서 암호화됩니다.

SSE가 서버 측 암호화를 뜻하며 알고리즘은 AES-256입니다.

암호화를 설정하고자 한다면 "x-amz-server-side-encryption":"AE256"로 헤더를 설정해야 합니다.

암호화를 하고자 한다면 이와 같습니다.

HTTP/HTTPS를 사용하여 업로드 할시에 Header에 추가합니다.

그러면 AWS에서 암호화 해야 하는 데이터라는 것을 인식하여 데이터 키와 객체를 사용해서 암호화합니다.

이 방식의 단점은 S3에서 데이터 키를 모두 소유 및 관리를 한다는 점 입니다.

🐾 SSE-KMS

AWS 키 관리 서비스를 사용해서 암호화 키를 관리하는 방법입니다.

KMS는 키관리 서비스를 의미하며 암호화 키는 KMS서비스 내에서 처리 가능합니다.

  • 아직 배우지 않은 부분 입니다.

해당 기능을 사용하는 이유는 누가 키에 접근할 수 있는지 제어 가능하며, 감사 및 추적 또한 가능하기 떄문입니다.

각각의 객체는 서버측에서 암호화되고 이떄의 헤더는 aws:kms로 지정해야 합니다.

원리는 동일하며 S3에 업로드 될떄 미리 정의해 둔 고객 마스터 키를 사용하여 암호화하는 방식입니다.

🐾 SSE-C

사용자가 만든 암호화 키를 관리할 떄 쓰이는 방식입니다.

서버 측 암호화 방식을 뜻하며 외부에서 고객이 관리하는 키를 사용합니다.

그러기 떄문에 S3에서는 암호화 키를 저장하지 않으며 사용후에는 폐기됩니다.

또한 키를 전송하는 과정이 있기 떄문에 이전과 다르게 반드시 HTTPS로 트래픽을 암호화 하여 전송해야 합니다.

저장하는 것은 어렵지 않지만 다시 가져오는 것은 복잡합니다.

왜냐하면 키를 클라이언트에서 보관하고 있고 AWS에서는 보관하고 있지 않고 폐기하기 떄문에 어떤 데이터 키를 사용했는지를 알 수가 없기 떄문입니다.

🐾 클라이언트 측 암호화

이 방식은 AWS에서 암호화를 하지 않고 클라이언트 측에서 객체를 암호화하여 객체를 전송하는 방법입니다.

즉 모든것을 클라이언트 측에서 도맡아서 담당하는 암호화라고 할 수 있습니다.

🚀 S3 암호화 실습

아까와 동일하게 S3에서 파일 업로드로 접속을 합니다.

파일을 선택하고 아래로 내려가 서버측 암호화를 선택합니다.

  • 이와같이 설정이 되면 AWS에서 해당 파일을 암호화 해서 관리해 줍니다.

이런식으로 업로드 하면 설정한 특정 파일에만 암호화가 동작을 합니다.

만약 모든 파일에 대해 Default값으로 암호화를 시키고 싶다면

버킷의 속성 탭에서 기본 암호화를 수정해 주면 됩니다.

SSE-C옵션은 AWS CLI에서 아직 실습 기능을 제공하지 않고 있기 떄문에 진행이 불가능하며, Client측에서의 암호화는 말 그대로 Client가 없기 떄문에 진행이 불가능 합니다.

🚀 S3 보안 및 버킷 정책

여러가지 보안이 있습니다.

첫번쨰는 사용자 기반 보안이 있습니다.

IAM사용자는 IAM정책으로 인해 접근권한에 제약이 있을수 있는데 이러한 방법을 활용하는 보안입니다.

두번쨰는 리소스 기반 보안입니다.

S3 콘솔에서 설정 가능한 전반의 규칙이며 S3버킷에서 보안주체가 무엇을 할 수 있는지를 결정하는 정책입니다.

  • 후에 실습에서 자세히 알아보겠습니다.

세번쨰는 세분화된 방식인 ACL방식입니다.

객체 레벨에서의 액세스 규칙을 설정합니다.

마지막은 버킷 ACL방식 입니다.

  • ACL방식은 매우 드물게만 사용이 됩니다.

보통 IAM으로 접근 가능한 사용자를 설정하고 이후 정해진 규칙에서만 사용 가능하게 동작을 시킵니다.

리소스 기반 보안 정책이 이러한 정해진 규칙을 규정하게 되는데 이는 JSON으로 작성이 됩니다.

{
	Version : "2012-10-17".
    "Statement": [
    	{
        	"Sid" : "PublicRead".
            "Effect" :"Allow",
            "Principal" :"*",
            "Action":[
            	"s3":GetObject"
            ].
            "Resource" :[
            	"arn:asw:s3:::examplebucket/*"
            ]
        
        }
    ]
}

이와 같이 정의가 되며 이는 Effect = Allow, 모든 사용자 ,Principal = * ,누구나, Resource = 모든것으로 정의가 되어 있는 버킷 정책입니다.

흔히 버킷 정책은 액세스 권한, 업로드 시점에 객체를 암호화등에 주로 사용이 됩니다.

🐾 블록 퍼블릭 액세스 버킷 설정

객체가 퍼블릭화 되는 것을 차단하는 설정입니다.

  • 계정에 제한이 있을 경우에 사용이 됩니다.

해당 기능을 설정하는 이유는 객체와 버킷이 외부로 공개되지 않도록 하기 위해서 사용이 되며 교차 계정 액세스를 방지하는데에도 사용이 됩니다.

즉 버킷을 절대로 퍼블릭으로 두지 않고 싶다면 이 기능을 설정해야 합니다.

🚀 S3 버킷 정책 실습

버킷을 선택하여 권한으로 이동합니다.

이후 스크롤을 내려 버킷 정책에서 작성을 하면 됩니다.

하지만 직접 작성하는 것은 상당히 어려운 작업이기 떄문에 AWS에서 제공하는 UI를 활용하면 됩니다.

  • 편집을 누른뒤에 정책 생성기에 들어갑니다.

  • 여기까지 진행이 되었다면 성공입니다.

이후 정책을 만들어 주면 됩니다.

간단하게, SSE-S3로 업로드 하지 않는 파일은 거부하는 정책을 만들어 보겠습니다.

  1. 저희는 S3버킷의 정책을 만드는 것이기 떄문에 Type을 S3로 설정해 줍니다.

  2. 거부하는 정책을 만들 것이기 떄문에 Effect를 Deny로 설정합니다.

  3. 모든 파일에 적용할 것이기 떄문에 Principal을 *로 설정합니다.

  4. 업로드 하는 모든 파일에 적용할 것이기 떄문에 Action은 PutObject를 선택 합니다.

  5. 그후 버킷 ARN을 등록합니다.

  • 버킷 ARN은 버킷이름 + 키이름으로 구성이 되어 있으며 이느 버킷 정책 편집 페이지에서 복사할 수 있습니다.
  • 복사를 한뒤에 반드시 마지막에 /*를 붙여줘야 합니다. 왜냐하면 어떤 키값이 들어올지 모르기 떄문에 모든 키값에 적용한다는 의미 입니다.

  • 새롭게 셋팅한 저의 버킷 정책입니다.

추가적인 조건이 필요합니다.

  1. Optional의 항목에서 Condition설정을 Null로 설정합니다.

  2. Key같은 경우에는 이전에 적었던 x-amz-server-side-encryption로 설정합니다.

  3. Value는 true로 설정합니다.

이 설정하는 이유는 7계층 통신에도 적용하기 위함입니다.

앞에 작성된 정책은 AWS CLI에서 직접 파일을 올릴떄에 적용이 되지만 HPPTS/HPPT요청을 보낼떄에는 적용이 되지 않습니다.

그러기 떄문에 OPtional항목을 추가하는 것이고, header에 위와같은 키값이 없다면 == Null이라면 그때 앞서 설정한 조건이 발생하는 것 입니다.

하지만 단순히 헤더값이 있기만 했을떄만 검사를 하는 것은 의미가 없습니다.

  • 왜냐하면 그냥 header를 추가한뒤에 아무 문자열이나 보낼 수 있기 떄문입니다.

그러기 떄문에 한가지 더 option을 추가해 줍니다.

  1. Condition을 StringNotEquals로 설정합니다.

  2. Key는 이전과 동일하게 설정합니다.

  3. Value는 AES256를 설정합니다.

이렇게 조건을 추가하여 한가지 정책을 더 추가한뒤에 정책을 생성하면 JSON파일이 나오게 되고 이를 복사하여 정책에 추가하면 됩니다.

  • 저의 정책이며 저는 빠른 실습을 위해서 StringNotEquals정책은 따로 추가하지 않았습니다.

이후 정책을 적용한뒤에 파일을 암호화없이 업로드하면 실패가 뜨는것으로 실습이 마무리 됩니다.

🚀 S3 웹사이트

S3에 있는 파일을 보는 호스팅에 대해서 알아보았습니다.

일반적인 URL과 유사하며 s.3-website.AWS-리전.amazonaws.com으로 끝나게 됩니다.

웹사이트 호스팅을 하였지만 설정한 버킷정책이 없다면 403 Forbidden오류가 발생합니다.

일단 테스트를 위해서 다음과 같은 파일을 업로드 합니다.

<html>
<head>
    <title>aws test</title>
</head>
<body>
    <h1>aws S3 Test</h1>
    <p>I Wanna Be A Good Developer</p>
</body>

<img src="coffee.jpg" width="500" />
</html>
<h1>Error</h1>

이후 해당 두개의 파일을 업로드 해줍니다.

  • 추가로 coffee.jpg라는 이름을 가지고 있는 파일도 업로드 해줍니다.

  • 현재의 저의 버킷입니다.

이후 속성탭에 가서 맨 아래로 스크롤하여 정적 웹 사이트 호스팅을 활성화 시켜줍니다.

이후 인덱스 문서는 index.html, 오류 문서는 error.html를 입력해 줍니다.

이후 호스팅을 활성화하게 되면 호스팅 활성화 항목으로 다시 이동하면 새로운 URL이 보이게 됩니다.

들어가보면 403 Forbidden이 발생을 하느네 이는 버킷에 액세스가 허용되지 않기 떄문입니다.

  • 보이는 것처럼 퍼블릭 액세스가 불가능합니다.

이걸 해결하는 것은 두가지가 있습니다.

  1. Block 퍼블릭 액세스 설정 변경
  • 모든 퍼블릭 액세스를 해제시켜주면 됩니다.
  1. 버킷 정책 설정

기본적으로 퍼블릭 액세스는 퍼블릭 접근을 막기 위해서 사용을 합니다.

단순히 퍼블릭 액세스를 모두 해제해주면 누구나 해당 데이터에 접근이 가능하기 떄문에

퍼블릭 액세스를 허용한 다음에는 반드시 정책을 설정해 주어야 합니다.

모든 퍼블릭 액세스 차단을 비활성화 시키고 버킷 정책을 편집해줍니다.

Action은 GetObject로 설정하고 나머지 설정은 앞서 설명했던것처럼 설정해 줍니다.

{
  "Id": "Policy1663389967392",
  "Version": "2012-10-17",
  "Statement": [
    {
      "Sid": "Stmt1663389958761",
      "Action": [
        "s3:GetObject"
      ],
      "Effect": "Allow",
      "Resource": "arn:aws:s3:::test-bucket-mbv/*",
      "Principal": "*"
    }
  ]
}
  • 이게 만들어진 저의 버킷 액세스 정책입니다.

이후 해당 페이지로 이동하여 다시 새로고침을 하면 원하는 페이지가 보이는 것을 확인할 수 있습니다.

  • 이외에도 URI의 뒤에 추가로 아무 쿼리문이나 추가하면 자동으로 설정한 Error.html 보이는 것 또한 확인할 수 있습니다.

🚀 CORS

기본적인 CORS의 개념을 다루는 글은 아니기 떄문에 이러한 부분이 궁금하다면 검색을 하셔서 알아보시면 될꺼 같습니다.

  • 쉽게 말하면 다른 Origin의 접근을 막는겁니다.

S3에서도 기본적으로 CORS가 적용이 되기 떄문에 다른 Origin에서 접근을 하고자 한다면 Headers에 Cors정책을 추가해 주어야 합니다.

기존의 index.html을 다음과 같이 업데이트 해줍니다.

<html>
<head>
    <title>aws test</title>
</head>
<body>
    <h1>aws S3 Test</h1>
    <p>I Wanna Be A Good Developer</p>
</body>

<img src="coffee.jpg" width="500" />

<!-- CORS demo -->

<div id="tofetch"/>
<script>
    let tofetch = document.getElementById("tofetch")

    fetch('extra-page.html').then((response) =>{
        console.log("response",response)
        return response.text();
    }).then((html) =>{
        console.log("html",html)
        tofetch.innerHTML = html
    })

</script>
</html>

또한 추가로 extra-page.html이라는 파일을 만들고 다음과 같이 적습니다.

<h1>extra Page</h1>

이후 두가지 파일을 다시 업로드 해줍니다.

  • 현재 저의 버킷입니다.

그리고 다시 웹사이트를 새로고침하면 extra-page.html이 추가로 보이는 것을 확인해 볼 수 있습니다.

이게 가능한 이유는 동일한 Origin에 존재하기 떄문에 가능합니다.

그럼 이제는 다른 Origin으로 시도를 해보겠습니다.

새로운 버킷을 만듭니다.

이떄 만드는 버킷은 퍼블릭 액세스를 비활성화 한 상태로 만들어야 하며, 기존에 만든 버킷과는 다른 리전을 가지고 있어야 합니다.

  • 다른 리전을 가지게 됨으로써 다른 Origin을 형성하는 것 입니다.

  • 이게 새롭게 만든 두개의 버킷 입니다.

이후 새롭게 만든 버킷의 웹 호스팅을 활성해 해주고, 버킷 정책을 생성해 줍니다.

  • 웹 호스팅 설정은 기존과 동일하게 index.html, error.html으로 설정하며, 정책 또한 기존과 동일하게 설정합니다.
  • 현재 새롭게 만든 버킷에는 index.html이 없기 떄문에 웹 호스팅이 동작하지는 않습니다.

그러고 다시 재접속을 하면 이번에는 403 Forbidden이 아닌 404에러가 발생을 할겁니다.

  • 403 Forbidden은 정책이 정해지지 않은 상태에서 접근을 하게 되었을떄 발생을 하며,
  • 404는 해당 파일을 찾을 수 없을떄 발생을 하는 것 입니다.

이후 새롭게 만든 Origin에 이전과 동일하게 extra-index.html파일 만을 추가해 줍니다.

그리고 url에 해당 파일명을 추가하면 이제는 extra-index.html이 보이는 것을 확인해 볼 수 있습니다.

이제 기존에 있던 버킷에서 extra-page파일을 삭제한뒤에 호스팅 페이지를 새로고침하면 Error가 발생하는 모습도 확인 가능합니다.

그럼 현재 상황을 정리해 보도록 하겠습니다.

A기존의 버킷에는 현재 index.html, error.html, coffee.jpg라는 파일이 있고

새롭게 만든 B에는 extra-page.html파일이 있습니다.

그럼 저희는 A버킷에서 B버킷에 있는 extra-page.html을 호출하면 CORS테스트 진행이 가능합니다.

그럼 이제 A라는 버킷을 열떄에 B버킷의 extra-page.html의 URl을 적어주면서 API 콜을 날립니다.

  • 현재 저의 B버킷의 extra-page.html의 위치는 다음과 같습니다.
  • http://cors-origin-test.s3-website.ca-central-1.amazonaws.com/extra-page.html

index.html파일을 이와 같이 수정합니다.

<html>
<head>
    <title>aws test</title>
</head>
<body>
    <h1>aws S3 Test</h1>
    <p>I Wanna Be A Good Developer</p>
</body>

<img src="coffee.jpg" width="500" />

<!-- CORS demo -->

<div id="tofetch"/>
<script>
    let tofetch = document.getElementById("tofetch")

    fetch('http://cors-origin-test.s3-website.ca-central-1.amazonaws.com/extra-page.html').then((response) =>{
        console.log("response",response)
        return response.text();
    }).then((html) =>{
        console.log("html",html)
        tofetch.innerHTML = html
    })

</script>
</html>

이후 A버킷에 index.html을 재업로드 해줍니다.

그후 호스팅된 URL로 접속해보면 콘솔창에서 이런 에러가 발생하는 것을 볼 수 있습니다.

  • 이것이 다른 Origin에서 접근을 할 떄 발생하는 에러 입니다.

이것을 해결하기 위해서는 저희는 B라는 버킷에서 CORS처리를 해주어야 합니다.

B의 권한 항목으로 이동 후 맨 아래에 있는 CORS 편집을 진행합니다.

다음과 같이 작성 합니다.

[
    {
        "AllowedHeaders": [
            "Authorization"
        ],
        "AllowedMethods": [
            "GET"
        ],
        "AllowedOrigins": [
            "A버킷이 요청을 보내는 URL"
        ],
        "ExposeHeaders": [],
        "MaxAgeSeconds": 3000
    }
]

중요한점은 URL을 적을때에 마지만 / 는 반드시 삭제해주어야 합니다.

그후 A버킷을 새로고침 해보면 문제없이 요청이 가는 것을 확인 가능하며 네트워크 창에서 요청에 대한 header값을 확인해보면

  • 다음과 같이 header값에 값이 추가된것을 확인 가능합니다.
profile
Block_Chain 개발자 입니다. 해당 블로그는 네트워크에 관한 내용을 다루고 있습니다.

0개의 댓글