DuckDB의 저장 데이터 암호화 기능
(duckdb.org)- DuckDB 1.4 버전부터 저장 데이터 암호화(Data-at-Rest Encryption) 기능이 추가되어, 데이터베이스 파일 전체를 AES 기반 표준 암호화로 보호 가능
- 지원 알고리듬은 AES-GCM-256과 AES-CTR-256, 이 중 GCM은 데이터 무결성 검증을 위한 인증 태그(tag) 를 포함
- 암호화는 데이터베이스 파일, WAL(Write-Ahead Log), 임시 파일 모두에 적용되며, 키 관리와 메모리 보호를 위한 보안 캐시 구조를 포함
- OpenSSL과 Mbed TLS 두 가지 구현이 제공되며, OpenSSL 사용 시 하드웨어 가속으로 성능 저하가 거의 없음
- 암호화된 DuckDB 파일은 보안성과 이식성을 동시에 확보하며, 클라우드나 CDN 환경에서도 안전한 데이터 배포 가능
암호화 개요
- DuckDB 1.4부터 데이터베이스 파일 전체를 투명하게 암호화(Transparent Encryption) 가능
- 저장 시 AES-GCM-256 또는 AES-CTR-256 암호화 사용
- AES-GCM은 무결성 검증을 위한 태그를 계산하며, AES-CTR은 더 빠르지만 인증 기능이 없음
- AES는 대칭키 암호화 알고리듬으로, 동일한 키로 암호화와 복호화를 수행
- IV(Initialization Vector)와 nonce를 사용해 동일 평문이 다른 암호문으로 변환되도록 보장
- NIST 표준 요건은 아직 완전히 충족하지 않음
DuckDB 내부 구현 구조
- 데이터베이스 파일의 메인 헤더는 평문으로 유지되며, 암호화 여부를 나타내는 플래그와 암호화 메타데이터 저장
- 메타데이터에는 데이터베이스 식별자(salt), 암호화 알고리듬 정보, 암호화된 canary 포함
-
키 파생 함수(KDF) 를 통해 사용자 입력 키를 32바이트 보안 키로 변환
- 파생된 키는 보안 캐시에 저장되어 디스크로 스왑되지 않음
- 원본 키는 메모리에서 즉시 삭제
- 데이터 블록은 기본 256KB 단위로 저장되며, 암호화 시 블록 헤더에 nonce/IV와 태그가 추가되어 40바이트로 확장
- 체크섬은 암호화되어 저장
WAL(Write-Ahead Log) 암호화
- WAL은 트랜잭션 복구용 로그 파일로, DuckDB에서는 항목 단위로 암호화 수행
- 각 항목에 nonce와 태그를 추가하여 AES-GCM 방식으로 보호
- 암호화된 WAL 항목은 길이(평문) → nonce → 암호화된 체크섬 및 데이터 → 태그 순으로 구성
- 암호화 키가 지정된 데이터베이스에서는 WAL 암호화가 자동 활성화
임시 파일 암호화
- 정렬, 조인, 윈도 함수 등 대용량 연산 시 생성되는 임시 파일도 자동 암호화
- 암호화된 데이터베이스를 연결하거나
SET temp_file_encryption = true설정 시 활성화 - DuckDB가 내부적으로 임시 키를 생성하며, 충돌 시 복호화 불가
- 암호화된 데이터베이스를 연결하거나
- 임시 파일은
.tmp또는.block확장자를 가지며, 크기 정보가 헤더에 포함- 체크섬은 계산 비용 절감을 위해 생략
암호화 사용 방법
- 세 가지 방식 지원:
- 기존 데이터베이스 암호화
- 새 암호화 데이터베이스 생성
- 기존 암호화 데이터베이스 재암호화
- 예시 명령:
ATTACH 'encrypted.duckdb' AS encrypted (ENCRYPTION_KEY 'asdf'); COPY FROM DATABASE unencrypted TO encrypted; - 암호화 여부는
FROM duckdb_databases();명령으로 확인 가능 - 기본 암호화 알고리듬은 AES-GCM, 필요 시 AES-CTR로 지정 가능
- 암호화된 데이터는 엔트로피(Entropy) 가 높아 무작위 데이터처럼 보임
구현 및 성능
- DuckDB는 외부 의존성을 최소화하기 위해 Mbed TLS와 OpenSSL 두 가지 암호화 구현을 포함
- Mbed TLS는 하드웨어 가속 비활성화로 성능이 낮고, 난수 생성기 취약점 발견으로 쓰기 기능 비활성화(1.4.1 이후)
- OpenSSL은 하드웨어 가속 및 안전한 난수 생성기를 사용,
httpfs확장 로드 시 자동 전환
- 성능 테스트 결과:
- 비암호화 SUMMARIZE 쿼리: 5.4초
- Mbed TLS 암호화: 6.2초
- OpenSSL 암호화: 5.4초 (성능 저하 없음)
- TPC-H Power/Throughput 테스트에서도 암호화 사용 시 성능 차이 미미
- Power@Size: 624,296 → 571,985
- Throughput@Size: 450,409 → 145,353 (디스크 I/O 증가 시 약간 감소)
결론
- DuckDB의 저장 데이터 암호화 기능으로 데이터베이스 파일 전체를 안전하게 보호 가능
- WAL과 임시 파일까지 암호화되어 클라우드 환경에서도 데이터 유출 위험 감소
- OpenSSL 기반 구현 시 성능 손실 거의 없음, 실무 환경에서도 효율적 사용 가능
- 암호화된 DuckDB 파일은 CDN 등 외부 배포에도 적합하며, 다중 테이블 저장 등 기존 기능 유지
- DuckDB 팀은 향후 사용자 피드백을 통해 기능 개선 예정
Hacker News 의견
-
AES-GCM의 nonce 재사용 민감도는 구현 시 까다로운 부분임
문서에서는 이를 인지하고 있지만 해결 방법을 공유하지 않았음
헤더에 12바이트 대신 16바이트 nonce가 포함되어 있고, 어떤 바이트가 랜덤인지 명시되지 않아 혼란스러움. 혹시 내가 놓친 부분이 있는지 궁금함- 정적 키를 사용하고, 12바이트 랜덤 nonce를 생성하며, 임시 버퍼에는 세션별 키를 사용하지 않는 구조임
-
DuckDB 팀의 성과에 계속 놀라고 있음
예전에 OpenSSL로 DuckDB 파일을 암호화하는 단순한 솔루션을 만들었는데, 첫 쿼리 시 2배의 실행 시간이 걸리고 메모리도 많이 사용했음
반면 DuckDB는 페이지 단위 암호화와 CPU의 AES 가속을 활용해 읽기/쓰기 비용이 거의 없는 수준임- 왜 그냥 LUKS를 쓰지 않는지 궁금함
커널 레벨에서 가속을 활용하고, 상위 애플리케이션에는 투명하게 동작함
여러 앱이 각기 다른 ACL과 키를 써야 하는 경우가 아니라면 DB 자체 암호화는 불필요함 - 솔직히 말해 DuckDB의 작업이 “놀라운” 수준은 아니라고 생각함
단순한 전체 파일 암호화 방식과 비교하면 당연히 좋아 보이지만, 이는 기본적인 수준의 구현임
우리 스스로도 이런 수준의 품질을 목표로 해야 함 - 결국 파이프라이닝 덕분임
저장소 입출력에 비하면 암호화 비용은 거의 무료에 가까움
- 왜 그냥 LUKS를 쓰지 않는지 궁금함
-
MotherDuck 외에 다중 사용자용 클라우드 기반 DuckDB를 잘 운영하는 모델이 있는지 궁금함
일반 DB처럼 여러 사용자가 동시에 접근하면서 DuckDB의 장점을 그대로 활용할 수 있는 구조를 찾고 있음- 순수 DuckDB만 쓴다면 Arrow Flight 서버를 앞단에 두거나 httpserver 확장을 사용할 수 있음
.duckdb파일을 어디에 저장하느냐(S3 vs EFS)에 따라 성능 차이가 큼
하지만 DuckLake가 더 나은 멀티플레이어 옵션으로 보임
우리는 DuckLake를 제품에 사용 중이며, 성능 저하를 줄이기 위해 분석용 테이블은 GCP Filestore 같은 빠른 스토리지에 저장함
하나의 DuckLake 카탈로그 안에서도 여러 스토리지 방식을 혼합할 수 있어 유연함 - 요즘 “Postgres 안의 DuckDB”라는 글을 자주 보는데, 아마 그게 원하는 형태일 것 같음
- GizmoSQL도 참고할 만함
- 순수 DuckDB만 쓴다면 Arrow Flight 서버를 앞단에 두거나 httpserver 확장을 사용할 수 있음
-
DuckDB는 지금까지 써본 AI 도구들보다 더 유용했음
LLM을 좋아하지만, 실제 업무 효율에서는 DuckDB가 훨씬 큰 도움을 줌 -
키의 인덱싱 처리 방식이 궁금함
검색 시 키를 암호화한 상태로 찾는지, 아니면 블록마다 복호화를 수행하는지 알고 싶음 -
“SQLite 암호화 확장은 2000달러 유료 애드온”이라는 말이 있지만,
SQLiteMultipleCiphers는 오래전부터 무료로 제공되고 있음
또한 Turso Database는 기본적으로 암호화를 지원함- 실제로 Python이나 Go에서 이런 변형된 SQLite를 플러그인과 함께 빌드해 사용하는 방법이 궁금함
언어별로 링크 과정이 까다로워 보임 -
SQLCipher도 있음
2009년부터 개발되어 안정적으로 동작하는 솔루션임
- 실제로 Python이나 Go에서 이런 변형된 SQLite를 플러그인과 함께 빌드해 사용하는 방법이 궁금함