암호화: at-rest, in-transit, KMS, envelope encryption
데이터가 암호화되어 있다는 말은 무엇을 보호하는가
"우리 DB는 암호화되어 있습니다"라는 말을 들을 때 물어봐야 할 질문들이 있다.
- 디스크가 암호화되어 있는가, 아니면 컬럼 값이 암호화되어 있는가?
- 암호화 키는 어디에 있는가? 같은 서버에 있는가?
- DB에서 백업 파일로 복사할 때도 암호화가 유지되는가?
- 네트워크를 지나는 쿼리 결과는 암호화되는가?
- 키를 잃어버리면 어떻게 되는가?
암호화는 단일 기술이 아니라 데이터가 놓이는 상태에 따라 다른 통제가 필요하다. 이 장은 세 가지 상태인 저장(at-rest), 이동(in-transit), 사용(in-use)과, 키를 안전하게 다루는 KMS 및 envelope encryption 패턴을 운영 관점에서 정리한다.
1. Encryption at-rest: 저장된 데이터 암호화
at-rest 암호화는 데이터가 디스크, 오브젝트 스토리지, 스냅샷, 백업 파일 등 저장 매체에 있을 때 무단 물리 접근에 대한 보호다. 디스크를 분리해 가거나 스토리지 계층에 침입한 공격자로부터 데이터를 보호한다. 다만 DB에 정상 접근이 가능한 계정에게는 at-rest 암호화가 보호를 제공하지 않는다. 권한 통제는 별도로 필요하다.
1.1 Transparent Data Encryption (TDE)
TDE는 DB 엔진이 투명하게 디스크 쓰기 시점에 암호화하고, 읽기 시점에 복호화하는 방식이다. 애플리케이션 코드 변경 없이 적용할 수 있다.
| 엔진 | TDE 지원 | 비고 |
|---|---|---|
| MySQL (Enterprise) | 있음 | InnoDB tablespace 암호화, keyring 플러그인 필요 |
| MySQL (Community) | 제한적 | InnoDB 테이블 수준 암호화 (ENCRYPTION='Y') 가능 |
| PostgreSQL | 없음 (네이티브 TDE 미지원) | 파일시스템 수준 암호화 또는 pgcrypto |
| AWS RDS/Aurora | 있음 | 인스턴스 생성 시 활성화, AWS KMS 키 사용 |
| ClickHouse | 있음 | 디스크 레벨 암호화 설정 |
PostgreSQL은 16 버전까지 네이티브 TDE가 없다. AWS Aurora PostgreSQL, Azure Database for PostgreSQL, EDB 등 상용 배포판은 자체 TDE를 추가한다. 오픈소스 PostgreSQL은 파일시스템 암호화(LUKS, dm-crypt)나 pgcrypto를 사용한다.
중요한 제약: TDE는 DB 프로세스가 실행 중일 때는 데이터가 이미 복호화된 상태로 메모리에 있다. 즉, DB에 접속 가능한 공격자는 TDE가 있어도 데이터를 읽을 수 있다. TDE는 물리 디스크 탈취에 대한 보호다.
1.2 Object storage at-rest 암호화
S3, GCS, Azure Blob 모두 서버 사이드 암호화(SSE)를 기본 또는 옵션으로 제공한다.
| 옵션 | 설명 | 키 관리 |
|---|---|---|
| SSE-S3 (S3 기준) | AWS 관리 키 사용 | 완전 관리형, 키 통제 불가 |
| SSE-KMS | AWS KMS 키 사용 | 키 사용 감사, 교차 계정 공유 제어 |
| SSE-C | 고객 제공 키 | 키를 직접 관리, 복잡도 높음 |
데이터 플랫폼에서는 SSE-KMS가 기본 선택이다. KMS 키 사용 기록이 CloudTrail에 남아 감사가 가능하다.
1.3 암호화 알고리즘
at-rest 암호화의 사실상 표준은 AES-256-GCM이다. AES-256은 256비트 키를 사용하는 대칭 암호화로, GCM 모드는 인증 태그(AEAD)를 포함해 기밀성과 무결성을 동시에 제공한다. 변조된 데이터를 복호화 시도 시 오류가 발생한다.
2. Encryption in-transit: 이동 중 데이터 암호화
in-transit 암호화는 데이터가 네트워크를 지날 때 도청과 중간자 공격(MITM)을 막는다. 데이터 플랫폼에서 전송 경로는 여러 곳이다.
- 애플리케이션 → DB 연결
- 서비스 → 서비스 (마이크로서비스, 파이프라인 내부)
- 클라이언트 → API 서버
- DB 복제 (primary → replica)
- Kafka producer/consumer → broker
2.1 TLS 1.2와 1.3
현재 표준은 TLS 1.3이다. TLS 1.0/1.1은 여러 취약점이 알려져 있어 폐기되었다. TLS 1.2도 올바르게 설정하면 안전하지만, TLS 1.3이 핸드셰이크가 빠르고 더 강한 암호 제품군만 허용한다.
-- MySQL: TLS 연결 요구
ALTER USER 'pipeline-svc'@'%' REQUIRE SSL;
-- PostgreSQL: pg_hba.conf에서 hostssl 설정
-- hostssl all all 0.0.0.0/0 scram-sha-256인증서 관리에서 자주 발생하는 실수는 두 가지다.
- 만료된 인증서: 자동 갱신(Let's Encrypt + certbot, AWS ACM)을 사용하지 않으면 만료로 서비스가 중단된다.
- 인증서 검증 생략: TLS는 연결했지만 서버 인증서를 검증하지 않으면 MITM을 막지 못한다.
ssl_verify_cert=True,verify=True같은 설정이 코드에 있어야 한다.
2.2 mTLS (상호 TLS 인증)
일반 TLS는 서버만 인증서를 제시한다. mTLS는 클라이언트도 인증서를 제시해 양방향 인증을 한다. 서비스 메시 환경(Istio, Linkerd)이나 내부 마이크로서비스 통신에서 사용된다. Kafka 클러스터는 내부 통신에 mTLS를 사용할 수 있다.
3. KMS: 키 관리 서비스
암호화의 강도는 키를 얼마나 잘 관리하느냐에 달려 있다. 키가 데이터와 같은 위치에 있거나 권한 없는 사람이 접근 가능하면 암호화는 유명무실해진다.
KMS(Key Management Service)는 암호화 키의 생성, 저장, 교체, 감사, 폐기를 전담하는 서비스다. 주요 클라우드 KMS는 HSM(Hardware Security Module) 기반이다. 키가 HSM 경계 밖으로 절대 나가지 않는다.
3.1 CMK vs 데이터 암호화 직접 사용의 차이
KMS에서 데이터를 직접 암호화하려면 (Encrypt API) 데이터를 KMS 서버로 보내야 한다. 이는 느리고 비용이 높으며, 대용량 데이터에는 현실적이지 않다. 이 문제를 해결하는 것이 envelope encryption이다.
3.2 키 격리와 키 rotation
운영 원칙 두 가지다.
키 격리: 서비스나 데이터 분류별로 다른 키를 사용한다. 예를 들어 PII용 키, payment 데이터용 키, 일반 운영 데이터용 키를 분리한다. 키 하나가 침해되어도 전체 데이터가 노출되지 않는다.
자동 키 rotation: AWS KMS CMK는 연간 자동 rotation 설정을 지원한다. 이전 키 버전은 이전에 암호화된 데이터를 복호화하는 데 계속 사용 가능하다. 새 데이터는 새 키 버전으로 암호화된다. rotation 후에도 이전 ciphertext를 다시 암호화(re-encryption)할 필요가 없다.
4. Envelope encryption: 대규모 데이터를 안전하게 암호화하는 패턴
envelope encryption은 데이터를 직접 KMS로 보내지 않고, 로컬에서 빠른 대칭 키(DEK)로 데이터를 암호화하고, 그 DEK를 KMS 키(KEK)로 보호하는 패턴이다.
4.1 DEK와 KEK의 역할
| 키 유형 | 이름 | 역할 | 위치 |
|---|---|---|---|
| DEK (Data Encryption Key) | 데이터 암호화 키 | 실제 데이터를 AES-256으로 암호화 | 로컬 메모리 (사용 후 삭제) |
| KEK (Key Encryption Key) | 키 암호화 키 | DEK를 암호화(wrap)하고 보관 | KMS / HSM 내부 (절대 외부 노출 없음) |
저장소에 남는 것은 암호화된 데이터와 암호화된 DEK 두 가지다. KEK 없이는 DEK를 복호화할 수 없고, DEK 없이는 데이터를 복호화할 수 없다. 두 레이어가 모두 필요하다.
4.2 Envelope encryption의 장점
성능: KMS API를 통해 32바이트짜리 DEK만 주고받는다. 데이터 자체를 KMS 서버로 보내지 않아 TB급 데이터도 로컬에서 빠르게 암호화된다.
비용: AWS KMS GenerateDataKey 호출 비용은 Encrypt 직접 호출에 비해 수천~수만 배 적은 API 호출로 대용량 처리가 가능하다.
키 교체 효율성: KEK를 교체해도 이미 암호화된 데이터를 다시 암호화할 필요가 없다. 암호화된 DEK만 새 KEK로 다시 wrap하면 된다. 수십 TB 데이터를 키 교체마다 재처리하지 않아도 된다.
키 격리: 데이터셋마다 다른 DEK를 사용하면 특정 DEK 노출 시 그 DEK로 암호화된 데이터만 위험하다.
4.3 클라우드별 Envelope Encryption
AWS KMS의 GenerateDataKey API는 envelope encryption을 직접 지원한다. 평문 DEK와 암호화된 DEK를 함께 반환한다. S3, RDS, DynamoDB, EBS는 내부적으로 이 패턴을 사용한다.
Google Cloud KMS, Azure Key Vault도 동일한 패턴을 제공한다. 애플리케이션 레벨에서 직접 구현할 때는 Google Tink 같은 라이브러리가 패턴을 추상화해 준다.
5. 데이터 플랫폼 암호화 설계 체크포인트
데이터가 흐르는 경로별로 암호화를 확인한다.
5.1 Kafka 암호화
Kafka는 broker-broker, client-broker 통신에 TLS를 사용한다. 메시지 at-rest 암호화는 기본적으로 broker가 제공하지 않는다. PII가 포함된 토픽의 경우 producer에서 AES-256으로 메시지를 암호화하고(application-level), consumer에서 복호화하는 방식이 사용된다.
5.2 Spark shuffle 암호화
Spark는 shuffle 데이터를 노드 간에 주고받을 때 기본적으로 암호화하지 않는다. 민감 데이터를 처리하는 경우 spark.authenticate=true와 spark.network.crypto.enabled=true를 설정한다.
5.3 백업 암호화
백업 파일은 원본과 동일한 수준의 민감도를 가진다. 백업이 암호화되지 않으면 at-rest 암호화가 있는 원본 DB보다 더 쉬운 공격 경로가 된다.
- mysqldump:
--ssl플래그를 사용하고, dump 파일 자체는 gpg로 암호화하거나 암호화된 스토리지에 저장 - xtrabackup:
--encrypt옵션으로 백업 시점 암호화 - pg_basebackup:
--compress+ 저장 위치 SSE-KMS - RDS 스냅샷: KMS 키로 암호화 후 공유 시 교차 계정 키 권한 설정
6. 운영 체크리스트
| 질문 | 확인 방법 |
|---|---|
| production DB 볼륨과 스냅샷이 암호화되어 있는가? | RDS console, SHOW VARIABLES LIKE '%encrypt%' (MySQL) |
| S3/GCS 버킷의 모든 객체가 SSE-KMS로 암호화되어 있는가? | 버킷 정책, bucket encryption 설정 |
| DB 연결이 TLS를 요구하는가? | REQUIRE SSL (MySQL), hostssl (PostgreSQL pg_hba.conf) |
| TLS 인증서 만료일 모니터링이 있는가? | ACM 알림, Prometheus cert-manager exporter |
| KMS 키를 누가 사용했는지 감사 로그가 있는가? | CloudTrail KMS event, GCP Cloud Audit Logs |
| KMS 키가 서비스·환경별로 분리되어 있는가? | KMS key alias 목록, Key policy 검토 |
| 백업 파일이 암호화된 스토리지에 저장되는가? | 백업 위치, 스토리지 암호화 설정 |
| 소스 코드 또는 설정 파일에 키나 비밀이 평문으로 있는가? | secret scanning (trufflehog, git-secrets) |
7. 흔한 안티패턴
7.1 "DB는 암호화했으니 끝이다"
DB TDE는 디스크 레벨 보호다. export된 CSV, BI extract, 개발용 dump, query log에 원본 데이터가 그대로 남는 경우가 많다. 암호화 적용 범위를 주기적으로 확인해야 한다.
7.2 "키를 데이터 옆에 둔다"
암호화된 데이터와 같은 S3 버킷에 키 파일을 두거나, DB와 같은 서버에 키를 저장하면 함께 노출된다. 키는 반드시 별도의 KMS 또는 Vault에 있어야 한다.
7.3 "자체 암호화 알고리즘을 만든다"
XOR, ROT13, 자체 치환 암호는 보안이 없다. MD5나 SHA-1 해시를 "암호화"라고 부르는 경우도 있다. 대칭 암호화에는 AES-256-GCM, 비대칭에는 RSA-2048 이상 또는 EC(타원곡선) 표준을 사용한다.
7.4 "TLS는 했으니 인증서 검증을 끈다"
개발 편의성을 위해 TLS는 켜되 인증서 검증을 비활성화(verify=False, ssl_verify_cert=False)하면 암호화는 되지만 MITM을 막지 못한다. 프로덕션에서는 반드시 인증서 체인 검증이 활성화되어야 한다.
7.5 "키를 교체하면 모든 데이터를 다시 암호화해야 한다"
envelope encryption을 사용하면 KEK를 교체해도 데이터를 재처리할 필요가 없다. 이 패턴 없이 데이터를 직접 암호화했다면 키 교체가 실질적으로 불가능해져 키 rotation을 영원히 미루게 된다.
마무리: 암호화는 계층이다
at-rest 암호화는 물리 침해를 막는다. in-transit 암호화는 네트워크 도청을 막는다. KMS는 키를 안전하게 보관한다. envelope encryption은 대규모 데이터를 효율적으로 보호하는 패턴이다.
어느 하나만으로는 부족하다. DBA와 데이터 플랫폼 엔지니어는 "암호화했다"는 체크박스보다 데이터가 어디에 어떤 상태로 있는지, 각 상태에서 키 없이는 데이터를 읽을 수 없는지 를 확인해야 한다.
다음 장에서는 암호화와 함께 데이터를 보호하는 또 다른 수단인 마스킹, 토크나이제이션, 가명처리, 보존 정책 같은 개인정보 처리 기법을 다룬다.
References
- NIST SP 800-111, "Guide to Storage Encryption Technologies for End User Devices": https://csrc.nist.gov/pubs/sp/800/111/final
- AWS Documentation, "Envelope encryption": https://docs.aws.amazon.com/kms/latest/developerguide/concepts.html#enveloping
- Google Cloud Documentation, "Envelope encryption": https://cloud.google.com/kms/docs/envelope-encryption
- AWS Prescriptive Guidance, "Encryption with AWS KMS": https://docs.aws.amazon.com/prescriptive-guidance/latest/aws-kms-best-practices/data-protection-encryption.html
- MySQL Documentation, "InnoDB Data-at-Rest Encryption": https://dev.mysql.com/doc/refman/8.0/en/innodb-data-encryption.html
- PostgreSQL Documentation, "Encryption Options": https://www.postgresql.org/docs/current/encryption-options.html
- Percona, "MySQL Backup Encryption with Percona XtraBackup": https://docs.percona.com/percona-xtrabackup/latest/encrypt-backups.html
- Kubernetes Documentation, "Encrypting Confidential Data at Rest": https://kubernetes.io/docs/tasks/administer-cluster/encrypt-data/