Ver3.0 ๐ S3 ์ ๊ทผ์ ์ด ์ ์ฑ ์๋ฒฝ ๊ฐ์ด๋

๐ S3 ์ ๊ทผ์ ์ด ์ ์ฑ ์๋ฒฝ ๊ฐ์ด๋
๐ฏ S3 ์ ๊ทผ์ ์ด, ์ ์ค์ํ ๊น?
์๋
! ์ค๋์ AWS S3์ ์ ๊ทผ์ ์ด ์ ์ฑ
์ ๋ํด ์ด์ผ๊ธฐํด๋ณผ ๊ฑฐ์ผ. ํด๋ผ์ฐ๋ ์๋์ ๋ฐ์ดํฐ ๋ณด์์ ์ ํ์ด ์๋๋ผ ํ์์์? ๐ก๏ธ
S3(Simple Storage Service)๋ AWS์์ ์ ๊ณตํ๋ ๊ฐ์ฒด ์คํ ๋ฆฌ์ง ์๋น์ค์ธ๋ฐ, ์ ์ธ๊ณ ์๋ง์ ๊ธฐ์
๋ค์ด ์ฌ์ฉํ๊ณ ์์ด. ๊ทธ๋ฐ๋ฐ ๋ง์ด์ผ, S3 ๋ฒํท ํ๋ ์๋ชป ์ค์ ํ๋ค๊ฐ ํ์ฌ ์ ์ฒด ๊ณ ๊ฐ ๋ฐ์ดํฐ๊ฐ ์ธํฐ๋ท์ ๋
ธ์ถ๋๋ ์ฌ๊ณ ๊ฐ ์ค์ ๋ก ์ผ์ด๋๊ณค ํด. ๐ฑ
2019๋
์บํผํ ์(Capital One) ํดํน ์ฌ๊ฑด ๊ธฐ์ต๋? 1์ต ๋ช
์ด์์ ๊ณ ๊ฐ ์ ๋ณด๊ฐ ์ ์ถ๋๋๋ฐ, ์์ธ ์ค ํ๋๊ฐ ๋ฐ๋ก ์๋ชป๋ S3 ์ ๊ทผ์ ์ด ์ค์ ์ด์์ด. ์ด๋ฐ ์ฌ๊ณ ๋ฅผ ๋ฐฉ์งํ๋ ค๋ฉด S3 ์ ๊ทผ์ ์ด ์ ์ฑ
์ ์ ๋๋ก ์ดํดํ๊ณ ๊ตฌ์ฑํ๋ ๊ฒ ์ ๋ง ์ค์ํด.
๐ S3 ์ ๊ทผ์ ์ด์ ํต์ฌ ๊ฐ๋
S3 ์ ๊ทผ์ ์ด๋ฅผ ์ดํดํ๋ ค๋ฉด ๋จผ์ ๊ธฐ๋ณธ ๊ฐ๋ ๋ถํฐ ํ์คํ ์ก๊ณ ๊ฐ์ผ ํด. ๋ง์น ์ง์ ์ง์ ๋ ๊ธฐ์ด๊ณต์ฌ๊ฐ ์ค์ํ ๊ฒ์ฒ๋ผ ๋ง์ด์ผ! ๐๏ธ
๐ฆ S3์ ๊ธฐ๋ณธ ๊ตฌ์กฐ
S3๋ ๋ฒํท(Bucket)๊ณผ ๊ฐ์ฒด(Object)๋ผ๋ ๋ ๊ฐ์ง ํต์ฌ ์์๋ก ๊ตฌ์ฑ๋ผ ์์ด.
๋ฒํท์ ์ฝ๊ฒ ๋งํด์ ์ต์์ ํด๋ ๊ฐ์ ๊ฑฐ์ผ. ์ ์ธ๊ณ์์ ์ ์ผํ ์ด๋ฆ์ ๊ฐ์ ธ์ผ ํ๊ณ , ํ ๋ฒ ์์ฑํ๋ฉด ์ด๋ฆ์ ๋ฐ๊ฟ ์ ์์ด. ์๋ฅผ ๋ค์ด my-company-data-2024 ๊ฐ์ ์์ผ๋ก ๋ง๋ค ์ ์์ง.
๊ฐ์ฒด๋ ๋ฒํท ์์ ์ ์ฅ๋๋ ์ค์ ํ์ผ๋ค์ด์ผ. ์ด๋ฏธ์ง, ๋์์, ๋ฌธ์, ๋ก๊ทธ ํ์ผ ๋ฑ ๋ญ๋ ์ง ์ ์ฅํ ์ ์์ด. ๊ฐ ๊ฐ์ฒด๋ ํค(Key)๋ผ๋ ๊ณ ์ ์๋ณ์๋ฅผ ๊ฐ์ง๋๋ฐ, ์ด๊ฒ ์ฌ์ค์ ํ์ผ ๊ฒฝ๋ก๋ผ๊ณ ๋ณด๋ฉด ๋ผ.
๐ญ ์ ๊ทผ์ ์ด์ 4๊ฐ์ง ๋ ์ด์ด
S3 ์ ๊ทผ์ ์ด๋ ์ฌ๋ฌ ๋ ์ด์ด๋ก ๊ตฌ์ฑ๋์ด ์์ด. ๋ง์น ์ํ๊ป์ง์ฒ๋ผ ์ฌ๋ฌ ๊ฒน์ ๋ณด์ ์ฅ์น๊ฐ ์๋ ๊ฑฐ์ง! ๊ฐ ๋ ์ด์ด๋ฅผ ํ๋์ฉ ์ดํด๋ณผ๊ฒ.
1๏ธโฃ IAM ์ ์ฑ (Identity-Based Policies)
IAM ์ ์ฑ
์ ๋๊ฐ(Who) ๋ฌด์์ ํ ์ ์๋์ง๋ฅผ ์ ์ํด. AWS ๊ณ์ ์ ์ฌ์ฉ์, ๊ทธ๋ฃน, ์ญํ ์ ๋ถ์ฌ๋๋ ๊ถํ์ด์ผ.
์๋ฅผ ๋ค์ด๋ณผ๊ฒ. ๊ฐ๋ฐํ ์ง์์๊ฒ๋ ๊ฐ๋ฐ์ฉ ๋ฒํท์ ์ฝ๊ธฐ/์ฐ๊ธฐ ๊ถํ์ ์ฃผ๊ณ , ๋ง์ผํ
ํ์๊ฒ๋ ๋ง์ผํ
์๋ฃ ๋ฒํท์๋ง ์ฝ๊ธฐ ๊ถํ์ ์ฃผ๋ ์์ด์ง. ์ด๋ ๊ฒ ํ๋ฉด ๊ฐ ํ์ด ํ์ํ ๋ฆฌ์์ค์๋ง ์ ๊ทผํ ์ ์์ด์ ๋ณด์์ด ๊ฐํ๋ผ.
2๏ธโฃ ๋ฒํท ์ ์ฑ (Bucket Policies)
๋ฒํท ์ ์ฑ
์ ๋ฌด์์(What) ๋๊ฐ ํ ์ ์๋์ง๋ฅผ ๋ฆฌ์์ค ๊ด์ ์์ ์ ์ํด. IAM ์ ์ฑ
์ด ์ฌ์ฉ์ ์ค์ฌ์ด๋ผ๋ฉด, ๋ฒํท ์ ์ฑ
์ ๋ฆฌ์์ค ์ค์ฌ์ด์ผ.
๋ฒํท ์ ์ฑ
์ JSON ํ์์ผ๋ก ์์ฑ๋๋๋ฐ, ์ฒ์ ๋ณด๋ฉด ์ข ๋ณต์กํด ๋ณด์ผ ์ ์์ด. ํ์ง๋ง ๊ตฌ์กฐ๋ฅผ ์ดํดํ๋ฉด ์๊ฐ๋ณด๋ค ๊ฐ๋จํด! ๊ธฐ๋ณธ ๊ตฌ์กฐ๋ ์ด๋ ๊ฒ ์๊ฒผ์ด:
{
"Version": "2012-10-17",
"Statement": [
{
"Effect": "Allow",
"Principal": "*",
"Action": "s3:GetObject",
"Resource": "arn:aws:s3:::my-bucket/*"
}
]
}
์ด ์ ์ฑ ์ ๋ชจ๋ ์ฌ๋(Principal: "*")์ด my-bucket์ ๋ชจ๋ ๊ฐ์ฒด๋ฅผ ์ฝ์ ์ ์๋๋ก(Action: "s3:GetObject") ํ์ฉ(Effect: "Allow")ํ๋ค๋ ๋ป์ด์ผ. ๋ฌผ๋ก ์ค์ ์ด์ ํ๊ฒฝ์์๋ ์ด๋ ๊ฒ ์ด์ด๋๋ฉด ์ ๋๊ฒ ์ง? ๐
3๏ธโฃ ACL (Access Control Lists)
ACL์ S3์ ๋ ๊ฑฐ์ ์ ๊ทผ์ ์ด ๋ฐฉ์์ด์ผ. ์์ฆ์ ์ ์ฌ์ฉํ์ง ์๋ ํธ์ธ๋ฐ, ๊ทธ ์ด์ ๋ IAM ์ ์ฑ
๊ณผ ๋ฒํท ์ ์ฑ
์ด ํจ์ฌ ๋ ์ธ๋ฐํ๊ณ ๊ฐ๋ ฅํ ์ ์ด๋ฅผ ์ ๊ณตํ๊ธฐ ๋๋ฌธ์ด์ผ.
ACL์ ๋ฒํท ๋ ๋ฒจ๊ณผ ๊ฐ์ฒด ๋ ๋ฒจ์์ ์ค์ ํ ์ ์์ด. ์ฃผ๋ก ๋ค๋ฅธ AWS ๊ณ์ ์ ๊ฐ๋จํ ๊ถํ์ ๋ถ์ฌํ ๋ ์ฌ์ฉํ์์ง. ํ์ง๋ง AWS๋ ๊ณต์์ ์ผ๋ก ACL ๋์ ๋ฒํท ์ ์ฑ
์ฌ์ฉ์ ๊ถ์ฅํ๊ณ ์์ด.
4๏ธโฃ ๋ธ๋ก ํผ๋ธ๋ฆญ ์ก์ธ์ค (Block Public Access)
์ด๊ฑด 2018๋
์ ๋์
๋ ๋น๊ต์ ์ต์ ๊ธฐ๋ฅ์ด์ผ. S3 ๋ฒํท์ด ์ค์๋ก ๊ณต๊ฐ๋๋ ๊ฒ์ ๋ฐฉ์งํ๊ธฐ ์ํ ์์ ์ฅ์น๋ผ๊ณ ๋ณด๋ฉด ๋ผ. ๐จ
4๊ฐ์ง ์ค์ ์ต์
์ด ์์ด:
- BlockPublicAcls: ์๋ก์ด ํผ๋ธ๋ฆญ ACL ์ฐจ๋จ
- IgnorePublicAcls: ๊ธฐ์กด ํผ๋ธ๋ฆญ ACL ๋ฌด์
- BlockPublicPolicy: ์๋ก์ด ํผ๋ธ๋ฆญ ๋ฒํท ์ ์ฑ
์ฐจ๋จ
- RestrictPublicBuckets: ํผ๋ธ๋ฆญ ๋ฒํท ์ ์ฑ
์ด ์๋ ๋ฒํท์ ์ ๊ทผ ์ ํ
๊ธฐ๋ณธ์ ์ผ๋ก ์ด 4๊ฐ์ง๊ฐ ๋ชจ๋ ํ์ฑํ๋์ด ์์ด. ์น์ฌ์ดํธ ํธ์คํ
์ฒ๋ผ ์ ๋ง ํผ๋ธ๋ฆญ ์ ๊ทผ์ด ํ์ํ ๊ฒฝ์ฐ๊ฐ ์๋๋ผ๋ฉด, ์ด ์ค์ ์ ๊ทธ๋๋ก ์ ์งํ๋ ๊ฒ ์ข์!
๐ ๏ธ IAM ์ ์ฑ ์์ธ ๊ฐ์ด๋
์, ์ด์ ๋ณธ๊ฒฉ์ ์ผ๋ก ๊ฐ ์ ๊ทผ์ ์ด ๋ฐฉ์์ ๊น์ด ์๊ฒ ํํค์ณ๋ณผ ์๊ฐ์ด์ผ! ๋จผ์ IAM ์ ์ฑ ๋ถํฐ ์์ํด๋ณด์. ๐ช
๐ IAM ์ ์ฑ ์ ๊ตฌ์กฐ
IAM ์ ์ฑ ๋ JSON ํ์์ผ๋ก ์์ฑ๋ผ. ๊ธฐ๋ณธ ๊ตฌ์กฐ๋ฅผ ์ดํดํ๋ฉด ๋ณต์กํ ์ ์ฑ ๋ ์ฝ๊ฒ ๋ง๋ค ์ ์์ด. ์ฃผ์ ์์๋ค์ ์ดํด๋ณผ๊ฒ:
{
"Version": "2012-10-17",
"Statement": [
{
"Sid": "AllowS3ReadAccess",
"Effect": "Allow",
"Action": [
"s3:GetObject",
"s3:ListBucket"
],
"Resource": [
"arn:aws:s3:::my-bucket",
"arn:aws:s3:::my-bucket/*"
],
"Condition": {
"IpAddress": {
"aws:SourceIp": "203.0.113.0/24"
}
}
}
]
}
๊ฐ ์์๋ฅผ ํ๋์ฉ ๋ฏ์ด๋ณด์:
Version: ์ ์ฑ
์ธ์ด ๋ฒ์ ์ด์ผ. ๊ฑฐ์ ํญ์ "2012-10-17"์ ์ฌ์ฉํด. ์ด๊ฒ ์ต์ ๋ฒ์ ์ด๊ฑฐ๋ .
Statement: ์ค์ ๊ถํ ๊ท์น๋ค์ด ๋ค์ด๊ฐ๋ ๋ฐฐ์ด์ด์ผ. ์ฌ๋ฌ ๊ฐ์ ๊ท์น์ ์ ์ํ ์ ์์ด.
Sid: Statement ID์ ์ฝ์๋ก, ๊ฐ ๊ท์น์ ๋ถ์ด๋ ์ค๋ช
๋ผ๋ฒจ์ด์ผ. ์ ํ์ฌํญ์ด์ง๋ง ๊ด๋ฆฌํ๊ธฐ ํธํ๊ฒ ๋ถ์ฌ์ฃผ๋ ๊ฒ ์ข์.
Effect: "Allow" ๋๋ "Deny" ๋ ์ค ํ๋์ผ. ํด๋น ์ก์
์ ํ์ฉํ ์ง ๊ฑฐ๋ถํ ์ง ๊ฒฐ์ ํด.
Action: ํ์ฉํ๊ฑฐ๋ ๊ฑฐ๋ถํ AWS ์์
๋ค์ด์ผ. S3์ ๊ฒฝ์ฐ s3:GetObject, s3:PutObject ๊ฐ์ ์์ผ๋ก ์์ฑํด.
Resource: ์ ์ฑ
์ด ์ ์ฉ๋ AWS ๋ฆฌ์์ค๋ฅผ ARN(Amazon Resource Name) ํ์์ผ๋ก ์ง์ ํด.
Condition: ์ ํ์ ์ผ๋ก ์ถ๊ฐํ ์ ์๋ ์กฐ๊ฑด๋ฌธ์ด์ผ. IP ์ฃผ์, ์๊ฐ, MFA ์ธ์ฆ ์ฌ๋ถ ๋ฑ ๋ค์ํ ์กฐ๊ฑด์ ์ค์ ํ ์ ์์ด.
๐ฏ ์์ฃผ ์ฌ์ฉํ๋ S3 ์ก์ ๋ค
S3์์ ์ฌ์ฉํ ์ ์๋ ์ก์ ์ ์ ๋ง ๋ง์. ํ์ง๋ง ์ค๋ฌด์์ ์์ฃผ ์ฐ์ด๋ ๊ฒ๋ค๋ง ์ถ๋ ค๋ณด๋ฉด ์ด ์ ๋์ผ:
| ์ก์ | ์ค๋ช | ์ฌ์ฉ ์์ |
|---|---|---|
| s3:ListBucket | ๋ฒํท ๋ด ๊ฐ์ฒด ๋ชฉ๋ก ์กฐํ | ํ์ผ ํ์๊ธฐ์ฒ๋ผ ๋ฒํท ๋ด์ฉ ๋ณด๊ธฐ |
| s3:GetObject | ๊ฐ์ฒด ๋ค์ด๋ก๋/์ฝ๊ธฐ | ํ์ผ ๋ด์ฉ ์ฝ๊ธฐ, ๋ค์ด๋ก๋ |
| s3:PutObject | ๊ฐ์ฒด ์ ๋ก๋/์์ฑ | ์ ํ์ผ ์ ๋ก๋, ๊ธฐ์กด ํ์ผ ๋ฎ์ด์ฐ๊ธฐ |
| s3:DeleteObject | ๊ฐ์ฒด ์ญ์ | ํ์ผ ์ญ์ |
| s3:GetBucketLocation | ๋ฒํท ๋ฆฌ์ ์ ๋ณด ์กฐํ | ๋ฒํท์ด ์ด๋ ์ง์ญ์ ์๋์ง ํ์ธ |
| s3:ListAllMyBuckets | ๊ณ์ ์ ๋ชจ๋ ๋ฒํท ๋ชฉ๋ก ์กฐํ | ์์ ํ ๋ฒํท ์ ์ฒด ๋ฆฌ์คํธ ๋ณด๊ธฐ |
์์ผ๋์นด๋(*)๋ฅผ ์ฌ์ฉํ๋ฉด ์ฌ๋ฌ ์ก์ ์ ํ ๋ฒ์ ์ง์ ํ ์๋ ์์ด. ์๋ฅผ ๋ค์ด s3:Get*๋ GetObject, GetObjectVersion, GetBucketLocation ๋ฑ Get์ผ๋ก ์์ํ๋ ๋ชจ๋ ์ก์ ์ ํฌํจํด.
๐ ์ค์ IAM ์ ์ฑ ์์
์์ 1: ์ฝ๊ธฐ ์ ์ฉ ์ ๊ทผ ๊ถํ
๋ฐ์ดํฐ ๋ถ์ํ์๊ฒ ํน์ ๋ฒํท์ ๋ฐ์ดํฐ๋ฅผ ์ฝ์ ์๋ง ์๊ณ ์์ ์ ๋ชปํ๊ฒ ํ๊ณ ์ถ๋ค๋ฉด?
{
"Version": "2012-10-17",
"Statement": [
{
"Sid": "ReadOnlyAccess",
"Effect": "Allow",
"Action": [
"s3:GetObject",
"s3:GetObjectVersion",
"s3:ListBucket"
],
"Resource": [
"arn:aws:s3:::analytics-data-bucket",
"arn:aws:s3:::analytics-data-bucket/*"
]
}
]
}
์ด ์ ์ฑ ์ analytics-data-bucket์ ๊ฐ์ฒด๋ฅผ ์ฝ๊ณ ๋ชฉ๋ก์ ๋ณผ ์ ์์ง๋ง, ์ ๋ก๋๋ ์ญ์ ๋ ํ ์ ์์ด. ๊น๋ํ์ง? ๐
์์ 2: ํน์ ํด๋์๋ง ์ ๊ทผ ํ์ฉ
S3์๋ ์ค์ ๋ก ํด๋ ๊ฐ๋ ์ด ์์ง๋ง, ํค(๊ฒฝ๋ก)๋ฅผ ์ฌ์ฉํด์ ํด๋์ฒ๋ผ ๊ตฌ์กฐํํ ์ ์์ด. ์ฌ์ฉ์๋ณ๋ก ์๊ธฐ ํด๋์๋ง ์ ๊ทผํ๊ฒ ํ๋ ค๋ฉด:
{
"Version": "2012-10-17",
"Statement": [
{
"Sid": "AllowUserToSeeTheBucketInTheConsole",
"Effect": "Allow",
"Action": [
"s3:ListAllMyBuckets",
"s3:GetBucketLocation"
],
"Resource": "arn:aws:s3:::*"
},
{
"Sid": "AllowListingOfUserFolder",
"Effect": "Allow",
"Action": "s3:ListBucket",
"Resource": "arn:aws:s3:::user-data-bucket",
"Condition": {
"StringLike": {
"s3:prefix": [
"${aws:username}/*",
"${aws:username}"
]
}
}
},
{
"Sid": "AllowAllS3ActionsInUserFolder",
"Effect": "Allow",
"Action": "s3:*",
"Resource": "arn:aws:s3:::user-data-bucket/${aws:username}/*"
}
]
}
์ด ์ ์ฑ ์ ์ข ๋ณต์กํด ๋ณด์ด์ง๋ง, ์๋ฆฌ๋ ๊ฐ๋จํด. ${aws:username} ๋ณ์๋ฅผ ์ฌ์ฉํด์ ๊ฐ ์ฌ์ฉ์๊ฐ ์๊ธฐ ์ด๋ฆ์ ํด๋์๋ง ์ ๊ทผํ ์ ์๊ฒ ๋ง๋ ๊ฑฐ์ผ. ์๋ฅผ ๋ค์ด john์ด๋ผ๋ ์ฌ์ฉ์๋ user-data-bucket/john/ ๊ฒฝ๋ก์๋ง ์ ๊ทผํ ์ ์์ด.
์์ 3: ์๊ฐ ๊ธฐ๋ฐ ์ ๊ทผ ์ ์ด
์ ๋ฌด ์๊ฐ์๋ง S3 ์ ๊ทผ์ ํ์ฉํ๊ณ ์ถ๋ค๋ฉด? Condition์ ํ์ฉํ๋ฉด ๋ผ!
{
"Version": "2012-10-17",
"Statement": [
{
"Sid": "AllowAccessDuringBusinessHours",
"Effect": "Allow",
"Action": "s3:*",
"Resource": [
"arn:aws:s3:::company-data/*"
],
"Condition": {
"DateGreaterThan": {
"aws:CurrentTime": "2024-01-01T09:00:00Z"
},
"DateLessThan": {
"aws:CurrentTime": "2024-12-31T18:00:00Z"
}
}
}
]
}
๋ฌผ๋ก ์ค์ ๋ก๋ ๋งค์ผ ๋ฐ๋ณต๋๋ ์๊ฐ ์กฐ๊ฑด์ ์ค์ ํ๋ ค๋ฉด ๋ค๋ฅธ ๋ฐฉ์์ ์ฌ์ฉํด์ผ ํ์ง๋ง, ์ด๋ฐ ์์ผ๋ก ์๊ฐ ๊ธฐ๋ฐ ์ ์ด๊ฐ ๊ฐ๋ฅํ๋ค๋ ๊ฑธ ์ ์ ์์ด!
์์ 4: IP ์ฃผ์ ๊ธฐ๋ฐ ์ ๊ทผ ์ ์ด
ํ์ฌ ์ฌ๋ฌด์ค IP์์๋ง ์ ๊ทผ์ ํ์ฉํ๊ณ ์ถ์ ๋:
{
"Version": "2012-10-17",
"Statement": [
{
"Sid": "AllowFromOfficeIP",
"Effect": "Allow",
"Action": "s3:*",
"Resource": [
"arn:aws:s3:::secure-data-bucket",
"arn:aws:s3:::secure-data-bucket/*"
],
"Condition": {
"IpAddress": {
"aws:SourceIp": [
"203.0.113.0/24",
"198.51.100.0/24"
]
}
}
}
]
}
์ด๋ ๊ฒ ํ๋ฉด ์ง์ ๋ IP ๋์ญ์์๋ง ๋ฒํท์ ์ ๊ทผํ ์ ์์ด. ์ฌํ๊ทผ๋ฌด๊ฐ ๋ง์์ง ์์ฆ์๋ VPN๊ณผ ํจ๊ป ์ฌ์ฉํ๋ฉด ํจ๊ณผ์ ์ด์ผ! ๐ข
๐ซ Deny ์ ์ฑ ์ ํ์ฉ
AWS IAM์์๋ ๋ช ์์ Deny๊ฐ ๋ชจ๋ Allow๋ณด๋ค ์ฐ์ ์์๊ฐ ๋์. ์ด๊ฑธ ํ์ฉํ๋ฉด ๊ฐ๋ ฅํ ๋ณด์ ์ ์ฑ ์ ๋ง๋ค ์ ์์ด.
{
"Version": "2012-10-17",
"Statement": [
{
"Sid": "DenyDeleteActions",
"Effect": "Deny",
"Action": [
"s3:DeleteObject",
"s3:DeleteObjectVersion",
"s3:DeleteBucket"
],
"Resource": [
"arn:aws:s3:::critical-data-bucket",
"arn:aws:s3:::critical-data-bucket/*"
]
}
]
}
์ด ์ ์ฑ ์ ์ ์ฉํ๋ฉด, ๋ค๋ฅธ ์ ์ฑ ์์ ์ญ์ ๊ถํ์ ํ์ฉํ๋๋ผ๋ ์ด ๋ฒํท์ ๋ฐ์ดํฐ๋ ์ ๋ ์ญ์ ํ ์ ์์ด. ์ค์ํ ๋ฐ์ดํฐ๋ฅผ ๋ณดํธํ๋ ์ตํ์ ๋ฐฉ์ด์ ์ด ๋๋ ๊ฑฐ์ง! ๐ก๏ธ
๐ ์ ์ฑ ๋ณ์ ํ์ฉํ๊ธฐ
AWS๋ ์ ์ฑ ์์ ์ฌ์ฉํ ์ ์๋ ๋ค์ํ ๋ณ์๋ฅผ ์ ๊ณตํด. ์ด๊ฑธ ํ์ฉํ๋ฉด ๋์ ์ด๊ณ ์ ์ฐํ ์ ์ฑ ์ ๋ง๋ค ์ ์์ด:
| ๋ณ์ | ์ค๋ช | ์์ ๊ฐ |
|---|---|---|
| ${aws:username} | IAM ์ฌ์ฉ์ ์ด๋ฆ | john.doe |
| ${aws:userid} | IAM ์ฌ์ฉ์ ID | AIDAI23HXX2LO4example |
| ${aws:PrincipalTag/department} | ์ฌ์ฉ์์ ํ๊ทธ ๊ฐ | engineering |
| ${aws:CurrentTime} | ํ์ฌ ์๊ฐ | 2024-01-15T10:30:00Z |
| ${aws:SourceIp} | ์์ฒญ ์ถ์ฒ IP | 203.0.113.42 |
ํนํ ํ๊ทธ ๊ธฐ๋ฐ ์ ๊ทผ์ ์ด(TBAC)๋ ์์ฆ ๋ง์ด ์ฌ์ฉํ๋ ๋ฐฉ์์ด์ผ. ์ฌ์ฉ์๋ ๋ฆฌ์์ค์ ํ๊ทธ๋ฅผ ๋ถ์ด๊ณ , ๊ทธ ํ๊ทธ๋ฅผ ๊ธฐ๋ฐ์ผ๋ก ๊ถํ์ ๋ถ์ฌํ๋ ๊ฑฐ์ง.
{
"Version": "2012-10-17",
"Statement": [
{
"Sid": "AllowAccessBasedOnTags",
"Effect": "Allow",
"Action": "s3:*",
"Resource": "arn:aws:s3:::project-data-bucket/*",
"Condition": {
"StringEquals": {
"s3:ExistingObjectTag/project": "${aws:PrincipalTag/project}"
}
}
}
]
}
์ด ์ ์ฑ ์ ์ฌ์ฉ์์ project ํ๊ทธ์ ๊ฐ์ฒด์ project ํ๊ทธ๊ฐ ์ผ์นํ ๋๋ง ์ ๊ทผ์ ํ์ฉํด. ํ๋ก์ ํธ๋ณ๋ก ๋ฐ์ดํฐ๋ฅผ ๊ฒฉ๋ฆฌํ๊ณ ์ถ์ ๋ ์๋ฒฝํ ๋ฐฉ๋ฒ์ด์ผ! ๐ฏ
๐ ๋ฒํท ์ ์ฑ ๋ง์คํฐํ๊ธฐ
์ด์ ๋ฒํท ์ ์ฑ ์ผ๋ก ๋์ด๊ฐ๋ณผ๊น? IAM ์ ์ฑ ๊ณผ ๋น์ทํด ๋ณด์ด์ง๋ง, ์ฌ์ฉ ๋ชฉ์ ๊ณผ ์ ์ฉ ๋ฐฉ์์ด ๋ฌ๋ผ. ๋ฒํท ์ ์ฑ ์ ๋ฆฌ์์ค ๊ธฐ๋ฐ ์ ์ฑ ์ด๋ผ์ ๋ฒํท ์์ฒด์ ์ง์ ์ฐ๊ฒฐ๋ผ.
๐ IAM ์ ์ฑ vs ๋ฒํท ์ ์ฑ
๋์ ์ฐจ์ด๋ฅผ ๋ช ํํ ์ดํดํ๋ ๊ฒ ์ค์ํด. ํ๋ก ์ ๋ฆฌํด๋ณผ๊ฒ:
| ๊ตฌ๋ถ | IAM ์ ์ฑ | ๋ฒํท ์ ์ฑ |
|---|---|---|
| ์ฐ๊ฒฐ ๋์ | ์ฌ์ฉ์, ๊ทธ๋ฃน, ์ญํ | S3 ๋ฒํท |
| ๊ด์ | ์ ์(Identity) ์ค์ฌ | ๋ฆฌ์์ค(Resource) ์ค์ฌ |
| ํฌ๋ก์ค ๊ณ์ | ์ ํ์ | ์ฝ๊ฒ ๊ฐ๋ฅ |
| ํฌ๊ธฐ ์ ํ | 6,144์ (๊ด๋ฆฌํ ์ ์ฑ ) | 20KB |
| Principal ์ง์ | ๋ถ๊ฐ๋ฅ | ํ์ |
| ์ฃผ ์ฌ์ฉ ์ผ์ด์ค | ๋ด๋ถ ์ฌ์ฉ์ ๊ถํ ๊ด๋ฆฌ | ์ธ๋ถ ์ ๊ทผ, ํผ๋ธ๋ฆญ ์ ๊ทผ ์ ์ด |
๊ฐ๋จํ ๋งํ๋ฉด, IAM ์ ์ฑ ์ "์ด ์ฌ๋์ด ๋ญ ํ ์ ์๋?"๋ฅผ ์ ์ํ๊ณ , ๋ฒํท ์ ์ฑ ์ "์ด ๋ฒํท์ ๋๊ฐ ์ ๊ทผํ ์ ์๋?"๋ฅผ ์ ์ํ๋ ๊ฑฐ์ผ. ๐ค
๐ ํผ๋ธ๋ฆญ ์น์ฌ์ดํธ ํธ์คํ
S3๋ก ์ ์ ์น์ฌ์ดํธ๋ฅผ ํธ์คํ ํ๋ ๊ฑด ์ ๋ง ํํ ์ฌ์ฉ ์ฌ๋ก์ผ. ์ด๋ ํ์ํ ๋ฒํท ์ ์ฑ ์:
{
"Version": "2012-10-17",
"Statement": [
{
"Sid": "PublicReadGetObject",
"Effect": "Allow",
"Principal": "*",
"Action": "s3:GetObject",
"Resource": "arn:aws:s3:::my-website-bucket/*"
}
]
}
Principal: "*"๋ ๋ชจ๋ ์ฌ๋์ ์๋ฏธํด. ์ฆ, ์ธํฐ๋ท์ ๋๊ตฌ๋ ์ด ๋ฒํท์ ๊ฐ์ฒด๋ฅผ ์ฝ์ ์ ์๋ค๋ ๋ป์ด์ง. ๋ฌผ๋ก ์ด๋ ๊ฒ ์ค์ ํ๋ ค๋ฉด ๋ธ๋ก ํผ๋ธ๋ฆญ ์ก์ธ์ค ์ค์ ์ ํด์ ํด์ผ ํด.
ํ์ง๋ง ์์ฆ์ S3 ์น์ฌ์ดํธ ํธ์คํ
๋ณด๋ค CloudFront๋ฅผ ์์ ๋๊ณ S3๋ ํ๋ผ์ด๋น์ผ๋ก ์ ์งํ๋ ๊ฒ ๋ ์ผ๋ฐ์ ์ด์ผ. ์ฑ๋ฅ๋ ์ข๊ณ ๋ณด์๋ ๊ฐํ๋๊ฑฐ๋ ! ๐
๐ ํฌ๋ก์ค ๊ณ์ ์ ๊ทผ ์ค์
๋ค๋ฅธ AWS ๊ณ์ ์ ๋ฒํท ์ ๊ทผ ๊ถํ์ ์ฃผ๊ณ ์ถ์ ๋ ๋ฒํท ์ ์ฑ ์ด ๋น์ ๋ฐํด:
{
"Version": "2012-10-17",
"Statement": [
{
"Sid": "AllowCrossAccountAccess",
"Effect": "Allow",
"Principal": {
"AWS": "arn:aws:iam::123456789012:root"
},
"Action": [
"s3:GetObject",
"s3:PutObject"
],
"Resource": "arn:aws:s3:::shared-data-bucket/*"
}
]
}
์ฌ๊ธฐ์ 123456789012๋ ๋ค๋ฅธ AWS ๊ณ์ ID์ผ. ์ด๋ ๊ฒ ํ๋ฉด ํด๋น ๊ณ์ ์ ์ฌ์ฉ์๋ค์ด ์ด ๋ฒํท์ ์ ๊ทผํ ์ ์์ด. ํํธ๋์ฌ์ ๋ฐ์ดํฐ๋ฅผ ๊ณต์ ํ๊ฑฐ๋, ๋ฉํฐ ๊ณ์ ์ํคํ ์ฒ๋ฅผ ๊ตฌ์ฑํ ๋ ํ์์ ์ด์ผ!
ํฌ๋ก์ค ๊ณ์ ์ ๊ทผ์ ์ค์ ํ ๋๋ ๊ณ์ ์ ์ฒด(root)๋ณด๋ค๋ ํน์ ์ญํ (Role)์ ์ง์ ํ๋ ๊ฒ ๋ ์์ ํด. ์๋ฅผ ๋ค์ด:
"AWS": "arn:aws:iam::123456789012:role/DataAccessRole"
์ด๋ ๊ฒ ํ๋ฉด ๋ ์ธ๋ฐํ ์ ์ด๊ฐ ๊ฐ๋ฅํด!
๐ ์ํธํ ๊ฐ์ ํ๊ธฐ
๋ฐ์ดํฐ ๋ณด์์ ์ํด ์ํธํ๋์ง ์์ ๊ฐ์ฒด ์ ๋ก๋๋ฅผ ์ฐจ๋จํ๊ณ ์ถ๋ค๋ฉด:
{
"Version": "2012-10-17",
"Statement": [
{
"Sid": "DenyUnencryptedObjectUploads",
"Effect": "Deny",
"Principal": "*",
"Action": "s3:PutObject",
"Resource": "arn:aws:s3:::secure-bucket/*",
"Condition": {
"StringNotEquals": {
"s3:x-amz-server-side-encryption": [
"AES256",
"aws:kms"
]
}
}
}
]
}
์ด ์ ์ฑ ์ ์๋ฒ ์ธก ์ํธํ ํค๋๊ฐ ์๋ ์ ๋ก๋๋ฅผ ๋ชจ๋ ๊ฑฐ๋ถํด. AES256(S3 ๊ด๋ฆฌํ ํค) ๋๋ aws:kms(KMS ๊ด๋ฆฌํ ํค) ์ํธํ๋ฅผ ์ฌ์ฉํด์ผ๋ง ์ ๋ก๋๊ฐ ๊ฐ๋ฅํด์ง๋ ๊ฑฐ์ง. ๐ช
๐ ์ง์ญ ๊ธฐ๋ฐ ์ ๊ทผ ์ ์ด
ํน์ ๊ตญ๊ฐ์์๋ง ์ ๊ทผ์ ํ์ฉํ๊ณ ์ถ์ ๋๋ ์์ด. GDPR ๊ฐ์ ๊ท์ ์ค์๋ฅผ ์ํด์ ๋ง์ด์ผ:
{
"Version": "2012-10-17",
"Statement": [
{
"Sid": "AllowOnlyFromSpecificCountries",
"Effect": "Deny",
"Principal": "*",
"Action": "s3:*",
"Resource": [
"arn:aws:s3:::eu-data-bucket",
"arn:aws:s3:::eu-data-bucket/*"
],
"Condition": {
"StringNotEquals": {
"aws:RequestedRegion": [
"eu-west-1",
"eu-central-1"
]
}
}
}
]
}
์ด ์ ์ฑ ์ EU ๋ฆฌ์ ์์์ ์์ฒญ๋ง ํ์ฉํ๊ณ ๋๋จธ์ง๋ ๋ชจ๋ ์ฐจ๋จํด. ๋ฐ์ดํฐ ์ฃผ๊ถ(Data Sovereignty) ์๊ตฌ์ฌํญ์ ์ถฉ์กฑ์ํฌ ์ ์์ด!
๐ MFA ์ธ์ฆ ๊ฐ์
์ค์ํ ์์ ์๋ MFA(๋ค์ค ์ธ์ฆ)๋ฅผ ์๊ตฌํ ์ ์์ด:
{
"Version": "2012-10-17",
"Statement": [
{
"Sid": "RequireMFAForDelete",
"Effect": "Deny",
"Principal": "*",
"Action": [
"s3:DeleteObject",
"s3:DeleteBucket"
],
"Resource": [
"arn:aws:s3:::critical-bucket",
"arn:aws:s3:::critical-bucket/*"
],
"Condition": {
"BoolIfExists": {
"aws:MultiFactorAuthPresent": "false"
}
}
}
]
}
์ด๋ ๊ฒ ํ๋ฉด MFA ์ธ์ฆ ์์ด๋ ์ ๋ ์ญ์ ํ ์ ์์ด. ์ค์๋ก ์ค์ํ ๋ฐ์ดํฐ๋ฅผ ์ง์ฐ๋ ์ฌ๊ณ ๋ฅผ ์๋ฐฉํ ์ ์์ง! ๐
๐จ ๋ณต์กํ ์กฐ๊ฑด ์กฐํฉํ๊ธฐ
์ฌ๋ฌ ์กฐ๊ฑด์ ์กฐํฉํ๋ฉด ์ ๋ง ์ธ๋ฐํ ์ ์ด๊ฐ ๊ฐ๋ฅํด. ์๋ฅผ ๋ค์ด๋ณผ๊ฒ:
{
"Version": "2012-10-17",
"Statement": [
{
"Sid": "ComplexConditionExample",
"Effect": "Allow",
"Principal": {
"AWS": "arn:aws:iam::123456789012:role/AppRole"
},
"Action": "s3:GetObject",
"Resource": "arn:aws:s3:::app-data-bucket/*",
"Condition": {
"IpAddress": {
"aws:SourceIp": "203.0.113.0/24"
},
"StringEquals": {
"s3:ExistingObjectTag/classification": "public"
},
"DateGreaterThan": {
"aws:CurrentTime": "2024-01-01T00:00:00Z"
},
"DateLessThan": {
"aws:CurrentTime": "2024-12-31T23:59:59Z"
}
}
}
]
}
์ด ์ ์ฑ
์:
- ํน์ ์ญํ (AppRole)์ด
- ํน์ IP ๋์ญ(203.0.113.0/24)์์
- public์ผ๋ก ํ๊ทธ๋ ๊ฐ์ฒด๋ง
- 2024๋
๋์๋ง
์ฝ์ ์ ์๊ฒ ํด. ์์ฒญ ๊ตฌ์ฒด์ ์ด์ง? ๐
๐ญ S3 ์ก์ธ์ค ํฌ์ธํธ ํ์ฉํ๊ธฐ
S3 ์ก์ธ์ค ํฌ์ธํธ๋ 2019๋ ์ ๋์ ๋ ๋น๊ต์ ์๋ก์ด ๊ธฐ๋ฅ์ด์ผ. ๋ณต์กํ ๋ฒํท ์ ์ฑ ์ ๋จ์ํํ๊ณ , ๋๊ท๋ชจ ์ ํ๋ฆฌ์ผ์ด์ ์ ์ ๊ทผ ๊ด๋ฆฌ๋ฅผ ์ฝ๊ฒ ๋ง๋ค์ด์ค. ๐ฏ
๐ค ์ก์ธ์ค ํฌ์ธํธ๊ฐ ๋ญ์ผ?
๊ฐ๋จํ ๋งํ๋ฉด, ํ๋์ ๋ฒํท์ ์ฌ๋ฌ ๊ฐ์ "์ถ์
๊ตฌ"๋ฅผ ๋ง๋๋ ๊ฑฐ์ผ. ๊ฐ ์ถ์
๊ตฌ๋ง๋ค ๋ค๋ฅธ ์ ์ฑ
์ ์ ์ฉํ ์ ์์ด์, ๋ณต์กํ ๋ฒํท ์ ์ฑ
์ ์ฌ๋ฌ ๊ฐ์ ๊ฐ๋จํ ์ ์ฑ
์ผ๋ก ๋๋ ์ ์์ง.
์๋ฅผ ๋ค์ด๋ณผ๊ฒ. ํ๋์ ๋ฐ์ดํฐ ๋ ์ดํฌ ๋ฒํท์ด ์๋๋ฐ:
- ๋ถ์ํ์ /analytics ๊ฒฝ๋ก๋ง ์ฝ๊ธฐ
- ๊ฐ๋ฐํ์ /development ๊ฒฝ๋ก์ ์ฝ๊ธฐ/์ฐ๊ธฐ
- ๋ง์ผํ
ํ์ /marketing ๊ฒฝ๋ก๋ง ์ฝ๊ธฐ
์ด๊ฑธ ํ๋์ ๋ฒํท ์ ์ฑ
์ผ๋ก ๊ด๋ฆฌํ๋ฉด ์ ๋ง ๋ณต์กํด์ ธ. ํ์ง๋ง ์ก์ธ์ค ํฌ์ธํธ๋ฅผ ์ฌ์ฉํ๋ฉด ๊ฐ ํ๋ณ๋ก ๋
๋ฆฝ์ ์ธ ์ ์ฑ
์ ๋ง๋ค ์ ์์ด!
๐ ๏ธ ์ก์ธ์ค ํฌ์ธํธ ์์ฑํ๊ธฐ
AWS CLI๋ก ์ก์ธ์ค ํฌ์ธํธ๋ฅผ ๋ง๋๋ ๋ฐฉ๋ฒ:
aws s3control create-access-point \
--account-id 123456789012 \
--name analytics-access-point \
--bucket data-lake-bucket \
--vpc-configuration VpcId=vpc-12345678
๊ทธ๋ฆฌ๊ณ ๊ฐ ์ก์ธ์ค ํฌ์ธํธ์ ์ ์ฑ ์ ์ ์ฉํด:
{
"Version": "2012-10-17",
"Statement": [
{
"Effect": "Allow",
"Principal": {
"AWS": "arn:aws:iam::123456789012:role/AnalyticsRole"
},
"Action": [
"s3:GetObject",
"s3:ListBucket"
],
"Resource": [
"arn:aws:s3:us-east-1:123456789012:accesspoint/analytics-access-point",
"arn:aws:s3:us-east-1:123456789012:accesspoint/analytics-access-point/object/analytics/*"
]
}
]
}
์ด์ ๋ถ์ํ์ ์ด ์ก์ธ์ค ํฌ์ธํธ๋ฅผ ํตํด์๋ง ๋ฒํท์ ์ ๊ทผํ๋ฉด ๋ผ. ์๋์ผ๋ก /analytics ๊ฒฝ๋ก๋ง ๋ณผ ์ ์๊ฒ ๋๋ ๊ฑฐ์ง!
๐ VPC ์ ์ฉ ์ก์ธ์ค ํฌ์ธํธ
์ก์ธ์ค ํฌ์ธํธ๋ฅผ ํน์ VPC์์๋ง ์ฌ์ฉํ๋๋ก ์ ํํ ์๋ ์์ด. ์ด๋ ๊ฒ ํ๋ฉด ์ธํฐ๋ท์ ํตํ ์ ๊ทผ์ ์์ ํ ์ฐจ๋จํ๊ณ , VPC ๋ด๋ถ์์๋ง S3์ ์ ๊ทผํ ์ ์๊ฒ ๋ผ:
{
"Version": "2012-10-17",
"Statement": [
{
"Effect": "Allow",
"Principal": "*",
"Action": "s3:*",
"Resource": [
"arn:aws:s3:us-east-1:123456789012:accesspoint/internal-access-point",
"arn:aws:s3:us-east-1:123456789012:accesspoint/internal-access-point/object/*"
],
"Condition": {
"StringEquals": {
"s3:DataAccessPointAccount": "123456789012"
}
}
}
]
}
์ด๊ฑด ํนํ ๋ฏผ๊ฐํ ๋ฐ์ดํฐ๋ฅผ ๋ค๋ฃฐ ๋ ์ ์ฉํด. ์ธ๋ถ ์ธํฐ๋ท ๋ ธ์ถ ์ํ์ ์์ ํ ์ ๊ฑฐํ ์ ์๊ฑฐ๋ ! ๐
๐ ๋ฉํฐ ๋ฆฌ์ ์ก์ธ์ค ํฌ์ธํธ
2021๋
์ ์ถ๊ฐ๋ ๋ฉํฐ ๋ฆฌ์ ์ก์ธ์ค ํฌ์ธํธ๋ ์ ๋ง ํ์ ์ ์ด์ผ. ์ฌ๋ฌ ๋ฆฌ์ ์ ๋ฒํท์ ํ๋์ ๊ธ๋ก๋ฒ ์๋ํฌ์ธํธ๋ก ํตํฉํ ์ ์์ด.
์๋ฅผ ๋ค์ด ๋ฏธ๊ตญ, ์ ๋ฝ, ์์์์ ๊ฐ๊ฐ ๋ฒํท์ด ์๋ค๋ฉด, ๋ฉํฐ ๋ฆฌ์ ์ก์ธ์ค ํฌ์ธํธ๋ฅผ ๋ง๋ค์ด์ ๊ฐ์ฅ ๊ฐ๊น์ด ๋ฒํท์ผ๋ก ์๋ ๋ผ์ฐํ
ํ ์ ์์ด. ๋ ์ดํด์๊ฐ ํ ์ค์ด๋ค์ง! ๐
aws s3control create-multi-region-access-point \
--account-id 123456789012 \
--details '{
"Name": "global-data-access",
"Regions": [
{"Bucket": "data-us-east-1"},
{"Bucket": "data-eu-west-1"},
{"Bucket": "data-ap-northeast-1"}
]
}'
์ ํ๋ฆฌ์ผ์ด์ ์ฝ๋๋ ํ๋์ ์๋ํฌ์ธํธ๋ง ์ฌ์ฉํ๋ฉด ๋๊ณ , AWS๊ฐ ์์์ ์ต์ ์ ๋ฒํท์ผ๋ก ์ฐ๊ฒฐํด์ค. ๊ธ๋ก๋ฒ ์๋น์ค๋ฅผ ์ด์ํ๋ค๋ฉด ์ ๋ง ์ ์ฉํ ๊ธฐ๋ฅ์ด์ผ!
๐ S3 Object Lock๊ณผ ๋ฒ์ ๊ด๋ฆฌ
๋ฐ์ดํฐ ๋ณดํธ์ ๋ ๋ค๋ฅธ ์ค์ํ ์ธก๋ฉด์ ์ค์๋ ์ ์์ ์ธ ์ญ์ ๋ก๋ถํฐ ๋ฐ์ดํฐ๋ฅผ ์งํค๋ ๊ฑฐ์ผ. S3๋ ์ด๋ฅผ ์ํ ๊ฐ๋ ฅํ ๊ธฐ๋ฅ๋ค์ ์ ๊ณตํด!
๐ ๋ฒ์ ๊ด๋ฆฌ (Versioning)
S3 ๋ฒ์ ๊ด๋ฆฌ๋ฅผ ํ์ฑํํ๋ฉด ๊ฐ์ฒด์ ๋ชจ๋ ๋ฒ์ ์ด ๋ณด์กด๋ผ. ํ์ผ์ ๋ฎ์ด์ฐ๊ฑฐ๋ ์ญ์ ํด๋ ์ด์ ๋ฒ์ ์ ๋ณต๊ตฌํ ์ ์์ด. ๋ง์น Git์ฒ๋ผ ๋ง์ด์ผ! ๐
๋ฒ์ ๊ด๋ฆฌ๋ฅผ ํ์ฑํํ๋ ๊ฑด ๊ฐ๋จํด:
aws s3api put-bucket-versioning \
--bucket my-bucket \
--versioning-configuration Status=Enabled
๋ฒ์ ๊ด๋ฆฌ๊ฐ ํ์ฑํ๋๋ฉด:
- ํ์ผ์ ์
๋ก๋ํ ๋๋ง๋ค ์ ๋ฒ์ ID๊ฐ ์์ฑ๋ผ
- ์ญ์ ํด๋ ์ค์ ๋ก๋ ์ญ์ ๋ง์ปค๋ง ์ถ๊ฐ๋ผ
- ์ธ์ ๋ ์ด์ ๋ฒ์ ์ผ๋ก ๋กค๋ฐฑ ๊ฐ๋ฅํด
๋จ์ ์? ์คํ ๋ฆฌ์ง ๋น์ฉ์ด ์ฆ๊ฐํ๋ค๋ ๊ฑฐ์ผ. ๋ชจ๋ ๋ฒ์ ์ ์ ์ฅํ๋๊น ๋น์ฐํ์ง. ๊ทธ๋์ ๋ผ์ดํ์ฌ์ดํด ์ ์ฑ
๊ณผ ํจ๊ป ์ฌ์ฉํด์ ์ค๋๋ ๋ฒ์ ์ ์๋์ผ๋ก ์ญ์ ํ๋ ๊ฒ ์ข์.
๐ S3 Object Lock
Object Lock์ WORM(Write Once Read Many) ๋ชจ๋ธ์ ๊ตฌํํด. ํ ๋ฒ ์ฐ๋ฉด ์ง์ ๋ ๊ธฐ๊ฐ ๋์ ์ ๋ ์์ ํ๊ฑฐ๋ ์ญ์ ํ ์ ์์ด. ๊ท์ ์ค์๊ฐ ์ค์ํ ์ฐ์
(๊ธ์ต, ์๋ฃ ๋ฑ)์์ ํ์์ ์ด์ผ! ๐๏ธ
Object Lock์๋ ๋ ๊ฐ์ง ๋ชจ๋๊ฐ ์์ด:
1๏ธโฃ Governance ๋ชจ๋
ํน๋ณํ ๊ถํ์ ๊ฐ์ง ์ฌ์ฉ์๋ ๋ณดํธ๋ฅผ ํด์ ํ๊ฑฐ๋ ๋ณด์กด ๊ธฐ๊ฐ์ ๋ณ๊ฒฝํ ์ ์์ด. ๋๋ถ๋ถ์ ์ฌ์ฉ์๋ ๋ณดํธ๋์ง๋ง, ๊ด๋ฆฌ์๋ ํ์์ ์์ ํ ์ ์๋ ๊ฑฐ์ง.
2๏ธโฃ Compliance ๋ชจ๋
๋ฃจํธ ์ฌ์ฉ์๋ฅผ ํฌํจํด์ ๋๊ตฌ๋ ๋ณดํธ๋ฅผ ํด์ ํ ์ ์์ด. ๋ณด์กด ๊ธฐ๊ฐ์ด ๋๋ ๋๊น์ง ์ ๋์ ์ผ๋ก ๋ณดํธ๋ผ. ๋ฒ์ ์๊ตฌ์ฌํญ์ ์ถฉ์กฑ์ํฌ ๋ ์ฌ์ฉํด.
Object Lock์ ์ค์ ํ๋ ๋ฐฉ๋ฒ:
aws s3api put-object-lock-configuration \
--bucket compliance-bucket \
--object-lock-configuration '{
"ObjectLockEnabled": "Enabled",
"Rule": {
"DefaultRetention": {
"Mode": "COMPLIANCE",
"Days": 365
}
}
}'
์ด๋ ๊ฒ ํ๋ฉด ์ ๋ก๋๋๋ ๋ชจ๋ ๊ฐ์ฒด๊ฐ 1๋ ๋์ ์๋์ผ๋ก ์ ๊ฒจ. ๊ธ์ต ๊ฑฐ๋ ๊ธฐ๋ก์ด๋ ์๋ฃ ๊ธฐ๋ก์ฒ๋ผ ๋ฒ์ ์ผ๋ก ๋ณด์กด ๊ธฐ๊ฐ์ด ์ ํด์ง ๋ฐ์ดํฐ์ ์๋ฒฝํด! ๐
โ๏ธ Legal Hold
Legal Hold๋ ๋ณด์กด ๊ธฐ๊ฐ๊ณผ ๋ฌด๊ดํ๊ฒ ๊ฐ์ฒด๋ฅผ ๋ฌด๊ธฐํ ๋ณดํธํ ์ ์์ด. ์์ก์ด๋ ์กฐ์ฌ๊ฐ ์งํ ์ค์ผ ๋ ์ฆ๊ฑฐ ์๋ฃ๋ฅผ ๋ณดํธํ๋ ์ฉ๋๋ก ์ฌ์ฉํด:
aws s3api put-object-legal-hold \
--bucket evidence-bucket \
--key important-document.pdf \
--legal-hold Status=ON
Legal Hold๊ฐ ์ค์ ๋๋ฉด s3:PutObjectLegalHold ๊ถํ์ ๊ฐ์ง ์ฌ์ฉ์๋ง ํด์ ํ ์ ์์ด. ๋ณด์กด ๊ธฐ๊ฐ์ด ๋๋๋ Legal Hold๊ฐ ํ์ฑํ๋์ด ์์ผ๋ฉด ์ญ์ ํ ์ ์์ง.
๐ S3 ์ ๊ทผ ๋ก๊น ๊ณผ ๋ชจ๋ํฐ๋ง
์๋ฌด๋ฆฌ ์๋ฒฝํ ์ ๊ทผ์ ์ด ์ ์ฑ ์ ๋ง๋ค์ด๋, ์ค์ ๋ก ์ด๋ค ์ผ์ด ์ผ์ด๋๋์ง ๋ชจ๋ํฐ๋งํ์ง ์์ผ๋ฉด ์์ฉ์์ด. ๋ก๊น ๊ณผ ๋ชจ๋ํฐ๋ง์ ๋ณด์์ ํต์ฌ์ด์ผ! ๐
๐ S3 ์๋ฒ ์ก์ธ์ค ๋ก๊น
S3 ์๋ฒ ์ก์ธ์ค ๋ก๊น ์ ํ์ฑํํ๋ฉด ๋ฒํท์ ๋ํ ๋ชจ๋ ์์ฒญ์ด ๊ธฐ๋ก๋ผ. ๋๊ฐ, ์ธ์ , ์ด๋ค ์์ ์ ํ๋์ง ์์ธํ๊ฒ ์ ์ ์์ด:
aws s3api put-bucket-logging \
--bucket my-bucket \
--bucket-logging-status '{
"LoggingEnabled": {
"TargetBucket": "my-logs-bucket",
"TargetPrefix": "s3-access-logs/"
}
}'
๋ก๊ทธ ํ์ผ์ ์ด๋ฐ ํ์์ผ๋ก ์ ์ฅ๋ผ:
79a59df900b949e55d96a1e698fbacedfd6e09d98eacf8f8d5218e7cd47ef2be my-bucket [06/Feb/2024:00:00:01 +0000] 192.0.2.3 79a59df900b949e55d96a1e698fbacedfd6e09d98eacf8f8d5218e7cd47ef2be 3E57427F3EXAMPLE REST.GET.VERSIONING - "GET /my-bucket?versioning HTTP/1.1" 200 - 113 - 7 - "-" "S3Console/0.4" - s9lzHYrFp76ZVxRcpX9+5cjAnEH2ROuNkd2BHfIa6UkFVdtjf5mKR3/eTPFvsiP/XV/VLi31234= SigV2 ECDHE-RSA-AES128-GCM-SHA256 AuthHeader my-bucket.s3.amazonaws.com TLSV1.2
๋ณต์กํด ๋ณด์ด์ง๋ง, ๊ฐ ํ๋๊ฐ ์๋ฏธํ๋ ๋ฐ๋ฅผ ์๋ฉด ์ ์ฉํ ์ ๋ณด๊ฐ ๋ง์:
- ์์ฒญ์ IP ์ฃผ์
- ์์ฒญ ์๊ฐ
- ์ํ๋ ์์
- HTTP ์ํ ์ฝ๋
- ์๋ฌ ์ฝ๋ (์๋ค๋ฉด)
- ์ ์ก๋ ๋ฐ์ดํธ ์
์ด ๋ก๊ทธ๋ฅผ ๋ถ์ํ๋ฉด ๋น์ ์์ ์ธ ์ ๊ทผ ํจํด์ ์ฐพ์๋ผ ์ ์์ด!
๐ AWS CloudTrail
CloudTrail์ AWS API ํธ์ถ์ ๊ธฐ๋กํด. S3 ์๋ฒ ์ก์ธ์ค ๋ก๊ทธ๋ณด๋ค ๋ ์์ธํ ์ ๋ณด๋ฅผ ์ ๊ณตํ๊ณ , ๊ด๋ฆฌ ์ด๋ฒคํธ์ ๋ฐ์ดํฐ ์ด๋ฒคํธ๋ฅผ ๋ชจ๋ ์ถ์ ํ ์ ์์ด.
ํนํ S3 ๋ฐ์ดํฐ ์ด๋ฒคํธ ๋ก๊น
์ ํ์ฑํํ๋ฉด:
aws cloudtrail put-event-selectors \
--trail-name my-trail \
--event-selectors '[
{
"ReadWriteType": "All",
"IncludeManagementEvents": true,
"DataResources": [
{
"Type": "AWS::S3::Object",
"Values": ["arn:aws:s3:::my-bucket/*"]
}
]
}
]'
CloudTrail ๋ก๊ทธ๋ JSON ํ์์ด๋ผ ํ์ฑํ๊ธฐ ์ฌ์:
{
"eventVersion": "1.08",
"userIdentity": {
"type": "IAMUser",
"principalId": "AIDAI23HXX2LO4example",
"arn": "arn:aws:iam::123456789012:user/Alice",
"accountId": "123456789012",
"userName": "Alice"
},
"eventTime": "2024-01-15T10:30:00Z",
"eventSource": "s3.amazonaws.com",
"eventName": "GetObject",
"awsRegion": "us-east-1",
"sourceIPAddress": "203.0.113.42",
"requestParameters": {
"bucketName": "my-bucket",
"key": "sensitive-data.csv"
},
"responseElements": null,
"requestID": "EXAMPLE123456789",
"eventID": "EXAMPLE-8752-4fc8-b0e6-example",
"readOnly": true,
"resources": [
{
"type": "AWS::S3::Object",
"ARN": "arn:aws:s3:::my-bucket/sensitive-data.csv"
}
],
"eventType": "AwsApiCall",
"recipientAccountId": "123456789012"
}
์ด ์ ๋ณด๋ก ๋๊ฐ(Alice), ์ธ์ (2024-01-15 10:30), ์ด๋์(203.0.113.42), ๋ฌด์์(sensitive-data.csv ์ฝ๊ธฐ) ํ๋์ง ์ ํํ ์ ์ ์์ด! ๐ต๏ธ
๐ Amazon Macie๋ก ๋ฏผ๊ฐ ๋ฐ์ดํฐ ํ์ง
Amazon Macie๋ ๋จธ์ ๋ฌ๋์ ์ฌ์ฉํด์ S3์ ์ ์ฅ๋ ๋ฏผ๊ฐํ ๋ฐ์ดํฐ๋ฅผ ์๋์ผ๋ก ์ฐพ์๋ด. ๊ฐ์ธ์ ๋ณด, ์ ์ฉ์นด๋ ๋ฒํธ, API ํค ๊ฐ์ ๊ฑธ ํ์งํ ์ ์์ด.
Macie๋ฅผ ํ์ฑํํ๋ฉด:
aws macie2 enable-macie
๊ทธ๋ฆฌ๊ณ ๋ถ๋ฅ ์์ ์ ์์ฑํด:
aws macie2 create-classification-job \
--job-type ONE_TIME \
--s3-job-definition '{
"bucketDefinitions": [
{
"accountId": "123456789012",
"buckets": ["my-bucket"]
}
]
}' \
--name "Sensitive Data Discovery" \
--description "Find PII in my-bucket"
Macie๋ ์๋์ผ๋ก ๋ฒํท์ ์ค์บํ๊ณ , ๋ฐ๊ฒฌํ ๋ฏผ๊ฐ ๋ฐ์ดํฐ๋ฅผ ๋ฆฌํฌํธํด์ค. ์ค์๋ก ๋ฏผ๊ฐํ ์ ๋ณด๊ฐ ๋ ธ์ถ๋๋ ๊ฑธ ๋ฐฉ์งํ ์ ์์ง! ๐ก๏ธ
โก Amazon GuardDuty
GuardDuty๋ ์ํ ํ์ง ์๋น์ค์ผ. CloudTrail ๋ก๊ทธ, VPC Flow Logs, DNS ๋ก๊ทธ๋ฅผ ๋ถ์ํด์ ์์ฌ์ค๋ฌ์ด ํ๋์ ์ฐพ์๋ด.
S3 ๊ด๋ จํด์๋ ์ด๋ฐ ์ํ์ ํ์งํ ์ ์์ด:
- ๋น์ ์์ ์ธ API ํธ์ถ ํจํด
- ์ต๋ช
์ฌ์ฉ์์ ์ ๊ทผ ์๋
- ์๋ ค์ง ์
์ฑ IP์์์ ์ ๊ทผ
- ๋๋ ๋ฐ์ดํฐ ์ ์ถ ์๋
GuardDuty๊ฐ ์ํ์ ํ์งํ๋ฉด ์๋์ผ๋ก ์๋ฆผ์ ๋ณด๋ด์ค. EventBridge์ ์ฐ๋ํ๋ฉด ์๋ ๋์๋ ๊ฐ๋ฅํด!
๐ฏ ์ค์ ์๋๋ฆฌ์ค๋ณ ์ ๊ทผ์ ์ด ๊ตฌ์ฑ
์ด๋ก ์ ์ถฉ๋ถํ ๋ฐฐ์ ์ผ๋, ์ด์ ์ค์ ์ํฉ์์ ์ด๋ป๊ฒ ์ ์ฉํ๋์ง ์ดํด๋ณด์! ๋ค์ํ ์๋๋ฆฌ์ค๋ฅผ ์ค๋นํ์ด. ๐ฌ
๐ข ์๋๋ฆฌ์ค 1: ๊ธฐ์ ๋ฐ์ดํฐ ๋ ์ดํฌ
๋๊ธฐ์
์์ ๋ฐ์ดํฐ ๋ ์ดํฌ๋ฅผ ๊ตฌ์ถํ๋ค๊ณ ๊ฐ์ ํด๋ณด์. ์ฌ๋ฌ ๋ถ์๊ฐ ๊ฐ์ ๋ฒํท์ ์ฌ์ฉํ์ง๋ง, ๊ฐ์ ์๊ธฐ ๋ถ์ ๋ฐ์ดํฐ๋ง ์ ๊ทผํ ์ ์์ด์ผ ํด.
์๊ตฌ์ฌํญ:
- ๊ฐ ๋ถ์๋ ์๊ธฐ ํด๋์๋ง ์ ๊ทผ
- ๋ฐ์ดํฐ ๊ณผํํ์ ๋ชจ๋ ๋ฐ์ดํฐ ์ฝ๊ธฐ ๊ฐ๋ฅ
- ์ญ์ ๋ ๊ด๋ฆฌ์๋ง ๊ฐ๋ฅ
- ๋ชจ๋ ์ ๊ทผ์ VPC ๋ด๋ถ์์๋ง
ํด๊ฒฐ ๋ฐฉ๋ฒ:
1. ๋จผ์ ๋ถ์๋ณ IAM ์ญํ ์ ๋ง๋ค์ด:
{
"Version": "2012-10-17",
"Statement": [
{
"Effect": "Allow",
"Action": [
"s3:ListBucket"
],
"Resource": "arn:aws:s3:::company-datalake",
"Condition": {
"StringLike": {
"s3:prefix": [
"${aws:PrincipalTag/department}/*"
]
}
}
},
{
"Effect": "Allow",
"Action": [
"s3:GetObject",
"s3:PutObject"
],
"Resource": "arn:aws:s3:::company-datalake/${aws:PrincipalTag/department}/*"
}
]
}
2. ๋ฐ์ดํฐ ๊ณผํํ์๋ ๋ณ๋ ์ ์ฑ :
{
"Version": "2012-10-17",
"Statement": [
{
"Effect": "Allow",
"Action": [
"s3:GetObject",
"s3:ListBucket"
],
"Resource": [
"arn:aws:s3:::company-datalake",
"arn:aws:s3:::company-datalake/*"
]
}
]
}
3. ๋ฒํท ์ ์ฑ ์ผ๋ก VPC ์ ํ๊ณผ ์ญ์ ๋ฐฉ์ง:
{
"Version": "2012-10-17",
"Statement": [
{
"Sid": "VPCOnly",
"Effect": "Deny",
"Principal": "*",
"Action": "s3:*",
"Resource": [
"arn:aws:s3:::company-datalake",
"arn:aws:s3:::company-datalake/*"
],
"Condition": {
"StringNotEquals": {
"aws:SourceVpc": "vpc-12345678"
}
}
},
{
"Sid": "DenyDeleteExceptAdmin",
"Effect": "Deny",
"NotPrincipal": {
"AWS": "arn:aws:iam::123456789012:role/AdminRole"
},
"Action": [
"s3:DeleteObject",
"s3:DeleteBucket"
],
"Resource": [
"arn:aws:s3:::company-datalake",
"arn:aws:s3:::company-datalake/*"
]
}
]
}
์ด๋ ๊ฒ ๊ตฌ์ฑํ๋ฉด ๊ฐ ๋ถ์๋ ์๊ธฐ ๋ฐ์ดํฐ๋ง ๊ด๋ฆฌํ๊ณ , ๋ฐ์ดํฐ ๊ณผํํ์ ๋ถ์์ ์ํด ๋ชจ๋ ๋ฐ์ดํฐ๋ฅผ ์ฝ์ ์ ์์ด. ๊ทธ๋ฆฌ๊ณ ์ค์๋ก ๋ฐ์ดํฐ๋ฅผ ์ง์ฐ๋ ์ผ๋ ๋ฐฉ์งํ ์ ์์ง! ๐
๐ ์๋๋ฆฌ์ค 2: ๊ธ๋ก๋ฒ CDN ์ฝํ ์ธ ๋ฐฐํฌ
์ ์ธ๊ณ ์ฌ์ฉ์์๊ฒ ์ ์ ์ฝํ
์ธ ๋ฅผ ์ ๊ณตํ๋ ์๋น์ค๋ฅผ ์ด์ํ๋ค๊ณ ํด๋ณด์. CloudFront์ S3๋ฅผ ํจ๊ป ์ฌ์ฉํ๋ ์ ํ์ ์ธ ํจํด์ด์ผ.
์๊ตฌ์ฌํญ:
- S3๋ ํผ๋ธ๋ฆญ ์ ๊ทผ ์ฐจ๋จ
- CloudFront๋ฅผ ํตํด์๋ง ์ ๊ทผ ๊ฐ๋ฅ
- ํน์ ๊ตญ๊ฐ๋ ์ฐจ๋จ (์ง์ญ ์ ํ)
- ํซ๋งํฌ ๋ฐฉ์ง
ํด๊ฒฐ ๋ฐฉ๋ฒ:
1. CloudFront Origin Access Identity(OAI) ์์ฑ:
aws cloudfront create-cloud-front-origin-access-identity \
--cloud-front-origin-access-identity-config \
CallerReference=my-oai-$(date +%s),Comment="OAI for my-website"
2. S3 ๋ฒํท ์ ์ฑ ์์ OAI๋ง ํ์ฉ:
{
"Version": "2012-10-17",
"Statement": [
{
"Sid": "AllowCloudFrontOAI",
"Effect": "Allow",
"Principal": {
"AWS": "arn:aws:iam::cloudfront:user/CloudFront Origin Access Identity EXAMPLE123"
},
"Action": "s3:GetObject",
"Resource": "arn:aws:s3:::my-website-bucket/*"
}
]
}
3. CloudFront ๋ฐฐํฌ์์ ์ง์ญ ์ ํ ์ค์ :
{
"GeoRestriction": {
"RestrictionType": "blacklist",
"Quantity": 2,
"Items": ["KP", "IR"]
}
}
4. Referer ํค๋ ์ฒดํฌ๋ก ํซ๋งํฌ ๋ฐฉ์ง:
{
"Version": "2012-10-17",
"Statement": [
{
"Sid": "PreventHotlinking",
"Effect": "Deny",
"Principal": "*",
"Action": "s3:GetObject",
"Resource": "arn:aws:s3:::my-website-bucket/*",
"Condition": {
"StringNotLike": {
"aws:Referer": [
"https://mywebsite.com/*",
"https://*.cloudfront.net/*"
]
}
}
}
]
}
์ด๋ ๊ฒ ํ๋ฉด S3๋ ์์ ํ ํ๋ผ์ด๋นํ๊ฒ ์ ์งํ๋ฉด์๋, CloudFront๋ฅผ ํตํด ์ ์ธ๊ณ์ ์ฝํ ์ธ ๋ฅผ ์์ ํ๊ฒ ๋ฐฐํฌํ ์ ์์ด! ๐
๐ผ ์๋๋ฆฌ์ค 3: ํํธ๋์ฌ์ ๋ฐ์ดํฐ ๊ณต์
์ธ๋ถ ํํธ๋์ฌ์ ์์ ํ๊ฒ ๋์ฉ๋ ํ์ผ์ ์ฃผ๊ณ ๋ฐ์์ผ ํ๋ ์ํฉ์ด์ผ.
์๊ตฌ์ฌํญ:
- ํํธ๋์ฌ AWS ๊ณ์ ์์ ์ ๊ทผ
- ํน์ ํด๋๋ง ์ ๊ทผ ๊ฐ๋ฅ
- ์
๋ก๋๋ ๊ฐ๋ฅํ์ง๋ง ์ญ์ ๋ ๋ถ๊ฐ
- ์ ๊ทผ ๋ก๊ทธ ์์ธ ๊ธฐ๋ก
ํด๊ฒฐ ๋ฐฉ๋ฒ:
1. ํํธ๋์ฌ ๊ณ์ ์ ์ญํ ์ ๊ถํ ๋ถ์ฌ:
{
"Version": "2012-10-17",
"Statement": [
{
"Sid": "AllowPartnerAccess",
"Effect": "Allow",
"Principal": {
"AWS": "arn:aws:iam::PARTNER-ACCOUNT-ID:role/DataExchangeRole"
},
"Action": [
"s3:GetObject",
"s3:PutObject",
"s3:ListBucket"
],
"Resource": [
"arn:aws:s3:::shared-data-bucket/partner-exchange/*"
],
"Condition": {
"StringEquals": {
"s3:x-amz-server-side-encryption": "AES256"
}
}
},
{
"Sid": "DenyDelete",
"Effect": "Deny",
"Principal": {
"AWS": "arn:aws:iam::PARTNER-ACCOUNT-ID:role/DataExchangeRole"
},
"Action": [
"s3:DeleteObject",
"s3:DeleteObjectVersion"
],
"Resource": "arn:aws:s3:::shared-data-bucket/*"
}
]
}
2. ํํธ๋์ฌ ๊ณ์ ์์ ์ญํ ์์ฑ (ํํธ๋์ฌ๊ฐ ํด์ผ ํ ์์ ):
{
"Version": "2012-10-17",
"Statement": [
{
"Effect": "Allow",
"Principal": {
"AWS": "arn:aws:iam::PARTNER-ACCOUNT-ID:root"
},
"Action": "sts:AssumeRole"
}
]
}
3. CloudTrail ๋ฐ์ดํฐ ์ด๋ฒคํธ ๋ก๊น ํ์ฑํ:
aws cloudtrail put-event-selectors \
--trail-name partner-access-trail \
--event-selectors '[
{
"ReadWriteType": "All",
"IncludeManagementEvents": false,
"DataResources": [
{
"Type": "AWS::S3::Object",
"Values": ["arn:aws:s3:::shared-data-bucket/partner-exchange/*"]
}
]
}
]'
์ด์ ํํธ๋์ฌ๋ ์๊ธฐ AWS ๊ณ์ ์์ ์ญํ ์ assumeํ๊ณ , ์ง์ ๋ ํด๋์ ์์ ํ๊ฒ ํ์ผ์ ์ ๋ก๋ํ ์ ์์ด. ๋ชจ๋ ํ๋์ CloudTrail์ ๊ธฐ๋ก๋๊ณ ! ๐
๐ฌ ์๋๋ฆฌ์ค 4: ์ฐ๊ตฌ ๋ฐ์ดํฐ ๊ณต๊ฐ
๋ํ์ด๋ ์ฐ๊ตฌ์์์ ์ฐ๊ตฌ ๋ฐ์ดํฐ๋ฅผ ๊ณต๊ฐํ๋ ค๊ณ ํด. ๋๊ตฌ๋ ๋ค์ด๋ก๋ํ ์ ์์ง๋ง, ๋น์ฉ์ ๋ค์ด๋ก๋ํ๋ ์ฌ๋์ด ๋ถ๋ดํ๊ฒ ํ๊ณ ์ถ์ด.
์๊ตฌ์ฌํญ:
- ํผ๋ธ๋ฆญ ์ฝ๊ธฐ ์ ๊ทผ
- Requester Pays ํ์ฑํ
- ๋์ฉ๋ ๋ค์ด๋ก๋ ์ ํ
- ํต๊ณ ์์ง
ํด๊ฒฐ ๋ฐฉ๋ฒ:
1. Requester Pays ํ์ฑํ:
aws s3api put-bucket-request-payment \
--bucket research-data-bucket \
--request-payment-configuration '{"Payer":"Requester"}'
2. ๋ฒํท ์ ์ฑ ์ค์ :
{
"Version": "2012-10-17",
"Statement": [
{
"Sid": "PublicReadWithRequesterPays",
"Effect": "Allow",
"Principal": "*",
"Action": [
"s3:GetObject",
"s3:ListBucket"
],
"Resource": [
"arn:aws:s3:::research-data-bucket",
"arn:aws:s3:::research-data-bucket/*"
]
}
]
}
3. ๋์ฉ๋ ๋ค์ด๋ก๋ ์ ํ (Lambda@Edge ์ฌ์ฉ):
exports.handler = async (event) => {
const request = event.Records[0].cf.request;
const headers = request.headers;
// ํ๋ฃจ ๋ค์ด๋ก๋ ์ ํ ์ฒดํฌ (DynamoDB ๋ฑ ํ์ฉ)
const clientIp = headers['x-forwarded-for'] ?
headers['x-forwarded-for'][0].value :
headers['cloudfront-viewer-address'][0].value;
const downloadCount = await checkDownloadCount(clientIp);
if (downloadCount > 100) {
return {
status: '429',
statusDescription: 'Too Many Requests',
body: 'Daily download limit exceeded'
};
}
return request;
};
Requester Pays๋ฅผ ์ฌ์ฉํ๋ฉด ๋ฐ์ดํฐ๋ฅผ ๊ณต๊ฐํ๋ฉด์๋ ์ ์ก ๋น์ฉ ๋ถ๋ด์ ์ค์ผ ์ ์์ด. ๋์ฉ๋ ๋ฐ์ดํฐ์ ์ ๊ณต์ ํ ๋ ์ ์ฉํ ๋ฐฉ๋ฒ์ด์ผ! ๐ฐ
๐ก๏ธ ๋ณด์ ๋ฒ ์คํธ ํ๋ํฐ์ค
์ง๊ธ๊น์ง ๋ฐฐ์ด ๋ด์ฉ์ ๋ฐํ์ผ๋ก, S3 ์ ๊ทผ์ ์ด์ ๋ณด์ ๋ฒ ์คํธ ํ๋ํฐ์ค๋ฅผ ์ ๋ฆฌํด๋ณผ๊ฒ. ์ด๊ฑธ ๋ฐ๋ฅด๋ฉด ๋๋ถ๋ถ์ ๋ณด์ ์ฌ๊ณ ๋ฅผ ์๋ฐฉํ ์ ์์ด! ๐ฏ
1๏ธโฃ ์ต์ ๊ถํ ์์น (Principle of Least Privilege)
ํญ์ ํ์ํ ์ต์ํ์ ๊ถํ๋ง ๋ถ์ฌํด. "์ผ๋จ ๋ค ์ฃผ๊ณ ๋์ค์ ์ ํํ์"๋ ์ํํ ์๊ฐ์ด์ผ.
๋์ ์:
{
"Effect": "Allow",
"Action": "s3:*",
"Resource": "*"
}
์ข์ ์:
{
"Effect": "Allow",
"Action": [
"s3:GetObject",
"s3:PutObject"
],
"Resource": "arn:aws:s3:::specific-bucket/specific-prefix/*"
}
2๏ธโฃ ๋ธ๋ก ํผ๋ธ๋ฆญ ์ก์ธ์ค ๊ธฐ๋ณธ ํ์ฑํ
์ ๋ง ํผ๋ธ๋ฆญ ์ ๊ทผ์ด ํ์ํ ๊ฒฝ์ฐ๊ฐ ์๋๋ผ๋ฉด, ๋ธ๋ก ํผ๋ธ๋ฆญ ์ก์ธ์ค ์ค์ ์ ์ ๋ ํด์ ํ์ง ๋ง. ์ด๊ฒ ๊ฐ์ฅ ๊ธฐ๋ณธ์ ์ด๋ฉด์๋ ๊ฐ๋ ฅํ ๋ฐฉ์ด๋ง์ด์ผ! ๐ง
3๏ธโฃ ์ํธํ๋ ํ์
๋ชจ๋ S3 ๋ฒํท์ ๊ธฐ๋ณธ ์ํธํ๋ฅผ ์ค์ ํด:
aws s3api put-bucket-encryption \
--bucket my-bucket \
--server-side-encryption-configuration '{
"Rules": [
{
"ApplyServerSideEncryptionByDefault": {
"SSEAlgorithm": "AES256"
},
"BucketKeyEnabled": true
}
]
}'
๋ ๊ฐ๋ ฅํ ๋ณด์์ด ํ์ํ๋ฉด AWS KMS๋ฅผ ์ฌ์ฉํด. ํค ๋กํ ์ด์ , ์ ๊ทผ ๋ก๊น , ์ธ๋ฐํ ๊ถํ ์ ์ด๊ฐ ๊ฐ๋ฅํด!
4๏ธโฃ MFA Delete ํ์ฑํ
์ค์ํ ๋ฒํท์๋ MFA Delete๋ฅผ ํ์ฑํํด์ ์ค์๋ ์ ์์ ์ธ ์ญ์ ๋ฅผ ๋ฐฉ์งํด:
aws s3api put-bucket-versioning \
--bucket critical-bucket \
--versioning-configuration Status=Enabled,MFADelete=Enabled \
--mfa "arn:aws:iam::123456789012:mfa/root-account-mfa-device 123456"
์ฐธ๊ณ ๋ก MFA Delete๋ ๋ฃจํธ ๊ณ์ ์ผ๋ก๋ง ํ์ฑํํ ์ ์์ด. ๊ทธ๋งํผ ์ค์ํ ์ค์ ์ด๋ผ๋ ๋ป์ด์ง!
5๏ธโฃ ์ ๊ธฐ์ ์ธ ์ ๊ทผ ๊ฒํ
IAM Access Analyzer๋ฅผ ์ฌ์ฉํด์ ์ธ๋ถ์์ ์ ๊ทผ ๊ฐ๋ฅํ ๋ฒํท์ ์ ๊ธฐ์ ์ผ๋ก ํ์ธํด:
aws accessanalyzer create-analyzer \
--analyzer-name s3-access-analyzer \
--type ACCOUNT
Access Analyzer๋ ์๋์ผ๋ก ์ธ๋ถ ์ ๊ทผ ๊ฐ๋ฅํ ๋ฆฌ์์ค๋ฅผ ์ฐพ์๋ด๊ณ ์๋ ค์ค. ์๋ํ์ง ์์ ๊ณต๊ฐ๋ฅผ ๋น ๋ฅด๊ฒ ๋ฐ๊ฒฌํ ์ ์์ด! ๐
6๏ธโฃ VPC ์๋ํฌ์ธํธ ์ฌ์ฉ
๊ฐ๋ฅํ๋ฉด VPC ์๋ํฌ์ธํธ๋ฅผ ํตํด S3์ ์ ๊ทผํด. ์ธํฐ๋ท์ ๊ฑฐ์น์ง ์์์ ๋ ์์ ํ๊ณ ๋น ๋ฅด๊ฑฐ๋ :
aws ec2 create-vpc-endpoint \
--vpc-id vpc-12345678 \
--service-name com.amazonaws.us-east-1.s3 \
--route-table-ids rtb-12345678
๊ทธ๋ฆฌ๊ณ ๋ฒํท ์ ์ฑ ์์ VPC ์๋ํฌ์ธํธ๋ฅผ ํตํ ์ ๊ทผ๋ง ํ์ฉ:
{
"Version": "2012-10-17",
"Statement": [
{
"Sid": "VPCEndpointOnly",
"Effect": "Deny",
"Principal": "*",
"Action": "s3:*",
"Resource": [
"arn:aws:s3:::my-bucket",
"arn:aws:s3:::my-bucket/*"
],
"Condition": {
"StringNotEquals": {
"aws:SourceVpce": "vpce-1234567"
}
}
}
]
}
7๏ธโฃ ํ๊ทธ ๊ธฐ๋ฐ ์ ๊ทผ์ ์ด ํ์ฉ
๋ฆฌ์์ค์ ์ฌ์ฉ์์ ํ๊ทธ๋ฅผ ๋ถ์ด๊ณ , ํ๊ทธ ๊ธฐ๋ฐ์ผ๋ก ๊ถํ์ ๊ด๋ฆฌํ๋ฉด ํ์ฅ์ฑ์ด ์ข์:
{
"Version": "2012-10-17",
"Statement": [
{
"Effect": "Allow",
"Action": "s3:*",
"Resource": "*",
"Condition": {
"StringEquals": {
"s3:ExistingObjectTag/Environment": "${aws:PrincipalTag/Environment}"
}
}
}
]
}
๊ฐ๋ฐ ํ๊ฒฝ ํ๊ทธ๋ฅผ ๊ฐ์ง ์ฌ์ฉ์๋ ๊ฐ๋ฐ ํ๊ฒฝ ํ๊ทธ๊ฐ ๋ถ์ ๊ฐ์ฒด๋ง ์ ๊ทผํ ์ ์์ด. ํ๊ฒฝ ๋ถ๋ฆฌ๊ฐ ์๋์ผ๋ก ์ด๋ฃจ์ด์ง๋ ๊ฑฐ์ง!
8๏ธโฃ ๋ผ์ดํ์ฌ์ดํด ์ ์ฑ ์ผ๋ก ์ค๋๋ ๋ฐ์ดํฐ ๊ด๋ฆฌ
์ค๋๋ ๋ฒ์ ์ด๋ ๋ถ์์ ํ ๋ฉํฐํํธ ์ ๋ก๋๋ฅผ ์๋์ผ๋ก ์ ๋ฆฌํด:
{
"Rules": [
{
"Id": "DeleteOldVersions",
"Status": "Enabled",
"NoncurrentVersionExpiration": {
"NoncurrentDays": 90
}
},
{
"Id": "CleanupIncompleteUploads",
"Status": "Enabled",
"AbortIncompleteMultipartUpload": {
"DaysAfterInitiation": 7
}
}
]
}
์ด๋ ๊ฒ ํ๋ฉด ์คํ ๋ฆฌ์ง ๋น์ฉ๋ ์ ์ฝํ๊ณ , ๋ถํ์ํ ๋ฐ์ดํฐ ๋ ธ์ถ ์ํ๋ ์ค์ผ ์ ์์ด!
9๏ธโฃ ์ ๊ธฐ์ ์ธ ๋ณด์ ๊ฐ์ฌ
AWS Config๋ฅผ ์ฌ์ฉํด์ S3 ๋ฒํท ์ค์ ์ ์ง์์ ์ผ๋ก ๋ชจ๋ํฐ๋งํด:
aws configservice put-config-rule \
--config-rule '{
"ConfigRuleName": "s3-bucket-public-read-prohibited",
"Source": {
"Owner": "AWS",
"SourceIdentifier": "S3_BUCKET_PUBLIC_READ_PROHIBITED"
}
}'
AWS Config๋ ๊ท์ ์ ์๋ฐํ๋ ๋ฒํท์ ์๋์ผ๋ก ์ฐพ์๋ด๊ณ , ํ์ํ๋ฉด ์๋ ์์ (Auto Remediation)๋ ๊ฐ๋ฅํด!
๐ ์ฌ๊ณ ๋์ ๊ณํ ์๋ฆฝ
์๋ฌด๋ฆฌ ์๋ฒฝํ ๋ณด์ ์ค์ ์ ํด๋ ์ฌ๊ณ ๋ ์ผ์ด๋ ์ ์์ด. ์ฌ๊ณ ๋์ ๊ณํ์ ๋ฏธ๋ฆฌ ๋ง๋ค์ด๋์:
1. ํ์ง: CloudWatch ์๋, GuardDuty ์๋ฆผ ์ค์
2. ๊ฒฉ๋ฆฌ: ์์ฌ์ค๋ฌ์ด ์ ๊ทผ ์ฆ์ ์ฐจ๋จํ๋ Lambda ํจ์
3. ์กฐ์ฌ: CloudTrail ๋ก๊ทธ ๋ถ์ ์ ์ฐจ
4. ๋ณต๊ตฌ: ๋ฐฑ์
์์ ๋ณต์ํ๋ ๋ฐฉ๋ฒ
5. ์ฌํ ๋ถ์: ์ฌ๋ฐ ๋ฐฉ์ง ๋์ฑ
์๋ฆฝ
์ด๋ฐ ๊ณํ์ด ์์ผ๋ฉด ์ค์ ์ฌ๊ณ ๊ฐ ๋ฐ์ํ์ ๋ ๋นํฉํ์ง ์๊ณ ์ ์ํ๊ฒ ๋์ํ ์ ์์ด! ๐จ
2. ํ ์คํธ ์ค์ ๊ทธ๋๋ก ์ด์: ๊ฐ๋ฐ/ํ ์คํธ ํ๊ฒฝ์์ ํธ์๋ฅผ ์ํด ๋์จํ๊ฒ ์ค์ ํ ๊ฑธ ์ด์์ ๊ทธ๋๋ก ๊ฐ์ ธ๊ฐ๋ฉด ์ ๋ผ
3. ์ ์ฑ ์ ๋ฐ์ดํธ ํ ํ ์คํธ ์ ํจ: ์ ์ฑ ์ ๋ณ๊ฒฝํ ํ์๋ ๋ฐ๋์ ์๋๋๋ก ๋์ํ๋์ง ํ์ธํด์ผ ํด
4. ๋ก๊ทธ ๋ชจ๋ํฐ๋ง ์ ํจ: ๋ก๊ทธ๋ฅผ ์๊ธฐ๋ง ํ๊ณ ํ์ธํ์ง ์์ผ๋ฉด ์๋ฏธ๊ฐ ์์ด
๐ง ํธ๋ฌ๋ธ์ํ ๊ฐ์ด๋
S3 ์ ๊ทผ์ ์ด๋ฅผ ์ค์ ํ๋ค ๋ณด๋ฉด ์์์น ๋ชปํ ๋ฌธ์ ๋ค์ด ์๊ธฐ๊ณค ํด. ์์ฃผ ๋ฐ์ํ๋ ๋ฌธ์ ๋ค๊ณผ ํด๊ฒฐ ๋ฐฉ๋ฒ์ ์ ๋ฆฌํด๋ดค์ด! ๐จ
โ ๋ฌธ์ 1: "Access Denied" ์๋ฌ
๊ฐ์ฅ ํํ ์๋ฌ์ผ. ์ฌ๋ฌ ์์ธ์ด ์์ ์ ์์ด:
์์ธ 1: IAM ์ ์ฑ
๋ถ์กฑ
์ฌ์ฉ์๋ ์ญํ ์ ํ์ํ ๊ถํ์ด ์๋ ๊ฒฝ์ฐ์ผ. IAM Policy Simulator๋ก ํ์ธํด๋ด:
aws iam simulate-principal-policy \
--policy-source-arn arn:aws:iam::123456789012:user/Alice \
--action-names s3:GetObject \
--resource-arns arn:aws:s3:::my-bucket/file.txt
์์ธ 2: ๋ฒํท ์ ์ฑ
์์ ๋ช
์์ Deny
๋ฒํท ์ ์ฑ
์ Deny ๋ฌธ์ด ์์ผ๋ฉด IAM ์ ์ฑ
์ Allow๋ณด๋ค ์ฐ์ ํด. ๋ฒํท ์ ์ฑ
์ ํ์ธํด๋ด:
aws s3api get-bucket-policy --bucket my-bucket
์์ธ 3: ๋ธ๋ก ํผ๋ธ๋ฆญ ์ก์ธ์ค ์ค์
ํผ๋ธ๋ฆญ ์ ๊ทผ์ด ํ์ํ๋ฐ ๋ธ๋ก ์ค์ ์ด ํ์ฑํ๋์ด ์์ ์ ์์ด:
aws s3api get-public-access-block --bucket my-bucket
์์ธ 4: ๊ฐ์ฒด ์์ ๊ถ ๋ฌธ์
๋ค๋ฅธ ๊ณ์ ์ด ์
๋ก๋ํ ๊ฐ์ฒด๋ ๊ธฐ๋ณธ์ ์ผ๋ก ์
๋ก๋๊ฐ ์์ ํด. ๋ฒํท ์์ ์๊ฐ ์ ๊ทผํ๋ ค๋ฉด ๊ฐ์ฒด ์์ ๊ถ ์ค์ ์ ํ์ธํด์ผ ํด:
aws s3api get-bucket-ownership-controls --bucket my-bucket
โ ๋ฌธ์ 2: CORS ์๋ฌ
์น ๋ธ๋ผ์ฐ์ ์์ S3์ ์ง์ ์ ๊ทผํ ๋ CORS ์๋ฌ๊ฐ ๋ฐ์ํ ์ ์์ด. CORS ์ค์ ์ ์ถ๊ฐํด์ค์ผ ํด:
{
"CORSRules": [
{
"AllowedOrigins": ["https://mywebsite.com"],
"AllowedMethods": ["GET", "PUT", "POST"],
"AllowedHeaders": ["*"],
"ExposeHeaders": ["ETag"],
"MaxAgeSeconds": 3000
}
]
}
aws s3api put-bucket-cors \
--bucket my-bucket \
--cors-configuration file://cors.json
โ ๋ฌธ์ 3: ์ ์ฑ ํฌ๊ธฐ ์ ํ ์ด๊ณผ
๋ฒํท ์ ์ฑ
์ 20KB๋ก ์ ํ๋ผ ์์ด. ์ ์ฑ
์ด ๋๋ฌด ์ปค์ง๋ฉด:
ํด๊ฒฐ์ฑ
1: ์ก์ธ์ค ํฌ์ธํธ ์ฌ์ฉ
๋ณต์กํ ์ ์ฑ
์ ์ฌ๋ฌ ์ก์ธ์ค ํฌ์ธํธ๋ก ๋ถ์ฐ์์ผ.
ํด๊ฒฐ์ฑ
2: IAM ์ ์ฑ
์ผ๋ก ์ด๋
๊ฐ๋ฅํ๋ฉด IAM ์ ์ฑ
์ผ๋ก ๊ถํ์ ๊ด๋ฆฌํ๊ณ , ๋ฒํท ์ ์ฑ
์ ํฌ๋ก์ค ๊ณ์ ์ ๊ทผ ๊ฐ์ ํ์ ์ฌํญ๋ง ์ฒ๋ฆฌํด.
ํด๊ฒฐ์ฑ
3: ์ ์ฑ
์ต์ ํ
์์ผ๋์นด๋๋ฅผ ํ์ฉํด์ ์ฌ๋ฌ ๊ท์น์ ํ๋๋ก ํฉ์ณ:
// ๋นํจ์จ์
"Resource": [
"arn:aws:s3:::my-bucket/folder1/*",
"arn:aws:s3:::my-bucket/folder2/*",
"arn:aws:s3:::my-bucket/folder3/*"
]
// ํจ์จ์
"Resource": "arn:aws:s3:::my-bucket/folder*/*"
โ ๋ฌธ์ 4: ํฌ๋ก์ค ๊ณ์ ์ ๊ทผ ์ ๋จ
ํฌ๋ก์ค ๊ณ์ ์ ๊ทผ์ ์ค์ ํ๋๋ฐ ์ ๋๋ ๊ฒฝ์ฐ:
์ฒดํฌ๋ฆฌ์คํธ:
1. ๋ฒํท ์ ์ฑ
์์ ๋ค๋ฅธ ๊ณ์ Principal ํ์ฉํ๋?
2. ๋ค๋ฅธ ๊ณ์ ์ IAM ์ ์ฑ
์์ ๋ฒํท ์ ๊ทผ ํ์ฉํ๋?
3. ๊ฐ์ฒด ACL์ด ๋ฒํท ์์ ์์๊ฒ ๊ถํ์ ์ฃผ๊ณ ์๋?
4. ๋ธ๋ก ํผ๋ธ๋ฆญ ์ก์ธ์ค๊ฐ ํฌ๋ก์ค ๊ณ์ ์ ๊ทผ์ ๋ง๊ณ ์์ง ์๋?
ํนํ ๊ฐ์ฒด ์์ ๊ถ ๋ฌธ์ ๊ฐ ๋ง์. ์
๋ก๋ํ ๋ --acl bucket-owner-full-control ์ต์
์ ์ถ๊ฐํ๋ฉด ํด๊ฒฐ๋ผ:
aws s3 cp file.txt s3://shared-bucket/ \
--acl bucket-owner-full-control
โ ๋ฌธ์ 5: ์ํธํ ๊ด๋ จ ์๋ฌ
KMS ์ํธํ๋ฅผ ์ฌ์ฉํ ๋ ๊ถํ ๋ฌธ์ ๊ฐ ์์ฃผ ๋ฐ์ํด:
์์ธ: KMS ํค ์ ์ฑ
์ ๊ถํ ์์
S3 ๋ฒํท ์ ๊ทผ ๊ถํ๋ง ์๊ณ KMS ํค ์ฌ์ฉ ๊ถํ์ด ์์ผ๋ฉด ์ํธํ๋ ๊ฐ์ฒด๋ฅผ ์ฝ์ ์ ์์ด. KMS ํค ์ ์ฑ
์ ํ์ธํด๋ด:
aws kms get-key-policy \
--key-id 1234abcd-12ab-34cd-56ef-1234567890ab \
--policy-name default
ํ์ํ ๊ถํ์ ์ถ๊ฐํด์ค:
{
"Sid": "Allow use of the key for S3",
"Effect": "Allow",
"Principal": {
"AWS": "arn:aws:iam::123456789012:role/MyRole"
},
"Action": [
"kms:Decrypt",
"kms:DescribeKey"
],
"Resource": "*"
}
๐ ๋๋ฒ๊น ํ
๋ฌธ์ ๋ฅผ ํด๊ฒฐํ ๋ ์ด๋ฐ ์์๋ก ์ ๊ทผํ๋ฉด ํจ์จ์ ์ด์ผ:
1. CloudTrail ๋ก๊ทธ ํ์ธ: ์ ํํ ์ด๋ค API ํธ์ถ์ด ์คํจํ๋์ง ํ์ธ
2. ์๋ฌ ๋ฉ์์ง ๋ถ์: AWS ์๋ฌ ๋ฉ์์ง๋ ์๊ฐ๋ณด๋ค ์น์ ํด. ์์ธํ ์ฝ์ด๋ด
3. IAM Policy Simulator ์ฌ์ฉ: ์ ์ฑ
์ด ์๋๋๋ก ๋์ํ๋์ง ์๋ฎฌ๋ ์ด์
4. ๋จ๊ณ๋ณ ํ
์คํธ: ๋ณต์กํ ์ ์ฑ
์ ๋จ์ํ ๋ฒ์ ๋ถํฐ ์์ํด์ ์ ์ง์ ์ผ๋ก ์ถ๊ฐ
5. AWS ๋ฌธ์ ์ฐธ์กฐ: AWS ๊ณต์ ๋ฌธ์๋ ์ ๋ง ์ ๋์ด ์์ด. ์์ฌ์ค๋ฌ์ฐ๋ฉด ๋ฌธ์๋ฅผ ํ์ธํด๋ด
ํนํ CloudTrail ๋ก๊ทธ๋ ์ ๋ง ์ ์ฉํด. ์คํจํ API ํธ์ถ์ ์ ํํ ์์ธ์ ์๋ ค์ฃผ๊ฑฐ๋ :
aws cloudtrail lookup-events \
--lookup-attributes AttributeKey=EventName,AttributeValue=GetObject \
--max-results 10
aws s3 ls s3://my-bucket --debug
HTTP ์์ฒญ/์๋ต, ์๋ช ๊ณผ์ ๋ฑ์ ๋ชจ๋ ๋ณผ ์ ์์ด์ ๋ฌธ์ ์์ธ์ ์ฐพ๊ธฐ ์ฌ์!
๐ ๊ณ ๊ธ ์ฃผ์ ์ ์ต์ ๊ธฐ๋ฅ
๊ธฐ๋ณธ์ ๋ง์คํฐํ๋ค๋ฉด, ์ด์ ์ข ๋ ๊ณ ๊ธ ์ฃผ์ ๋ค์ ์ดํด๋ณผ ์ฐจ๋ก์ผ! AWS๋ ๊ณ์ ์๋ก์ด ๊ธฐ๋ฅ์ ์ถ๊ฐํ๊ณ ์๊ฑฐ๋ . ๐
๐ฏ S3 Object Lambda
2021๋
์ ์ถ์๋ S3 Object Lambda๋ ์ ๋ง ํ์ ์ ์ธ ๊ธฐ๋ฅ์ด์ผ. ๊ฐ์ฒด๋ฅผ ์ฝ์ ๋ ์ค์๊ฐ์ผ๋ก ๋ณํํ ์ ์์ด!
์๋ฅผ ๋ค์ด:
- ๋ฏผ๊ฐํ ์ ๋ณด๋ฅผ ์๋์ผ๋ก ๋ง์คํน
- ์ด๋ฏธ์ง ํฌ๊ธฐ๋ฅผ ์์ฒญ์์ ๋ง๊ฒ ์กฐ์
- ๋ฐ์ดํฐ๋ฅผ ๋ค๋ฅธ ํ์์ผ๋ก ๋ณํ
- ์ํฐ๋งํฌ ์ถ๊ฐ
์ค์ ๋ฐฉ๋ฒ:
// 1. Lambda ํจ์ ์์ฑ
exports.handler = async (event) => {
const { getObjectContext, userRequest } = event;
const { outputRoute, outputToken, inputS3Url } = getObjectContext;
// ์๋ณธ ๊ฐ์ฒด ๊ฐ์ ธ์ค๊ธฐ
const response = await fetch(inputS3Url);
let data = await response.text();
// ๋ฏผ๊ฐํ ์ ๋ณด ๋ง์คํน
data = data.replace(/\d{3}-\d{2}-\d{4}/g, 'XXX-XX-XXXX');
// ๋ณํ๋ ๋ฐ์ดํฐ ๋ฐํ
await s3.writeGetObjectResponse({
RequestRoute: outputRoute,
RequestToken: outputToken,
Body: data
});
return { statusCode: 200 };
};
// 2. Object Lambda Access Point ์์ฑ
aws s3control create-access-point-for-object-lambda \
--account-id 123456789012 \
--name my-object-lambda-ap \
--configuration '{
"SupportingAccessPoint": "arn:aws:s3:us-east-1:123456789012:accesspoint/my-ap",
"TransformationConfigurations": [{
"Actions": ["GetObject"],
"ContentTransformation": {
"AwsLambda": {
"FunctionArn": "arn:aws:lambda:us-east-1:123456789012:function:MyTransformFunction"
}
}
}]
}'
์ด์ Object Lambda Access Point๋ฅผ ํตํด ๊ฐ์ฒด๋ฅผ ์ฝ์ผ๋ฉด ์๋์ผ๋ก Lambda ํจ์๊ฐ ์คํ๋๊ณ , ๋ณํ๋ ๋ฐ์ดํฐ๋ฅผ ๋ฐ๊ฒ ๋ผ. ์๋ณธ ๋ฐ์ดํฐ๋ ๊ทธ๋๋ก ์ ์ง๋๋ฉด์ ๋ง์ด์ผ! ๐จ
๐ S3 Access Grants
2023๋
์ ์ถ์๋ S3 Access Grants๋ IAM ์ ์ฑ
์์ด๋ S3 ์ ๊ทผ ๊ถํ์ ๋ถ์ฌํ ์ ์๊ฒ ํด์ค. ํนํ ๋๊ท๋ชจ ์กฐ์ง์์ ์ ์ฉํด.
๊ธฐ์กด ๋ฐฉ์์ ๋ฌธ์ ์ :
- IAM ์ ์ฑ
์ด ๋๋ฌด ๋ณต์กํด์ง
- ์ฌ์ฉ์๋ง๋ค ๊ฐ๋ณ ์ ์ฑ
๊ด๋ฆฌ๊ฐ ์ด๋ ค์
- ๊ถํ ๋ณ๊ฒฝ์ด ๋๋ฆผ
Access Grants์ ์ฅ์ :
- Active Directory๋ Okta ๊ฐ์ IdP์ ์ง์ ์ฐ๋
- ์ธ์
๊ธฐ๋ฐ ์์ ์๊ฒฉ์ฆ๋ช
์๋ ๋ฐ๊ธ
- ๋ ์ธ๋ฐํ ๊ถํ ์ ์ด
์ค์ ์์:
// 1. Access Grants ์ธ์คํด์ค ์์ฑ
aws s3control create-access-grants-instance \
--account-id 123456789012 \
--identity-center-arn arn:aws:sso:::instance/ssoins-1234567890abcdef
// 2. ์์น ๋ฑ๋ก
aws s3control create-access-grants-location \
--account-id 123456789012 \
--location-scope s3://my-bucket/data/* \
--iam-role-arn arn:aws:iam::123456789012:role/S3AccessGrantsRole
// 3. ๊ถํ ๋ถ์ฌ
aws s3control create-access-grant \
--account-id 123456789012 \
--access-grants-location-id default \
--grantee '{
"GranteeType": "IAM",
"GranteeIdentifier": "arn:aws:iam::123456789012:user/Alice"
}' \
--permission READ \
--access-grants-location-configuration '{
"S3SubPrefix": "project-a/*"
}'
์ด์ Alice๋ ์๋์ผ๋ก project-a ํด๋์ ๋ํ ์์ ์๊ฒฉ์ฆ๋ช ์ ๋ฐ์์ ์ ๊ทผํ ์ ์์ด. IAM ์ ์ฑ ์ ์์ ํ ํ์๊ฐ ์์ง! ๐
๐ S3 Express One Zone
2023๋
๋ง์ ์ถ์๋ S3 Express One Zone์ ์ด๊ณ ์ฑ๋ฅ ์คํ ๋ฆฌ์ง ํด๋์ค์ผ. ์ผ๋ฐ S3๋ณด๋ค 10๋ฐฐ ๋น ๋ฅธ ์ฑ๋ฅ์ ์ ๊ณตํด!
ํน์ง:
- ํ ์๋ฆฌ ์ ๋ฐ๋ฆฌ์ด ๋ ์ดํด์
- ์ด๋น ์์ญ๋ง ์์ฒญ ์ฒ๋ฆฌ
- ๋จ์ผ ๊ฐ์ฉ ์์ญ์ ์ ์ฅ
- ๋๋ ํ ๋ฆฌ ๋ฒํท ์ฌ์ฉ
์ ๊ทผ์ ์ด ์ธก๋ฉด์์ ์ฃผ๋ชฉํ ์ :
// Express One Zone์ ์ธ์
๊ธฐ๋ฐ ์ธ์ฆ ์ฌ์ฉ
aws s3express create-session \
--bucket my-express-bucket--use1-az1--x-s3
// ์ธ์
์๊ฒฉ์ฆ๋ช
์ผ๋ก ์ ๊ทผ
aws s3 cp file.txt s3://my-express-bucket--use1-az1--x-s3/ \
--session-token <session-token>
์ผ๋ฐ S3์ ๋ค๋ฅด๊ฒ ์ธ์ ๊ธฐ๋ฐ ์ธ์ฆ์ ์ฌ์ฉํด์ ์ฑ๋ฅ์ ๊ทน๋ํํ์ด. ๊ณ ์ฑ๋ฅ์ด ํ์ํ ML ํ์ต์ด๋ ์ค์๊ฐ ๋ถ์์ ์๋ฒฝํด! โก
๐ S3 Bucket Keys
KMS ์ํธํ๋ฅผ ์ฌ์ฉํ ๋ ๋น์ฉ์ ํฌ๊ฒ ์ค์ฌ์ฃผ๋ ๊ธฐ๋ฅ์ด์ผ. ๊ธฐ๋ณธ์ ์ผ๋ก ๊ฐ์ฒด๋ง๋ค KMS API๋ฅผ ํธ์ถํ๋๋ฐ, Bucket Keys๋ฅผ ์ฌ์ฉํ๋ฉด ๋ฒํท ๋ ๋ฒจ์์ ํค๋ฅผ ์์ฑํด์ ์ฌ์ฌ์ฉํด.
๋น์ฉ ์ ๊ฐ ํจ๊ณผ:
- KMS API ํธ์ถ 99% ๊ฐ์
- ์ํธํ ๋น์ฉ ๋ํญ ์ ๊ฐ
- ์ฑ๋ฅ๋ ํฅ์
ํ์ฑํ ๋ฐฉ๋ฒ:
aws s3api put-bucket-encryption \
--bucket my-bucket \
--server-side-encryption-configuration '{
"Rules": [{
"ApplyServerSideEncryptionByDefault": {
"SSEAlgorithm": "aws:kms",
"KMSMasterKeyID": "arn:aws:kms:us-east-1:123456789012:key/1234abcd-12ab-34cd-56ef-1234567890ab"
},
"BucketKeyEnabled": true
}]
}'
๋์ฉ๋ ๋ฐ์ดํฐ๋ฅผ ๋ค๋ฃจ๋ ๊ฒฝ์ฐ Bucket Keys๋ ํ์์ผ. ๋น์ฉ๊ณผ ์ฑ๋ฅ ๋ชจ๋ ๊ฐ์ ๋๊ฑฐ๋ ! ๐ฐ
๐ S3 Storage Lens
Storage Lens๋ S3 ์ฌ์ฉ ํํฉ์ ์๊ฐํํ๊ณ ์ต์ ํ ๊ถ์ฅ์ฌํญ์ ์ ๊ณตํด. ์ ๊ทผ์ ์ด ๊ด์ ์์๋ ์ ์ฉํ ์ธ์ฌ์ดํธ๋ฅผ ์ค:
- ํผ๋ธ๋ฆญ ์ ๊ทผ ๊ฐ๋ฅํ ๋ฒํท ์๋ณ
- ์ํธํ๋์ง ์์ ๊ฐ์ฒด ์ฐพ๊ธฐ
- ์ค๋๋ ๋ฒ์ ์ ๋ฆฌ ๊ถ์ฅ
- ๋น์ฉ ์ต์ ํ ๊ธฐํ ๋ฐ๊ฒฌ
๊ณ ๊ธ ๋ฉํธ๋ฆญ์ ํ์ฑํํ๋ฉด ๋ ์์ธํ ์ ๋ณด๋ฅผ ๋ณผ ์ ์์ด:
aws s3control put-storage-lens-configuration \
--account-id 123456789012 \
--config-id advanced-metrics-config \
--storage-lens-configuration '{
"Id": "advanced-metrics-config",
"AccountLevel": {
"BucketLevel": {
"ActivityMetrics": {
"IsEnabled": true
},
"AdvancedCostOptimizationMetrics": {
"IsEnabled": true
},
"AdvancedDataProtectionMetrics": {
"IsEnabled": true
}
}
},
"IsEnabled": true
}'
Storage Lens ๋์๋ณด๋๋ฅผ ์ ๊ธฐ์ ์ผ๋ก ํ์ธํ๋ฉด ๋ณด์ ์ทจ์ฝ์ ์ ์กฐ๊ธฐ์ ๋ฐ๊ฒฌํ ์ ์์ด! ๐
๐ค AI/ML๊ณผ S3 ์ ๊ทผ์ ์ด
์์ฆ AI/ML ์ํฌ๋ก๋๊ฐ ๋ง์์ง๋ฉด์ S3 ์ ๊ทผ ํจํด๋ ๋ณํ๊ณ ์์ด. ๋ช ๊ฐ์ง ๊ณ ๋ ค์ฌํญ:
1. SageMaker์ S3 ํตํฉ
SageMaker๋ S3์์ ํ์ต ๋ฐ์ดํฐ๋ฅผ ์ฝ๊ณ ๋ชจ๋ธ์ ์ ์ฅํด. ์ ์ ํ ๊ถํ ์ค์ ์ด ์ค์ํด:
{
"Version": "2012-10-17",
"Statement": [
{
"Effect": "Allow",
"Action": [
"s3:GetObject",
"s3:PutObject",
"s3:DeleteObject",
"s3:ListBucket"
],
"Resource": [
"arn:aws:s3:::sagemaker-training-data/*",
"arn:aws:s3:::sagemaker-models/*"
]
}
]
}
2. ๋์ฉ๋ ๋ฐ์ดํฐ์
์ ๊ทผ ์ต์ ํ
ML ํ์ต์ ์๋ฐฑ GB~TB์ ๋ฐ์ดํฐ๋ฅผ ์ฝ์ด. S3 Select๋ S3 Object Lambda๋ฅผ ํ์ฉํ๋ฉด ํ์ํ ๋ฐ์ดํฐ๋ง ๊ฐ์ ธ์ฌ ์ ์์ด:
aws s3api select-object-content \
--bucket training-data \
--key dataset.csv \
--expression "SELECT * FROM S3Object WHERE category = 'positive'" \
--expression-type SQL \
--input-serialization '{"CSV": {"FileHeaderInfo": "USE"}}' \
--output-serialization '{"CSV": {}}' \
output.csv
3. ๋ชจ๋ธ ์ํฐํฉํธ ๋ณดํธ
ํ์ต๋ ๋ชจ๋ธ์ ์ค์ํ ์์ฐ์ด์ผ. Object Lock์ผ๋ก ๋ณดํธํ๊ณ , ๋ฒ์ ๊ด๋ฆฌ๋ฅผ ํ์ฑํํด์ ๋ชจ๋ธ ๋ณ๊ฒฝ ์ด๋ ฅ์ ์ถ์ ํด์ผ ํด.
๐ผ ๋น์ฉ ์ต์ ํ ์ ๋ต
S3 ์ ๊ทผ์ ์ด๋ฅผ ์ค์ ํ๋ฉด์ ๋น์ฉ๋ ํจ๊ป ๊ณ ๋ คํด์ผ ํด. ๋ณด์๊ณผ ๋น์ฉ, ๋ ๋ง๋ฆฌ ํ ๋ผ๋ฅผ ๋ค ์ก๋ ๋ฐฉ๋ฒ์ ์๋ ค์ค๊ฒ! ๐ฐ
๐ ์คํ ๋ฆฌ์ง ํด๋์ค ์ต์ ํ
์ ๊ทผ ๋น๋์ ๋ฐ๋ผ ์ ์ ํ ์คํ ๋ฆฌ์ง ํด๋์ค๋ฅผ ์ ํํ๋ฉด ๋น์ฉ์ ํฌ๊ฒ ์ค์ผ ์ ์์ด:
- S3 Standard: ์์ฃผ ์ ๊ทผํ๋ ๋ฐ์ดํฐ (๊ฐ์ฅ ๋น์)
- S3 Intelligent-Tiering: ์ ๊ทผ ํจํด์ด ๋ณํ๋ ๋ฐ์ดํฐ (์๋ ์ต์ ํ)
- S3 Standard-IA: ๊ฐ๋ ์ ๊ทผํ๋ ๋ฐ์ดํฐ
- S3 One Zone-IA: ์ค์ํ์ง ์์ ๋ฐ์ดํฐ
- S3 Glacier: ์์นด์ด๋ธ ๋ฐ์ดํฐ
- S3 Glacier Deep Archive: ์ฅ๊ธฐ ๋ณด๊ด ๋ฐ์ดํฐ (๊ฐ์ฅ ์ ๋ ด)
๋ผ์ดํ์ฌ์ดํด ์ ์ฑ
์ผ๋ก ์๋ ์ ํ:
{
"Rules": [
{
"Id": "MoveToIA",
"Status": "Enabled",
"Transitions": [
{
"Days": 30,
"StorageClass": "STANDARD_IA"
},
{
"Days": 90,
"StorageClass": "GLACIER"
}
]
}
]
}
์ ๊ทผ์ ์ด ๊ด์ ์์ ์ฃผ์ํ ์ : Glacier์์ ๋ฐ์ดํฐ๋ฅผ ๋ณต์ํ ๋๋ ์ถ๊ฐ ๊ถํ์ด ํ์ํด:
{
"Effect": "Allow",
"Action": [
"s3:RestoreObject",
"s3:GetObject"
],
"Resource": "arn:aws:s3:::archive-bucket/*"
}
๐ ์ค๋ณต ์ ๊ฑฐ์ ์์ถ
S3๋ ์๋ ์ค๋ณต ์ ๊ฑฐ๋ฅผ ํ์ง ์์. ์ ํ๋ฆฌ์ผ์ด์
๋ ๋ฒจ์์ ์ฒ๋ฆฌํด์ผ ํด:
1. ์
๋ก๋ ์ ์ค๋ณต ์ฒดํฌ: ๊ฐ์ฒด์ MD5 ํด์๋ฅผ ๊ณ์ฐํ๊ณ , ์ด๋ฏธ ์กด์ฌํ๋์ง ํ์ธ
2. ์์ถ: ํ
์คํธ ํ์ผ์ gzip์ผ๋ก ์์ถํ๋ฉด 70-90% ์ฉ๋ ์ ๊ฐ
3. Delta ์
๋ก๋: ๋ณ๊ฒฝ๋ ๋ถ๋ถ๋ง ์
๋ก๋
Lambda ํจ์๋ก ์๋ํํ ์ ์์ด:
exports.handler = async (event) => {
const s3 = new AWS.S3();
const bucket = event.Records[0].s3.bucket.name;
const key = event.Records[0].s3.object.key;
// ๊ฐ์ฒด ๋ค์ด๋ก๋
const object = await s3.getObject({ Bucket: bucket, Key: key }).promise();
// ์์ถ
const compressed = zlib.gzipSync(object.Body);
// ์์ถ๋ ๋ฒ์ ์
๋ก๋
await s3.putObject({
Bucket: bucket,
Key: key + '.gz',
Body: compressed,
ContentEncoding: 'gzip'
}).promise();
// ์๋ณธ ์ญ์ (์ ํ์ฌํญ)
await s3.deleteObject({ Bucket: bucket, Key: key }).promise();
};
๐ ์์ฒญ ๋น์ฉ ์ต์ ํ
S3๋ ์์ฒญ ํ์์ ๋ฐ๋ผ์๋ ๊ณผ๊ธ๋ผ. ํนํ LIST ์์ฒญ์ด ๋น์ธ:
์ต์ ํ ํ:
1. ๋ฐฐ์น ์ฒ๋ฆฌ: ์ฌ๋ฌ ๊ฐ์ฒด๋ฅผ ํ ๋ฒ์ ์ฒ๋ฆฌ
2. S3 Inventory ์ฌ์ฉ: LIST ๋์ Inventory ๋ฆฌํฌํธ ํ์ฉ
3. ์บ์ฑ: CloudFront๋ ElastiCache๋ก ์์ฃผ ์ ๊ทผํ๋ ๋ฐ์ดํฐ ์บ์ฑ
4. S3 Select ํ์ฉ: ์ ์ฒด ๊ฐ์ฒด ๋์ ํ์ํ ๋ถ๋ถ๋ง ๊ฐ์ ธ์ค๊ธฐ
S3 Inventory ์ค์ :
aws s3api put-bucket-inventory-configuration \
--bucket my-bucket \
--id daily-inventory \
--inventory-configuration '{
"Destination": {
"S3BucketDestination": {
"Bucket": "arn:aws:s3:::inventory-bucket",
"Format": "Parquet"
}
},
"IsEnabled": true,
"Id": "daily-inventory",
"IncludedObjectVersions": "Current",
"Schedule": {
"Frequency": "Daily"
}
}'
Inventory๋ฅผ ์ฌ์ฉํ๋ฉด LIST API๋ฅผ ํธ์ถํ์ง ์๊ณ ๋ ๋ฒํท ๋ด์ฉ์ ํ์ ํ ์ ์์ด. ๋น์ฉ์ด ํฌ๊ฒ ์ ๊ฐ๋ผ! ๐
๐ ๋ฐ์ดํฐ ์ ์ก ๋น์ฉ ์ ๊ฐ
AWS์์ ๋ฐ์ดํฐ๋ฅผ ๋ด๋ณด๋ผ ๋(egress) ๋น์ฉ์ด ๋ฐ์ํด. ์ด๋ฅผ ์ค์ด๋ ๋ฐฉ๋ฒ:
1. CloudFront ์ฌ์ฉ: CloudFront๋ฅผ ํตํ ์ ์ก์ด ์ง์ S3๋ณด๋ค ์ ๋ ดํ ์ ์์ด
2. ๋ฆฌ์ ์ ํ: ์ฌ์ฉ์์ ๊ฐ๊น์ด ๋ฆฌ์ ์ฌ์ฉ
3. VPC ์๋ํฌ์ธํธ: ๊ฐ์ ๋ฆฌ์ ๋ด ์ ์ก์ ๋ฌด๋ฃ
4. S3 Transfer Acceleration: ์ฅ๊ฑฐ๋ฆฌ ์ ์ก ์ต์ ํ
VPC ์๋ํฌ์ธํธ ์ ์ฑ
์ผ๋ก ๋น์ฉ ์ ์ด:
{
"Statement": [
{
"Sid": "RestrictToVPCEndpoint",
"Effect": "Deny",
"Principal": "*",
"Action": "s3:*",
"Resource": [
"arn:aws:s3:::my-bucket",
"arn:aws:s3:::my-bucket/*"
],
"Condition": {
"StringNotEquals": {
"aws:SourceVpce": "vpce-1234567"
}
}
}
]
}
์ด๋ ๊ฒ ํ๋ฉด VPC ์๋ํฌ์ธํธ๋ฅผ ํตํ ์ ๊ทผ๋ง ํ์ฉํด์ ๋ฐ์ดํฐ ์ ์ก ๋น์ฉ์ ์ ๋ก๋ก ๋ง๋ค ์ ์์ด! ๐ฏ
๐ก ๋น์ฉ ๋ชจ๋ํฐ๋ง
AWS Cost Explorer์ S3 Storage Lens๋ฅผ ํ์ฉํด์ ๋น์ฉ์ ์ง์์ ์ผ๋ก ๋ชจ๋ํฐ๋งํด:
๋น์ฉ ์๋ ์ค์ :
aws cloudwatch put-metric-alarm \
--alarm-name s3-cost-alarm \
--alarm-description "Alert when S3 cost exceeds threshold" \
--metric-name EstimatedCharges \
--namespace AWS/Billing \
--statistic Maximum \
--period 21600 \
--evaluation-periods 1 \
--threshold 1000 \
--comparison-operator GreaterThanThreshold \
--dimensions Name=ServiceName,Value=AmazonS3
๋น์ฉ ์ด์ ํ์ง:
AWS Cost Anomaly Detection์ ํ์ฑํํ๋ฉด ๋น์ ์์ ์ธ ๋น์ฉ ์ฆ๊ฐ๋ฅผ ์๋์ผ๋ก ๊ฐ์งํ๊ณ ์๋ ค์ค. ์ค์๋ก ๋๋์ ๋ฐ์ดํฐ๋ฅผ ์
๋ก๋ํ๊ฑฐ๋, ๊ณต๊ฒฉ์ ๋ฐ๋ ๊ฒฝ์ฐ๋ฅผ ๋น ๋ฅด๊ฒ ๋ฐ๊ฒฌํ ์ ์์ด!
1. Intelligent-Tiering์ผ๋ก ์๋ ์ต์ ํ (40% ์ ๊ฐ)
2. ์ค๋๋ ๋ฒ์ ์๋ ์ญ์ (20% ์ ๊ฐ)
3. CloudFront ์บ์ฑ ๊ฐํ (15% ์ ๊ฐ)
4. ๋ถํ์ํ ๋ก๊ทธ ์ ๋ฆฌ (9% ์ ๊ฐ)
์์ ์ต์ ํ๋ค์ด ๋ชจ์ฌ์ ํฐ ํจ๊ณผ๋ฅผ ๋ง๋ค์ด๋ธ ๊ฑฐ์ผ!
๐ ํ์ต ๋ฆฌ์์ค์ ๋ค์ ๋จ๊ณ
์ฌ๊ธฐ๊น์ง S3 ์ ๊ทผ์ ์ด์ ๋ํด ์ ๋ง ๋ง์ ๊ฑธ ๋ฐฐ์ ์ด! ํ์ง๋ง ํด๋ผ์ฐ๋ ๊ธฐ์ ์ ๊ณ์ ๋ฐ์ ํ๊ณ ์์ด. ์ง์์ ์ผ๋ก ํ์ตํ๋ ๊ฒ ์ค์ํด. ๐
๐ ์ถ์ฒ ํ์ต ์๋ฃ
๊ณต์ ๋ฌธ์:
- AWS S3 User Guide: ๊ฐ์ฅ ์ ํํ๊ณ ์ต์ ์ ๋ณด
- AWS Security Best Practices: ๋ณด์ ๊ถ์ฅ์ฌํญ
- AWS Well-Architected Framework: ์ํคํ
์ฒ ์ค๊ณ ์์น
์จ๋ผ์ธ ๊ฐ์:
- AWS Skill Builder: AWS ๊ณต์ ๋ฌด๋ฃ ๊ต์ก
- A Cloud Guru: ์ค์ต ์ค์ฌ ๊ฐ์
- Udemy: ๋ค์ํ ํ๊ธ ๊ฐ์
์๊ฒฉ์ฆ:
- AWS Certified Solutions Architect: S3 ํฌํจ ์ ๋ฐ์ ์ธ AWS ์ง์
- AWS Certified Security - Specialty: ๋ณด์ ์ ๋ฌธ ์๊ฒฉ์ฆ
- AWS Certified DevOps Engineer: ์ด์ ์๋ํ ์ค์ฌ
์๊ฒฉ์ฆ ์ค๋นํ๋ฉด์ ์ค๋ฌด ์ง์๋ ํจ๊ป ์์ ์ ์์ด!
๐ ๏ธ ์ค์ต ํ๋ก์ ํธ ์์ด๋์ด
์ด๋ก ๋ง ๊ณต๋ถํ๋ฉด ๊ธ๋ฐฉ ์์ด๋ฒ๋ ค. ์ง์ ํด๋ณด๋ ๊ฒ ์ต๊ณ ์ ํ์ต ๋ฐฉ๋ฒ์ด์ผ:
์ด๊ธ ํ๋ก์ ํธ:
1. ์ ์ ์น์ฌ์ดํธ ํธ์คํ
with CloudFront
2. ์ฌ์ง ๊ณต์ ์ฑ (์
๋ก๋/๋ค์ด๋ก๋ ๊ถํ ๋ถ๋ฆฌ)
3. ๋ก๊ทธ ์์ง ์์คํ
(์ฌ๋ฌ ์์ค์์ S3๋ก)
์ค๊ธ ํ๋ก์ ํธ:
1. ๋ฉํฐ ํ
๋ํธ SaaS ์คํ ๋ฆฌ์ง (ํ
๋ํธ๋ณ ๊ฒฉ๋ฆฌ)
2. ๋ฐ์ดํฐ ๋ ์ดํฌ ๊ตฌ์ถ (๋ถ์๋ณ ์ ๊ทผ์ ์ด)
3. ๋ฐฑ์
์๋ํ ์์คํ
(์ํธํ, ๋ฒ์ ๊ด๋ฆฌ)
๊ณ ๊ธ ํ๋ก์ ํธ:
1. ๊ธ๋ก๋ฒ CDN with ๋ฉํฐ ๋ฆฌ์ ๋ณต์
2. ์ปดํ๋ผ์ด์ธ์ค ์ค์ ์คํ ๋ฆฌ์ง (GDPR, HIPAA)
3. AI/ML ํ์ดํ๋ผ์ธ (SageMaker + S3)
ํ๋ก์ ํธ๋ฅผ ์งํํ๋ฉด์ ๋งํ๋ ๋ถ๋ถ์ด ์๋ค๋ฉด, ์ฌ๋ฅ๋ท์์ ๋ฉํ ๋ฅผ ์ฐพ์๋ณด๋ ๊ฒ๋ ์ข์ ๋ฐฉ๋ฒ์ด์ผ!
๐ ์ปค๋ฎค๋ํฐ ์ฐธ์ฌ
ํผ์ ๊ณต๋ถํ๋ฉด ์ธ๋กญ๊ณ ํ๋ค ์ ์์ด. ์ปค๋ฎค๋ํฐ์ ์ฐธ์ฌํด๋ด:
- AWS ํ๊ตญ ์ฌ์ฉ์ ๋ชจ์: ์ ๊ธฐ ๋ฐ์
๊ณผ ์ธ๋ฏธ๋
- Reddit r/aws: ๊ธ๋ก๋ฒ ์ปค๋ฎค๋ํฐ
- Stack Overflow: ๊ธฐ์ Q&A
- AWS re:Post: AWS ๊ณต์ ์ปค๋ฎค๋ํฐ
- LinkedIn ๊ทธ๋ฃน: ์ ๋ฌธ๊ฐ ๋คํธ์ํน
๋ค๋ฅธ ์ฌ๋๋ค์ ๊ฒฝํ์ ๋ฃ๊ณ , ์ง๋ฌธํ๊ณ , ๋ต๋ณํ๋ฉด์ ์ค๋ ฅ์ด ์ฅ์ฅ ๋์ด๋ ๊ฑฐ์ผ! ๐
๐ฎ ๋ฏธ๋ ํธ๋ ๋
์์ผ๋ก S3์ ํด๋ผ์ฐ๋ ์คํ ๋ฆฌ์ง๋ ์ด๋ป๊ฒ ๋ฐ์ ํ ๊น?
์์๋๋ ๋ณํ:
1. AI ๊ธฐ๋ฐ ์๋ ์ต์ ํ: ์ ๊ทผ ํจํด์ ํ์ตํด์ ์๋์ผ๋ก ์ ์ฑ
์กฐ์
2. ์ ๋ก ํธ๋ฌ์คํธ ์ํคํ
์ฒ: ๋ชจ๋ ์ ๊ทผ์ ๊ฒ์ฆํ๋ ๋ณด์ ๋ชจ๋ธ
3. ์ฃ์ง ์ปดํจํ
ํตํฉ: IoT ๊ธฐ๊ธฐ์ S3์ ๊ธด๋ฐํ ์ฐ๋
4. ์์ ์ํธํ: ์์ ์ปดํจํฐ ์๋๋ฅผ ๋๋นํ ์ํธํ
5. ํ์ ์ค๋ฆฝ ์คํ ๋ฆฌ์ง: ํ๊ฒฝ์ ๊ณ ๋ คํ ์คํ ๋ฆฌ์ง ์ ํ
์ด๋ฐ ํธ๋ ๋๋ฅผ ๋ฏธ๋ฆฌ ์๊ณ ์ค๋นํ๋ฉด ๊ฒฝ์๋ ฅ์ ์ ์งํ ์ ์์ด!
๐ผ ์ปค๋ฆฌ์ด ๋ฐ์
S3 ์ ๊ทผ์ ์ด ์ ๋ฌธ์ฑ์ ๋ค์ํ ์ปค๋ฆฌ์ด ๊ฒฝ๋ก๋ก ์ด์ด์ง ์ ์์ด:
- ํด๋ผ์ฐ๋ ์ํคํ
ํธ: ์ ์ฒด ์์คํ
์ค๊ณ
- ๋ณด์ ์์ง๋์ด: ํด๋ผ์ฐ๋ ๋ณด์ ์ ๋ฌธ
- DevOps ์์ง๋์ด: ์๋ํ์ ์ด์
- ๋ฐ์ดํฐ ์์ง๋์ด: ๋ฐ์ดํฐ ํ์ดํ๋ผ์ธ ๊ตฌ์ถ
- ์ปจ์คํดํธ: ๊ธฐ์
ํด๋ผ์ฐ๋ ์ ํ ์ง์
๊ฐ ๋ถ์ผ๋ง๋ค S3 ์ง์์ด ํ์์ ์ด์ผ. ํํํ ๊ธฐ์ด๋ฅผ ์์๋๋ฉด ์ด๋ค ๋ฐฉํฅ์ผ๋ก๋ ์ฑ์ฅํ ์ ์์ด! ๐ฑ
๐ฌ ๋ง๋ฌด๋ฆฌํ๋ฉฐ
์! ์ ๋ง ๊ธด ์ฌ์ ์ด์์ง? ๐
S3 ์ ๊ทผ์ ์ด์ ๊ธฐ์ด๋ถํฐ ๊ณ ๊ธ ์ฃผ์ ๊น์ง, ์ค์ ์๋๋ฆฌ์ค์ ํธ๋ฌ๋ธ์ํ
, ๋น์ฉ ์ต์ ํ๊น์ง ๋ชจ๋ ๋ค๋ค์ด.
ํต์ฌ์ ๋ค์ ํ๋ฒ ์ ๋ฆฌํ๋ฉด:
โ
๋ค์ธต ๋ฐฉ์ด: IAM ์ ์ฑ
, ๋ฒํท ์ ์ฑ
, ACL, ๋ธ๋ก ํผ๋ธ๋ฆญ ์ก์ธ์ค๋ฅผ ์กฐํฉํด์ ์ฌ์ฉ
โ
์ต์ ๊ถํ: ๊ผญ ํ์ํ ๊ถํ๋ง ๋ถ์ฌ
โ
์ํธํ: ์ ์ฅ ๋ฐ์ดํฐ์ ์ ์ก ๋ฐ์ดํฐ ๋ชจ๋ ์ํธํ
โ
๋ชจ๋ํฐ๋ง: CloudTrail, GuardDuty, Macie๋ก ์ง์์ ๊ฐ์
โ
์๋ํ: Lambda, EventBridge๋ก ๋ณด์ ์ ์ฑ
์๋ ์ ์ฉ
โ
ํ
์คํธ: ์ ์ฑ
๋ณ๊ฒฝ ํ ๋ฐ๋์ ๊ฒ์ฆ
โ
๋ฌธ์ํ: ์ค์ ์ด์ ์ ๋ฐฉ๋ฒ์ ๊ธฐ๋ก
S3 ์ ๊ทผ์ ์ด๋ ํ ๋ฒ ์ค์ ํ๊ณ ๋๋๋ ๊ฒ ์๋์ผ. ์ง์์ ์ผ๋ก ๊ฒํ ํ๊ณ ๊ฐ์ ํด์ผ ํด. ์๋ก์ด ์ํ์ด ๋ํ๋๊ณ , AWS๋ ๊ณ์ ์ ๊ธฐ๋ฅ์ ์ถ์ํ๋๊น ๋ง์ด์ผ.
์ฒ์์๋ ๋ณต์กํ๊ณ ์ด๋ ต๊ฒ ๋๊ปด์ง ์ ์์ด. ํ์ง๋ง ํ๋์ฉ ์ฐจ๊ทผ์ฐจ๊ทผ ์ตํ๋ค ๋ณด๋ฉด ์ด๋์ ์ ๋ฌธ๊ฐ๊ฐ ๋์ด ์์ ๊ฑฐ์ผ! ๐ช
ํน์ ๋งํ๋ ๋ถ๋ถ์ด ์๊ฑฐ๋, ๋ ๊น์ด ๋ฐฐ์ฐ๊ณ ์ถ๋ค๋ฉด ์ฃผ์ ํ์ง ๋ง๊ณ ๋์์ ์์ฒญํด. AWS ์ปค๋ฎค๋ํฐ๋ ์ ๋ง ์น์ ํ๊ณ , ์ฌ๋ฅ๋ท ๊ฐ์ ํ๋ซํผ์์๋ ์ค๋ฌด ์ ๋ฌธ๊ฐ๋ค์ ์กฐ์ธ์ ๋ฐ์ ์ ์์ด.
ํด๋ผ์ฐ๋ ๋ณด์์ ์ ํ์ด ์๋๋ผ ํ์์ผ. ์ค๋ ๋ฐฐ์ด ๋ด์ฉ์ ๋ฐํ์ผ๋ก ์์ ํ๊ณ ํจ์จ์ ์ธ S3 ํ๊ฒฝ์ ๊ตฌ์ถํ๊ธธ ๋ฐ๋ผ! ๐
์ง๋ฌธ์ด๋ ํผ๋๋ฐฑ์ด ์๋ค๋ฉด ์ธ์ ๋ ํ์์ด์ผ. ํจ๊ป ์ฑ์ฅํ๋ ํด๋ผ์ฐ๋ ์ปค๋ฎค๋ํฐ๋ฅผ ๋ง๋ค์ด๊ฐ์! ๐
ํ์ด์ ๋น์ด! Happy Cloud Computing! โ๏ธโจ
๊ด๋ จ ํค์๋
๋๊ธ ์์ฑ
์ด ๊ธ์ ๋ํ ์ฌ๋ฌ๋ถ์ ์๊ฐ์ ๋ค๋ ค์ฃผ์ธ์
๋ก๊ทธ์ธ์ด ํ์ํฉ๋๋ค
๋๊ธ์ ์์ฑํ๋ ค๋ฉด ๋จผ์ ๋ก๊ทธ์ธํด์ฃผ์ธ์.
๋๊ธ 0
์ง์์ธ์ ์ฒ - ์ง์ ์ฌ์ฐ๊ถ ๋ณดํธ ๊ณ ์ง
์ง์ ์ฌ์ฐ๊ถ ๋ณดํธ ๊ณ ์ง
- ์ ์๊ถ ๋ฐ ์์ ๊ถ: ๋ณธ ์ปจํ ์ธ ๋ ์ฌ๋ฅ๋ท์ ๋ ์ AI ๊ธฐ์ ๋ก ์์ฑ๋์์ผ๋ฉฐ, ๋ํ๋ฏผ๊ตญ ์ ์๊ถ๋ฒ ๋ฐ ๊ตญ์ ์ ์๊ถ ํ์ฝ์ ์ํด ๋ณดํธ๋ฉ๋๋ค.
- AI ์์ฑ ์ปจํ ์ธ ์ ๋ฒ์ ์ง์: ๋ณธ AI ์์ฑ ์ปจํ ์ธ ๋ ์ฌ๋ฅ๋ท์ ์ง์ ์ฐฝ์๋ฌผ๋ก ์ธ์ ๋๋ฉฐ, ๊ด๋ จ ๋ฒ๊ท์ ๋ฐ๋ผ ์ ์๊ถ ๋ณดํธ๋ฅผ ๋ฐ์ต๋๋ค.
- ์ฌ์ฉ ์ ํ: ์ฌ๋ฅ๋ท์ ๋ช ์์ ์๋ฉด ๋์ ์์ด ๋ณธ ์ปจํ ์ธ ๋ฅผ ๋ณต์ , ์์ , ๋ฐฐํฌ, ๋๋ ์์ ์ ์ผ๋ก ํ์ฉํ๋ ํ์๋ ์๊ฒฉํ ๊ธ์ง๋ฉ๋๋ค.
- ๋ฐ์ดํฐ ์์ง ๊ธ์ง: ๋ณธ ์ปจํ ์ธ ์ ๋ํ ๋ฌด๋จ ์คํฌ๋ํ, ํฌ๋กค๋ง, ๋ฐ ์๋ํ๋ ๋ฐ์ดํฐ ์์ง์ ๋ฒ์ ์ ์ฌ์ ๋์์ด ๋ฉ๋๋ค.
- AI ํ์ต ์ ํ: ์ฌ๋ฅ๋ท์ AI ์์ฑ ์ปจํ ์ธ ๋ฅผ ํ AI ๋ชจ๋ธ ํ์ต์ ๋ฌด๋จ ์ฌ์ฉํ๋ ํ์๋ ๊ธ์ง๋๋ฉฐ, ์ด๋ ์ง์ ์ฌ์ฐ๊ถ ์นจํด๋ก ๊ฐ์ฃผ๋ฉ๋๋ค.
์์ง ๋๊ธ์ด ์์ต๋๋ค.