서버를 멍청한 저장소로 두는 R2 암호문 스토리지

웹 · 앱 개발4분 읽기

제로널리지 아키텍처에서 서버의 이상적인 모습은 "멍청한 저장소"입니다. 파일이 무엇인지 모르고 열어 볼 수도 없으며 그저 암호문 덩어리를 받아 보관하고 돌려줄 뿐인 저장소. 이 원칙을 실제 클라우드 인프라 위에 올리려면 저장소 선택과 접근 경로 설계가 함께 맞물려야 합니다. Ciphek이 Cloudflare R2를 고르고 서버를 파일 바이트에서 떼어 낸 방식을 정리합니다.

스트리밍이 많은 서비스의 비용 구조

미디어 클라우드는 저장보다 전송에서 무너집니다. 사진과 영상은 자주 올리고 자주 재생되는데, 일반적인 클라우드 스토리지는 데이터를 내보낼 때마다 전송(egress) 비용을 물립니다. 재생이 늘수록 트래픽 비용이 사용량에 비례해 증가하니, 인기가 곧 비용 폭탄이 되는 구조입니다. 스트리밍을 전제하는 서비스에서 이 전송 과금은 설계 단계에서 반드시 풀어야 할 문제였습니다.

Cloudflare R2를 택한 가장 큰 이유가 여기 있습니다. R2는 S3 호환 API를 제공하면서 전송 비용이 없습니다. 저장 용량 과금만 있고 데이터를 얼마나 많이 내보내든 egress가 붙지 않으니, 스트리밍이 많아져도 트래픽 비용이 함께 뛰지 않습니다. 같은 워크로드를 일반적인 오브젝트 스토리지에 올리면 전송 비용만으로 운영이 어려워지는 것과 대비됩니다. S3 호환이라 필요하면 다른 저장소로 옮길 여지도 남습니다.

서버는 URL만 발급한다

멍청한 저장소 원칙을 지키려면 파일 바이트가 애플리케이션 서버를 경유하지 않아야 합니다. Ciphek의 Hono API 서버는 업로드나 다운로드 요청이 오면 권한을 확인한 뒤 짧은 수명의 presigned URL만 발급합니다. 실제 암호문 바이트는 브라우저와 R2 사이에서 직접 오가고 서버는 그 흐름에 끼어들지 않습니다. 이렇게 하면 서버는 대용량 트래픽을 나르는 부담에서 벗어나고 동시에 평문은 물론 암호문 바이트조차 서버 메모리를 지나지 않습니다.

presigned URL에는 짧은 만료 시간을 둡니다. 접근 권한을 시간으로 제한해, URL이 유출되더라도 짧은 창 밖에서는 쓸모가 없게 만듭니다. 브라우저는 청크를 올리거나 받을 때마다 필요한 범위의 URL을 서버에서 받아 R2에 직접 요청합니다. 권한 판단이라는 머리 역할은 서버가, 바이트를 나르는 힘 역할은 R2가 맡는 분업입니다. 이 분업이 제로널리지와 비용, 성능을 동시에 만족시키는 뼈대입니다.

저장되는 것은 오직 암호문

R2에 올라가는 것은 앞선 단계에서 브라우저가 암호화한 청크들입니다. 각 청크는 24바이트 논스와 그 뒤에 붙는 암호문을 이어 붙인 단순한 포맷으로 저장됩니다. 이 논스는 복호화에 반드시 필요하지만 비밀은 아니므로 암호문과 함께 보관해도 안전합니다. 파일은 파일 식별자별로 청크 인덱스에 따라 정리되어, 재생 시 필요한 조각만 골라 가져올 수 있습니다.

메타데이터도 마찬가지입니다. 파일명, 태그 같은 정보는 그 자체로 내용을 유추할 단서가 되므로, 이것들도 브라우저에서 암호화한 뒤 데이터베이스에 저장합니다. 즉 R2에는 암호화된 파일 본문이, 데이터베이스에는 암호화된 메타데이터가 들어가고 어느 쪽도 서버가 열어 볼 수 없습니다. 저장소에 접근할 수 있는 누군가가 데이터를 통째로 가져가더라도 마스터 패스워드 없이는 파일명 하나 읽을 수 없는 상태입니다.

무엇을 저장소에 맡기고 무엇을 맡기지 않는가

이 설계에서 저장소가 아는 것과 모르는 것의 경계는 분명합니다. R2는 어떤 사용자의 어떤 파일이 얼마만 한 크기의 암호문으로 존재하는지는 알지만 그 안이 무엇인지는 모릅니다. 서버는 누가 무엇에 접근할 권한이 있는지는 판단하지만 접근되는 바이트의 내용은 모릅니다. 각 구성 요소가 자기 역할에 필요한 최소한만 알도록 나눈 것이 이 아키텍처의 핵심입니다.

결국 클라우드 스토리지를 고르는 일은 단순히 싼 곳을 찾는 문제가 아니라, 비용 구조와 신뢰 경계를 함께 맞추는 문제였습니다. zero egress는 스트리밍 서비스의 비용을 지켰고 presigned URL 기반 직접 전송은 서버를 바이트에서 떼어 놓았으며 암호문만 저장하는 원칙은 저장소가 침해되더라도 내용을 지킵니다. 세 결정이 맞물려 "멍청하지만 믿을 수 있는 저장소"가 완성됩니다.

이 저장소에 올라가는 청크가 어떻게 암호화되는지는 XChaCha20 청크 AAD 바인딩에서, 저장된 청크를 어떻게 받아 재생하는지는 MediaSource 암호화 스트리밍에서 다룹니다. 전체 구조는 제로널리지 암호화 미디어 클라우드 사례에 있습니다.

자주 묻는 질문

왜 S3가 아니라 Cloudflare R2인가요?

미디어 클라우드는 스트리밍이 많아 전송(egress) 비용이 운영을 좌우합니다. R2는 S3 호환 API를 제공하면서 전송 비용이 없어, 재생이 아무리 늘어도 트래픽 비용이 함께 증가하지 않습니다. 저장 과금만 있는 구조라 스트리밍 중심 워크로드에 유리하고 S3 호환이라 이전 가능성도 남습니다.

presigned URL이 유출되면 위험하지 않나요?

presigned URL에는 짧은 만료 시간을 둡니다. 유출되더라도 짧은 접근 창이 지나면 URL 자체가 무효가 되어 재사용할 수 없습니다. 게다가 그 URL로 접근하는 대상은 브라우저가 이미 암호화해 올린 암호문이므로, 설령 짧은 창 안에 내려받아도 마스터 패스워드 없이는 복호화할 수 없습니다.

서버가 파일 바이트를 아예 안 거치나요?

네. 서버는 권한을 확인하고 짧은 수명의 presigned URL을 발급할 뿐, 실제 파일 바이트는 브라우저와 R2 사이에서 직접 오갑니다. 서버는 대용량 트래픽을 나르지 않아 부담이 적고 평문은 물론 암호문 바이트조차 서버를 경유하지 않아 신뢰 경계가 더 좁아집니다.

#CloudflareR2#presignedURL#zeroegress#스토리지#S3

업무자동화 구축이 필요하신가요?

무료 상담 신청