Contents
🎯 AWS 보안 서비스🔑 암호화 기초 (Encryption 101)🔐 AWS KMS (Key Management Service)🗄️ AWS Systems Manager Parameter Store🔒 AWS Secrets Manager🛡️ AWS Certificate Manager (ACM)🔍 웹 애플리케이션 보안🛡️ AWS Shield - DDoS 보호🔥 AWS Firewall Manager🔍 위협 탐지 서비스📋 보안 모범 사례 체크리스트🎯 실전 시나리오🎓 보안 및 암호화💰 비용 최적화 팁🛠️ 트러블슈팅 가이드📚 참고 사이트🎯 AWS 보안 서비스
보안의 중요성
- 데이터 보호: 저장 및 전송 중 데이터 암호화
- 규정 준수: GDPR, HIPAA, PCI-DSS 등 요구사항 충족
- 비밀 관리: API 키, 패스워드 안전한 저장
- 위협 방어: DDoS, SQL Injection 등 공격 차단
보안 서비스 분류
┌─────────────────────────────────────────────┐
│ AWS 보안 서비스 계층 │
├─────────────────────────────────────────────┤
│ 암호화 관리 │ KMS, CloudHSM │
│ 비밀 관리 │ Secrets Manager, SSM │
│ 인증서 관리 │ ACM (Certificate Manager) │
│ 네트워크 보안 │ WAF, Shield, Firewall Mgr │
│ 위협 탐지 │ GuardDuty, Inspector │
│ 규정 준수 │ Macie, Config │
└─────────────────────────────────────────────┘
🔑 암호화 기초 (Encryption 101)
암호화의 두 가지 유형
1. 저장 데이터 암호화 (Encryption at Rest)
데이터가 디스크에 저장될 때 암호화
# 예: S3 객체 암호화
import boto3
s3 = boto3.client('s3')
# 서버 측 암호화로 업로드
s3.put_object(
Bucket='my-secure-bucket',
Key='sensitive-data.txt',
Body='Confidential Information',
ServerSideEncryption='AES256' # or 'aws:kms'
)
2. 전송 데이터 암호화 (Encryption in Transit)
네트워크를 통해 데이터가 이동할 때 암호화 (SSL/TLS)
# HTTPS 강제 S3 버킷 정책
{
"Version": "2012-10-17",
"Statement": [
{
"Sid": "DenyUnencryptedConnections",
"Effect": "Deny",
"Principal": "*",
"Action": "s3:*",
"Resource": "arn:aws:s3:::my-bucket/*",
"Condition": {
"Bool": {
"aws:SecureTransport": "false"
}
}
}
]
}
대칭 vs 비대칭 암호화
특성 | 대칭 암호화 | 비대칭 암호화 |
키 | 하나의 키 | 공개키 + 개인키 |
속도 | 빠름 | 느림 |
사용 사례 | 데이터 암호화 | 디지털 서명, 키 교환 |
알고리즘 | AES-256 | RSA, ECC |
AWS 서비스 | KMS (주로) | CloudHSM, ACM |
🔐 AWS KMS (Key Management Service)
KMS
AWS KMS는 암호화 키를 생성하고 관리하는 완전 관리형 서비스입니다. FIPS 140-2 레벨 2 검증을 받았으며 대부분의 AWS 서비스와 통합
KMS 주요 개념
1. Customer Master Key (CMK)
# KMS 키 생성
aws kms create-key \
--description "My application encryption key" \
--key-usage ENCRYPT_DECRYPT \
--origin AWS_KMS
# 별칭 생성
aws kms create-alias \
--alias-name alias/my-app-key \
--target-key-id 1234abcd-12ab-34cd-56ef-1234567890ab
2. 키 유형
- AWS 관리형 키: AWS 서비스가 자동 생성 (무료)
- 고객 관리형 키: 사용자가 직접 생성 및 관리
- AWS 소유 키: AWS가 소유하고 관리 (사용자 접근 불가)
# 고객 관리형 키로 데이터 암호화
import boto3
import base64
kms = boto3.client('kms')
# 데이터 암호화
plaintext = "Sensitive data"
response = kms.encrypt(
KeyId='alias/my-app-key',
Plaintext=plaintext.encode()
)
ciphertext = base64.b64encode(response['CiphertextBlob'])
print(f"Encrypted: {ciphertext.decode()}")
# 데이터 복호화
decrypt_response = kms.decrypt(
CiphertextBlob=base64.b64decode(ciphertext)
)
decrypted = decrypt_response['Plaintext'].decode()
print(f"Decrypted: {decrypted}")
KMS 키 정책
{
"Version": "2012-10-17",
"Statement": [
{
"Sid": "Enable IAM User Permissions",
"Effect": "Allow",
"Principal": {
"AWS": "arn:aws:iam::123456789012:root"
},
"Action": "kms:*",
"Resource": "*"
},
{
"Sid": "Allow use of the key for S3",
"Effect": "Allow",
"Principal": {
"Service": "s3.amazonaws.com"
},
"Action": [
"kms:Decrypt",
"kms:GenerateDataKey"
],
"Resource": "*"
}
]
}
CLI를 통한 KMS 실습
# 1. KMS 키 생성
KEY_ID=$(aws kms create-key --query 'KeyMetadata.KeyId' --output text)
# 2. 텍스트 파일 암호화
echo "Secret message" > plaintext.txt
aws kms encrypt \
--key-id $KEY_ID \
--plaintext fileb://plaintext.txt \
--output text \
--query CiphertextBlob | base64 -d > encrypted.bin
# 3. 복호화
aws kms decrypt \
--ciphertext-blob fileb://encrypted.bin \
--output text \
--query Plaintext | base64 -d
# 4. 키 로테이션 활성화
aws kms enable-key-rotation --key-id $KEY_ID
# 5. 키 비활성화
aws kms disable-key --key-id $KEY_ID
KMS Multi-Region Keys
멀티 리전 키를 사용하면 여러 리전에서 동일한 키 ID로 암호화/복호화가 가능합니다.
# 멀티 리전 키 생성 (주 리전)
aws kms create-key \
--multi-region \
--description "Multi-region key for global app"
# 복제 키 생성 (보조 리전)
aws kms replicate-key \
--key-id mrk-1234abcd \
--replica-region eu-west-1
사용 사례:
- 글로벌 애플리케이션의 재해 복구
- 리전 간 암호화된 데이터 공유
- 낮은 지연 시간의 암호화 작업
S3 암호화와 KMS
# S3 버킷 기본 암호화 설정
s3 = boto3.client('s3')
s3.put_bucket_encryption(
Bucket='my-encrypted-bucket',
ServerSideEncryptionConfiguration={
'Rules': [{
'ApplyServerSideEncryptionByDefault': {
'SSEAlgorithm': 'aws:kms',
'KMSMasterKeyID': 'alias/my-s3-key'
},
'BucketKeyEnabled': True
}]
}
)
🗄️ AWS Systems Manager Parameter Store
Parameter Store
안전한 계층적 스토리지로 구성 데이터와 비밀을 관리하고 무료 티어가 있어 소규모 프로젝트에 적합
파라미터 유형
- String: 일반 텍스트
- StringList: 쉼표로 구분된 값들
- SecureString: KMS로 암호화된 값
CLI를 통한 Parameter Store 실습
# 1. 일반 파라미터 생성
aws ssm put-parameter \
--name "/myapp/database/host" \
--value "db.example.com" \
--type String \
--description "Database host endpoint"
# 2. 암호화된 파라미터 생성
aws ssm put-parameter \
--name "/myapp/database/password" \
--value "MySecurePassword123!" \
--type SecureString \
--key-id alias/aws/ssm \
--description "Database password"
# 3. 파라미터 조회
aws ssm get-parameter \
--name "/myapp/database/password" \
--with-decryption
# 4. 경로 기반 조회 (계층 구조)
aws ssm get-parameters-by-path \
--path "/myapp/database" \
--recursive \
--with-decryption
# 5. 파라미터 업데이트
aws ssm put-parameter \
--name "/myapp/database/password" \
--value "NewPassword456!" \
--type SecureString \
--overwrite
# 6. 파라미터 삭제
aws ssm delete-parameter --name "/myapp/database/password"
Lambda에서 Parameter Store 사용
import boto3
import os
ssm = boto3.client('ssm')
def lambda_handler(event, context):
# 파라미터 조회
response = ssm.get_parameter(
Name='/myapp/database/password',
WithDecryption=True
)
db_password = response['Parameter']['Value']
# 데이터베이스 연결
import pymysql
connection = pymysql.connect(
host=os.environ['DB_HOST'],
user=os.environ['DB_USER'],
password=db_password,
database='myapp'
)
# ... 나머지 로직
Parameter Store 계층 구조 모범 사례
/myapp/
├── dev/
│ ├── database/
│ │ ├── host
│ │ ├── port
│ │ └── password
│ └── api/
│ ├── key
│ └── endpoint
├── staging/
│ └── ...
└── prod/
└── ...
🔒 AWS Secrets Manager
Secrets Manager
Secrets Manager는 데이터베이스 자격 증명, API 키 등의 비밀을 안전하게 저장하고 자동으로 로테이션하는 서비스
Parameter Store vs Secrets Manager
기능 | Parameter Store | Secrets Manager |
가격 | 무료/유료 티어 | 사용량 기반 ($0.40/비밀/월) |
자동 로테이션 | 없음 | 있음 |
최대 크기 | 8KB (표준), 4KB (고급) | 64KB |
교차 계정 접근 | 어려움 | 쉬움 |
사용 사례 | 구성 값, 비민감 데이터 | DB 자격 증명, API 키 |
Secrets Manager 실습
# 1. 비밀 생성
aws secretsmanager create-secret \
--name prod/myapp/database \
--description "Production database credentials" \
--secret-string '{
"username": "admin",
"password": "MySecurePassword123!",
"host": "db.example.com",
"port": "3306"
}'
# 2. 비밀 조회
aws secretsmanager get-secret-value \
--secret-id prod/myapp/database
# 3. 비밀 업데이트
aws secretsmanager update-secret \
--secret-id prod/myapp/database \
--secret-string '{
"username": "admin",
"password": "NewPassword456!",
"host": "db.example.com",
"port": "3306"
}'
# 4. 비밀 로테이션 설정
aws secretsmanager rotate-secret \
--secret-id prod/myapp/database \
--rotation-lambda-arn arn:aws:lambda:region:account:function:SecretsManagerRotation \
--rotation-rules AutomaticallyAfterDays=30
Lambda를 이용한 자동 로테이션
import boto3
import pymysql
import json
def lambda_handler(event, context):
"""RDS MySQL 패스워드 자동 로테이션"""
secretsmanager = boto3.client('secretsmanager')
# 현재 비밀 값 가져오기
current_secret = secretsmanager.get_secret_value(
SecretId=event['SecretId']
)
current_dict = json.loads(current_secret['SecretString'])
# 새 패스워드 생성
import secrets as secret_gen
new_password = secret_gen.token_urlsafe(32)
# 데이터베이스에 새 패스워드 설정
connection = pymysql.connect(
host=current_dict['host'],
user=current_dict['username'],
password=current_dict['password']
)
cursor = connection.cursor()
cursor.execute(
f"ALTER USER '{current_dict['username']}'@'%' IDENTIFIED BY '{new_password}'"
)
connection.commit()
connection.close()
# Secrets Manager 업데이트
new_secret = current_dict.copy()
new_secret['password'] = new_password
secretsmanager.update_secret(
SecretId=event['SecretId'],
SecretString=json.dumps(new_secret)
)
return {
'statusCode': 200,
'body': 'Password rotated successfully'
}
애플리케이션에서 Secrets Manager 사용
import boto3
import json
from botocore.exceptions import ClientError
def get_secret(secret_name):
"""Secrets Manager에서 비밀 조회"""
client = boto3.client('secretsmanager', region_name='us-east-1')
try:
response = client.get_secret_value(SecretId=secret_name)
except ClientError as e:
if e.response['Error']['Code'] == 'ResourceNotFoundException':
print(f"Secret {secret_name} not found")
raise e
else:
if 'SecretString' in response:
return json.loads(response['SecretString'])
else:
import base64
return base64.b64decode(response['SecretBinary'])
# 사용 예제
db_credentials = get_secret('prod/myapp/database')
connection = pymysql.connect(
host=db_credentials['host'],
user=db_credentials['username'],
password=db_credentials['password'],
database='myapp'
)
🛡️ AWS Certificate Manager (ACM)
ACM
AWS Certificate Manager는 SSL/TLS 인증서를 무료로 프로비저닝, 관리, 배포하는 서비스
ACM 주요 기능
- 무료 SSL/TLS 인증서: 공용 인증서 무료 발급
- 자동 갱신: 만료 전 자동으로 갱신
- AWS 서비스 통합: ELB, CloudFront, API Gateway 등
ACM 인증서 발급
# 1. 인증서 요청
aws acm request-certificate \
--domain-name example.com \
--subject-alternative-names *.example.com \
--validation-method DNS
# 2. 인증서 상태 확인
aws acm describe-certificate \
--certificate-arn arn:aws:acm:region:account:certificate/12345
# 3. 인증서 목록
aws acm list-certificates
# 4. 인증서 삭제
aws acm delete-certificate \
--certificate-arn arn:aws:acm:region:account:certificate/12345
도메인 검증 방법
DNS 검증 (권장)
# ACM이 제공하는 CNAME 레코드를 Route 53에 추가
aws route53 change-resource-record-sets \
--hosted-zone-id Z1234567890ABC \
--change-batch '{
"Changes": [{
"Action": "CREATE",
"ResourceRecordSet": {
"Name": "_abc123.example.com",
"Type": "CNAME",
"TTL": 300,
"ResourceRecords": [{"Value": "_xyz456.acm-validations.aws"}]
}
}]
}'
이메일 검증
- 도메인 관리자 이메일로 확인 링크 전송
- admin@, administrator@, hostmaster@ 등
CloudFront에 ACM 인증서 연결
import boto3
cloudfront = boto3.client('cloudfront')
# CloudFront 배포에 ACM 인증서 적용
response = cloudfront.update_distribution(
Id='E1234567890ABC',
DistributionConfig={
'ViewerCertificate': {
'ACMCertificateArn': 'arn:aws:acm:us-east-1:123456789012:certificate/abc-123',
'SSLSupportMethod': 'sni-only',
'MinimumProtocolVersion': 'TLSv1.2_2021'
},
# ... 기타 설정
}
)
🔍 웹 애플리케이션 보안
AWS WAF (Web Application Firewall)
WAF는 웹 애플리케이션을 일반적인 웹 공격으로부터 보호
WAF 핵심 개념
1. Web ACL (Access Control List)
# Web ACL 생성
aws wafv2 create-web-acl \
--name MyWebACL \
--scope REGIONAL \
--default-action Block={} \
--rules file://rules.json \
--visibility-config SampledRequestsEnabled=true,CloudWatchMetricsEnabled=true,MetricName=MyWebACL
2. Rule Groups
{
"Name": "SQLInjectionRuleGroup",
"Priority": 1,
"Statement": {
"ManagedRuleGroupStatement": {
"VendorName": "AWS",
"Name": "AWSManagedRulesSQLiRuleSet"
}
},
"VisibilityConfig": {
"SampledRequestsEnabled": true,
"CloudWatchMetricsEnabled": true,
"MetricName": "SQLInjectionRule"
}
}
WAF 규칙 유형
1. IP 기반 규칙
{
"Name": "BlockBadIPs",
"Priority": 0,
"Statement": {
"IPSetReferenceStatement": {
"Arn": "arn:aws:wafv2:region:account:regional/ipset/BadIPs/12345"
}
},
"Action": {
"Block": {}
}
}
2. 지리적 차단
{
"Name": "BlockCountries",
"Priority": 1,
"Statement": {
"GeoMatchStatement": {
"CountryCodes": ["KP", "IR"]
}
},
"Action": {
"Block": {}
}
}
3. Rate Limiting
{
"Name": "RateLimitRule",
"Priority": 2,
"Statement": {
"RateBasedStatement": {
"Limit": 2000,
"AggregateKeyType": "IP"
}
},
"Action": {
"Block": {}
}
}
AWS 관리형 규칙
import boto3
wafv2 = boto3.client('wafv2')
# AWS 관리형 규칙 그룹 추가
response = wafv2.update_web_acl(
Name='MyWebACL',
Scope='REGIONAL',
Id='web-acl-id',
Rules=[
{
'Name': 'AWSManagedRulesCommonRuleSet',
'Priority': 1,
'Statement': {
'ManagedRuleGroupStatement': {
'VendorName': 'AWS',
'Name': 'AWSManagedRulesCommonRuleSet'
}
},
'OverrideAction': {'None': {}},
'VisibilityConfig': {
'SampledRequestsEnabled': True,
'CloudWatchMetricsEnabled': True,
'MetricName': 'CommonRuleSet'
}
}
]
)
AWS 관리형 규칙 세트:
- Core Rule Set (CRS)
- SQL Injection Protection
- XSS Protection
- Known Bad Inputs
- Linux Operating System
- Windows Operating System
🛡️ AWS Shield - DDoS 보호
Shield 유형
1. AWS Shield Standard
- 무료
- 모든 AWS 고객에게 자동 제공
- Layer 3/4 DDoS 공격 방어
2. AWS Shield Advanced
- 유료 ($3,000/월)
- Layer 7 DDoS 공격 방어
- 24/7 DDoS Response Team (DRT)
- 비용 보호 (DDoS로 인한 비용 환불)
# Shield Advanced 구독
aws shield subscribe
# 보호 리소스 추가
aws shield create-protection \
--name "MyAppProtection" \
--resource-arn arn:aws:elasticloadbalancing:region:account:loadbalancer/app/my-alb/abc123
DDoS 모범 사례
┌──────────────────────────────────────┐
│ CloudFront (Shield Standard) │
│ - 엣지 로케이션에서 트래픽 분산 │
└──────────────┬───────────────────────┘
│
▼
┌──────────────────────────────────────┐
│ Route 53 (Shield Standard) │
│ - DNS 쿼리 플러드 방어 │
└──────────────┬───────────────────────┘
│
▼
┌──────────────────────────────────────┐
│ WAF (Rate Limiting) │
│ - Layer 7 공격 차단 │
└──────────────┬───────────────────────┘
│
▼
┌──────────────────────────────────────┐
│ ALB (Shield Standard) │
│ - Auto Scaling으로 확장 │
└──────────────┬───────────────────────┘
│
▼
┌──────────────────────────────────────┐
│ EC2 Auto Scaling Group │
└──────────────────────────────────────┘
🔥 AWS Firewall Manager
Firewall Manager
여러 계정과 리소스의 방화벽 규칙을 중앙에서 관리하는 서비스
주요 기능
- WAF 규칙 중앙 관리
- Shield Advanced 보호 자동 적용
- VPC Security Groups 관리
- AWS Network Firewall 정책 관리
# Firewall Manager 정책 생성
aws fms put-policy --policy '{
"PolicyName": "OrgWideWAFPolicy",
"SecurityServicePolicyData": {
"Type": "WAFV2",
"ManagedServiceData": "{\"type\":\"WAFV2\",\"preProcessRuleGroups\":[{\"ruleGroupArn\":null,\"overrideAction\":{\"type\":\"NONE\"},\"managedRuleGroupIdentifier\":{\"vendorName\":\"AWS\",\"managedRuleGroupName\":\"AWSManagedRulesCommonRuleSet\"},\"ruleGroupType\":\"ManagedRuleGroup\"}]}"
},
"ResourceType": "AWS::ElasticLoadBalancingV2::LoadBalancer",
"RemediationEnabled": true,
"IncludeMap": {
"ACCOUNT": ["123456789012", "234567890123"]
}
}'
🔍 위협 탐지 서비스
AWS GuardDuty
지능형 위협 탐지 서비스로, 머신러닝을 사용하여 비정상적인 활동을 감지
# GuardDuty 활성화
aws guardduty create-detector --enable
# 탐지 결과 조회
aws guardduty list-findings \
--detector-id 12abc34d567e8fa901bc2d34e56789f0
# 특정 탐지 결과 상세 정보
aws guardduty get-findings \
--detector-id 12abc34d567e8fa901bc2d34e56789f0 \
--finding-ids 04b8ab51c2e9e5e8c6e9d1234567890a
GuardDuty가 탐지하는 위협:
- EC2 인스턴스 침해
- 계정 탈취 시도
- 비정상적인 API 호출
- 암호화폐 채굴
- 데이터 유출 시도
AWS Inspector
EC2 인스턴스와 컨테이너의 보안 취약점을 자동으로 평가
# Inspector 활성화
aws inspector2 enable \
--resource-types EC2 ECR
# 평가 결과 조회
aws inspector2 list-findings \
--filter-criteria '{
"severity": [{"comparison": "EQUALS", "value": "CRITICAL"}]
}'
Inspector가 검사하는 항목:
- 소프트웨어 취약점 (CVE)
- 네트워크 노출
- 패키지 취약점
- 컨테이너 이미지 취약점
Amazon Macie
S3 버킷의 민감한 데이터를 자동으로 발견하고 보호
# Macie 활성화
aws macie2 enable-macie
# 민감한 데이터 검색 작업 생성
aws macie2 create-classification-job \
--job-type ONE_TIME \
--s3-job-definition '{
"bucketDefinitions": [{
"accountId": "123456789012",
"buckets": ["my-sensitive-bucket"]
}]
}' \
--name "PII-Detection-Job"
Macie가 탐지하는 데이터:
- 개인 식별 정보 (PII)
- 신용카드 번호
- 주민등록번호
- API 키 및 비밀 키
- 의료 정보 (PHI)
📋 보안 모범 사례 체크리스트
암호화
모든 S3 버킷에 기본 암호화 활성화
RDS 인스턴스 암호화 활성화
EBS 볼륨 암호화 활성화
KMS 키 로테이션 활성화
HTTPS/TLS 강제 (전송 중 암호화)
비밀 관리
하드코딩된 자격 증명 제거
Secrets Manager 또는 Parameter Store 사용
자동 비밀 로테이션 설정
최소 권한 원칙 적용
정기적인 비밀 감사
인증서 관리
ACM으로 SSL/TLS 인증서 관리
자동 갱신 활성화
강력한 암호화 프로토콜 사용 (TLSv1.2+)
인증서 만료 모니터링
웹 애플리케이션 보안
WAF 활성화 및 규칙 설정
Shield Standard/Advanced 활용
Rate Limiting 구성
SQL Injection, XSS 방어 규칙 적용
정기적인 규칙 업데이트
위협 탐지
GuardDuty 활성화
Inspector로 취약점 스캔
Macie로 민감한 데이터 보호
CloudWatch Alarms 설정
보안 이벤트 알림 구성
🎯 실전 시나리오
시나리오 1: 완전한 암호화 파이프라인 구축
import boto3
import json
class SecureDataPipeline:
def __init__(self):
self.kms = boto3.client('kms')
self.s3 = boto3.client('s3')
self.secretsmanager = boto3.client('secretsmanager')
def setup_encryption_key(self):
"""KMS 키 생성 및 설정"""
response = self.kms.create_key(
Description='Data pipeline encryption key',
KeyUsage='ENCRYPT_DECRYPT',
Origin='AWS_KMS'
)
key_id = response['KeyMetadata']['KeyId']
# 별칭 생성
self.kms.create_alias(
AliasName='alias/data-pipeline-key',
TargetKeyId=key_id
)
# 키 로테이션 활성화
self.kms.enable_key_rotation(KeyId=key_id)
return key_id
def create_encrypted_bucket(self, bucket_name, key_id):
"""암호화된 S3 버킷 생성"""
# 버킷 생성
self.s3.create_bucket(Bucket=bucket_name)
# 기본 암호화 설정
self.s3.put_bucket_encryption(
Bucket=bucket_name,
ServerSideEncryptionConfiguration={
'Rules': [{
'ApplyServerSideEncryptionByDefault': {
'SSEAlgorithm': 'aws:kms',
'KMSMasterKeyID': key_id
},
'BucketKeyEnabled': True
}]
}
)
# 버킷 정책: HTTPS 강제
bucket_policy = {
"Version": "2012-10-17",
"Statement": [{
"Sid": "DenyUnencryptedObjectUploads",
"Effect": "Deny",
"Principal": "*",
"Action": "s3:PutObject",
"Resource": f"arn:aws:s3:::{bucket_name}/*",
"Condition": {
"StringNotEquals": {
"s3:x-amz-server-side-encryption": "aws:kms"
}
}
}]
}
self.s3.put_bucket_policy(
Bucket=bucket_name,
Policy=json.dumps(bucket_policy)
)
def store_database_credentials(self, db_config):
"""데이터베이스 자격 증명을 Secrets Manager에 저장"""
secret_value = {
'username': db_config['username'],
'password': db_config['password'],
'engine': 'mysql',
'host': db_config['host'],
'port': db_config['port'],
'dbname': db_config['dbname']
}
response = self.secretsmanager.create_secret(
Name='prod/datawarehouse/credentials',
Description='Data warehouse database credentials',
SecretString=json.dumps(secret_value)
)
# 자동 로테이션 설정
self.secretsmanager.rotate_secret(
SecretId=response['ARN'],
RotationLambdaARN='arn:aws:lambda:region:account:function:SecretsManagerRotation',
RotationRules={'AutomaticallyAfterDays': 30}
)
return response['ARN']
# 사용 예제
pipeline = SecureDataPipeline()
key_id = pipeline.setup_encryption_key()
pipeline.create_encrypted_bucket('my-secure-data-lake', key_id)
pipeline.store_database_credentials({
'username': 'admin',
'password': 'SecurePass123!',
'host': 'db.example.com',
'port': 3306,
'dbname': 'warehouse'
})
시나리오 2: WAF를 이용한 웹 애플리케이션 보호
import boto3
class WebApplicationFirewall:
def __init__(self):
self.wafv2 = boto3.client('wafv2')
self.elbv2 = boto3.client('elbv2')
def create_ip_set(self, ip_addresses):
"""차단할 IP 세트 생성"""
response = self.wafv2.create_ip_set(
Scope='REGIONAL',
Name='BlockedIPs',
Description='Blocked IP addresses',
IPAddressVersion='IPV4',
Addresses=ip_addresses
)
return response['Summary']['ARN']
def create_web_acl(self, ip_set_arn):
"""Web ACL 생성"""
rules = [
{
'Name': 'BlockBadIPs',
'Priority': 0,
'Statement': {
'IPSetReferenceStatement': {
'Arn': ip_set_arn
}
},
'Action': {'Block': {}},
'VisibilityConfig': {
'SampledRequestsEnabled': True,
'CloudWatchMetricsEnabled': True,
'MetricName': 'BlockBadIPs'
}
},
{
'Name': 'RateLimitRule',
'Priority': 1,
'Statement': {
'RateBasedStatement': {
'Limit': 2000,
'AggregateKeyType': 'IP'
}
},
'Action': {'Block': {}},
'VisibilityConfig': {
'SampledRequestsEnabled': True,
'CloudWatchMetricsEnabled': True,
'MetricName': 'RateLimit'
}
},
{
'Name': 'AWSManagedRulesCommonRuleSet',
'Priority': 2,
'Statement': {
'ManagedRuleGroupStatement': {
'VendorName': 'AWS',
'Name': 'AWSManagedRulesCommonRuleSet',
'ExcludedRules': []
}
},
'OverrideAction': {'None': {}},
'VisibilityConfig': {
'SampledRequestsEnabled': True,
'CloudWatchMetricsEnabled': True,
'MetricName': 'AWS-AWSManagedRulesCommonRuleSet'
}
},
{
'Name': 'AWSManagedRulesSQLiRuleSet',
'Priority': 3,
'Statement': {
'ManagedRuleGroupStatement': {
'VendorName': 'AWS',
'Name': 'AWSManagedRulesSQLiRuleSet'
}
},
'OverrideAction': {'None': {}},
'VisibilityConfig': {
'SampledRequestsEnabled': True,
'CloudWatchMetricsEnabled': True,
'MetricName': 'AWS-AWSManagedRulesSQLiRuleSet'
}
}
]
response = self.wafv2.create_web_acl(
Scope='REGIONAL',
Name='MyWebApplicationACL',
DefaultAction={'Allow': {}},
Description='Web ACL for production application',
Rules=rules,
VisibilityConfig={
'SampledRequestsEnabled': True,
'CloudWatchMetricsEnabled': True,
'MetricName': 'MyWebACL'
}
)
return response['Summary']['ARN']
def associate_with_alb(self, web_acl_arn, alb_arn):
"""ALB와 Web ACL 연결"""
self.wafv2.associate_web_acl(
WebACLArn=web_acl_arn,
ResourceArn=alb_arn
)
def setup_cloudwatch_alarms(self, web_acl_name):
"""CloudWatch 알람 설정"""
cloudwatch = boto3.client('cloudwatch')
# 차단된 요청 알람
cloudwatch.put_metric_alarm(
AlarmName='WAF-HighBlockedRequests',
ComparisonOperator='GreaterThanThreshold',
EvaluationPeriods=1,
MetricName='BlockedRequests',
Namespace='AWS/WAFV2',
Period=300,
Statistic='Sum',
Threshold=1000,
ActionsEnabled=True,
AlarmActions=['arn:aws:sns:region:account:security-alerts'],
AlarmDescription='Alert when blocked requests exceed threshold',
Dimensions=[
{'Name': 'WebACL', 'Value': web_acl_name},
{'Name': 'Region', 'Value': 'us-east-1'},
{'Name': 'Rule', 'Value': 'ALL'}
]
)
# 사용 예제
waf = WebApplicationFirewall()
ip_set_arn = waf.create_ip_set(['192.0.2.0/24', '198.51.100.0/24'])
web_acl_arn = waf.create_web_acl(ip_set_arn)
waf.associate_with_alb(
web_acl_arn,
'arn:aws:elasticloadbalancing:region:account:loadbalancer/app/my-alb/1234567890'
)
waf.setup_cloudwatch_alarms('MyWebApplicationACL')
시나리오 3: 종합 보안 모니터링 대시보드
import boto3
from datetime import datetime, timedelta
class SecurityMonitoring:
def __init__(self):
self.guardduty = boto3.client('guardduty')
self.inspector = boto3.client('inspector2')
self.securityhub = boto3.client('securityhub')
self.cloudwatch = boto3.client('cloudwatch')
def get_guardduty_findings(self, severity=['HIGH', 'CRITICAL']):
"""GuardDuty 탐지 결과 조회"""
# Detector ID 가져오기
detectors = self.guardduty.list_detectors()
if not detectors['DetectorIds']:
return []
detector_id = detectors['DetectorIds'][0]
# Finding 조회
findings = self.guardduty.list_findings(
DetectorId=detector_id,
FindingCriteria={
'Criterion': {
'severity': {
'Gte': 7 # HIGH and CRITICAL
},
'service.archived': {
'Eq': ['false']
}
}
}
)
if not findings['FindingIds']:
return []
# Finding 상세 정보
details = self.guardduty.get_findings(
DetectorId=detector_id,
FindingIds=findings['FindingIds']
)
return details['Findings']
def get_inspector_vulnerabilities(self):
"""Inspector 취약점 조회"""
response = self.inspector.list_findings(
filterCriteria={
'severity': [
{'comparison': 'EQUALS', 'value': 'CRITICAL'},
{'comparison': 'EQUALS', 'value': 'HIGH'}
]
},
maxResults=100
)
return response['findings']
def create_security_dashboard(self):
"""CloudWatch 보안 대시보드 생성"""
dashboard_body = {
"widgets": [
{
"type": "metric",
"properties": {
"metrics": [
["AWS/WAFV2", "BlockedRequests", {"stat": "Sum"}],
[".", "AllowedRequests", {"stat": "Sum"}]
],
"period": 300,
"stat": "Average",
"region": "us-east-1",
"title": "WAF Requests",
"yAxis": {"left": {"min": 0}}
}
},
{
"type": "log",
"properties": {
"query": """
SOURCE '/aws/guardduty/findings'
| fields @timestamp, severity, type, title
| filter severity >= 7
| sort @timestamp desc
| limit 20
""",
"region": "us-east-1",
"title": "Recent GuardDuty Findings"
}
},
{
"type": "metric",
"properties": {
"metrics": [
["AWS/KMS", "SecondsUntilKeyMaterialExpiration"],
[".", "NumberOfNotFoundExceptions"]
],
"period": 3600,
"stat": "Average",
"region": "us-east-1",
"title": "KMS Key Health"
}
}
]
}
self.cloudwatch.put_dashboard(
DashboardName='SecurityMonitoring',
DashboardBody=json.dumps(dashboard_body)
)
def send_security_report(self):
"""일일 보안 리포트 전송"""
sns = boto3.client('sns')
# 데이터 수집
guardduty_findings = self.get_guardduty_findings()
inspector_vulns = self.get_inspector_vulnerabilities()
# 리포트 생성
report = f"""
Daily Security Report - {datetime.now().strftime('%Y-%m-%d')}
GuardDuty Findings:
- Total High/Critical: {len(guardduty_findings)}
Inspector Vulnerabilities:
- Total High/Critical: {len(inspector_vulns)}
Top Threats:
"""
for finding in guardduty_findings[:5]:
report += f"\n- {finding['Type']}: {finding['Title']}"
# SNS로 전송
sns.publish(
TopicArn='arn:aws:sns:region:account:security-reports',
Subject='Daily Security Report',
Message=report
)
# 사용 예제
monitor = SecurityMonitoring()
monitor.create_security_dashboard()
monitor.send_security_report()
🎓 보안 및 암호화
- Q: KMS와 CloudHSM의 주요 차이점은?
- A: KMS는 AWS 관리형 서비스 (멀티 테넌트), CloudHSM은 전용 하드웨어 (단일 테넌트)
- Q: Parameter Store와 Secrets Manager의 주요 차이는?
- A: Secrets Manager는 자동 로테이션과 교차 계정 접근 지원, Parameter Store는 저렴하지만 기능 제한
- Q: AWS Certificate Manager(ACM) 인증서는 어떤 서비스와 사용할 수 있나?
- A: ELB, CloudFront, API Gateway (EC2에는 직접 설치 불가)
- Q: WAF의 Rate-based rule은 어떤 공격을 방어하나?
- A: DDoS, Brute Force 공격
- Q: Shield Standard와 Shield Advanced의 차이는?
- A: Standard는 무료이며 Layer 3/4 방어, Advanced는 유료이며 Layer 7 방어와 DRT 지원
- Q: GuardDuty는 어떤 데이터 소스를 분석하나?
- A: VPC Flow Logs, CloudTrail 이벤트, DNS 로그
💰 비용 최적화 팁
KMS 비용 절감
# KMS 키 사용량 모니터링
cloudwatch = boto3.client('cloudwatch')
response = cloudwatch.get_metric_statistics(
Namespace='AWS/KMS',
MetricName='NumberOfCalls',
Dimensions=[
{'Name': 'KeyId', 'Value': 'your-key-id'}
],
StartTime=datetime.now() - timedelta(days=7),
EndTime=datetime.now(),
Period=86400,
Statistics=['Sum']
)
# S3 Bucket Keys 사용 (KMS API 호출 99% 감소)
s3 = boto3.client('s3')
s3.put_bucket_encryption(
Bucket='my-bucket',
ServerSideEncryptionConfiguration={
'Rules': [{
'ApplyServerSideEncryptionByDefault': {
'SSEAlgorithm': 'aws:kms',
'KMSMasterKeyID': 'alias/my-key'
},
'BucketKeyEnabled': True # 이것이 핵심!
}]
}
)
Secrets Manager vs Parameter Store 선택
요구사항 | 추천 서비스 | 월 비용 (10개 비밀) |
단순 구성 값 | Parameter Store | $0 |
DB 자격 증명 (로테이션 불필요) | Parameter Store | $0 |
DB 자격 증명 (자동 로테이션) | Secrets Manager | $4 |
교차 계정 접근 | Secrets Manager | $4 |
64KB 초과 값 | 별도 솔루션 | - |
WAF 비용 최적화
# 불필요한 규칙 제거
# Web ACL: $5/월
# 규칙: $1/월/규칙
# 요청: $0.60/백만 요청
# 비용 효율적인 규칙 구성
# 1. IP 차단: 높은 우선순위 (빠른 차단)
# 2. Rate Limiting: 중간 우선순위
# 3. 관리형 규칙: 필요한 것만 선택
🛠️ 트러블슈팅 가이드
KMS 키 접근 거부 오류
# 문제: "AccessDeniedException"
# 해결 방법:
# 1. 키 정책 확인
aws kms get-key-policy \
--key-id alias/my-key \
--policy-name default
# 2. IAM 정책 확인
aws iam get-user-policy \
--user-name my-user \
--policy-name KMSAccess
# 3. 키 상태 확인
aws kms describe-key --key-id alias/my-key
# 4. VPC 엔드포인트 확인 (VPC 내에서 접근 시)
aws ec2 describe-vpc-endpoints \
--filters "Name=service-name,Values=com.amazonaws.region.kms"
Secrets Manager 로테이션 실패
import boto3
import json
def troubleshoot_rotation():
sm = boto3.client('secretsmanager')
logs = boto3.client('logs')
# 로테이션 상태 확인
response = sm.describe_secret(
SecretId='my-secret'
)
if 'RotationEnabled' in response:
print(f"Rotation Enabled: {response['RotationEnabled']}")
print(f"Last Rotation: {response.get('LastRotatedDate')}")
# Lambda 로그 확인
lambda_arn = response['RotationLambdaARN']
function_name = lambda_arn.split(':')[-1]
log_group = f'/aws/lambda/{function_name}'
# 최근 로그 스트림
streams = logs.describe_log_streams(
logGroupName=log_group,
orderBy='LastEventTime',
descending=True,
limit=1
)
if streams['logStreams']:
# 로그 이벤트 조회
events = logs.get_log_events(
logGroupName=log_group,
logStreamName=streams['logStreams'][0]['logStreamName']
)
for event in events['events']:
print(event['message'])
troubleshoot_rotation()
WAF 규칙 False Positive 해결
def analyze_waf_blocked_requests():
"""WAF에서 차단된 요청 분석"""
wafv2 = boto3.client('wafv2')
# 샘플 요청 가져오기
response = wafv2.get_sampled_requests(
WebAclArn='arn:aws:wafv2:region:account:regional/webacl/name/id',
RuleMetricName='BlockedRequests',
Scope='REGIONAL',
TimeWindow={
'StartTime': datetime.now() - timedelta(hours=1),
'EndTime': datetime.now()
},
MaxItems=100
)
# 차단 패턴 분석
blocked_ips = {}
blocked_uris = {}
for sample in response['SampledRequests']:
request = sample['Request']
ip = request['ClientIP']
uri = request['URI']
blocked_ips[ip] = blocked_ips.get(ip, 0) + 1
blocked_uris[uri] = blocked_uris.get(uri, 0) + 1
print("Top Blocked IPs:")
for ip, count in sorted(blocked_ips.items(), key=lambda x: x[1], reverse=True)[:10]:
print(f" {ip}: {count} requests")
print("\nTop Blocked URIs:")
for uri, count in sorted(blocked_uris.items(), key=lambda x: x[1], reverse=True)[:10]:
print(f" {uri}: {count} requests")
analyze_waf_blocked_requests()
📚 참고 사이트
AWS 공식 문서
보안 프레임워크
AWS의 보안 및 암호화 서비스는 데이터와 애플리케이션을 보호하는 강력한 도구들로 각 서비스는 특정 목적에 최적화되어 있으며, 함께 사용할 때 최대의 효과를 발휘
암호화 계층:
- KMS: 암호화 키 관리의 중심
- CloudHSM: 규정 준수가 중요한 경우
- ACM: SSL/TLS 인증서 관리
비밀 관리:
- Parameter Store: 저렴하고 간단한 구성 관리
- Secrets Manager: 자동 로테이션이 필요한 경우
웹 보안:
- WAF: Layer 7 공격 방어
- Shield: DDoS 공격 방어
- Firewall Manager: 중앙 집중식 관리
위협 탐지:
- GuardDuty: 지능형 위협 탐지
- Inspector: 취약점 스캔
- Macie: 민감한 데이터 보호
- 모든 데이터에 암호화 적용 (저장 및 전송 중)
- 비밀 관리 시스템 구축 (Parameter Store 또는 Secrets Manager)
- WAF로 웹 애플리케이션 보호
- 위협 탐지 서비스 활성화 (GuardDuty, Inspector)
- 정기적인 보안 감사 및 개선
Share article