| 일 | 월 | 화 | 수 | 목 | 금 | 토 |
|---|---|---|---|---|---|---|
| 1 | ||||||
| 2 | 3 | 4 | 5 | 6 | 7 | 8 |
| 9 | 10 | 11 | 12 | 13 | 14 | 15 |
| 16 | 17 | 18 | 19 | 20 | 21 | 22 |
| 23 | 24 | 25 | 26 | 27 | 28 | 29 |
| 30 | 31 |
- 네트워크
- git
- 용어정리
- IaaS
- nodejs
- 이론
- network
- kubernetes
- MongoDB
- synology
- 쿠버네티스
- node.js
- gns3
- 명령어
- docker
- uid
- RAPA
- express
- Docker-compose
- mysql
- OpenStack
- 실습
- dockerfile
- ACL
- Javascript
- Docker Swarm
- 개념
- worker
- RAID
- 도커
- Today
- Total
융융이'Blog
Synology NAS 사진을 안전하게 AI에 연결하기: 읽기 전용 MCP 구축기 본문
한눈에 보는 결과
Synology NAS의 지정된 테스트 폴더를 Codex 같은 AI 클라이언트가 MCP(Model Context Protocol)로 조회할 수 있도록 읽기 전용 서버를 구축했다.
이번 실습에서 중요하게 본 것은 단순히 사진을 읽는 기능이 아니었다. 관리자 계정을 사용하지 않고, 허용된 폴더만 읽게 하고, 원본을 수정할 수 없게 만든 뒤 실제 실패 테스트로 이를 검증하는 것이 목표였다.
최종적으로 다음 항목을 확인했다.
- 사진 목록 조회
- 사진 형식·크기·해상도 조회
- 최대 크기가 제한된 JPEG 미리보기 생성
- 허용된 폴더 밖으로 나가는 경로 차단
- 사진 폴더에 대한 파일 생성 차단
- 인증 토큰이 없는 MCP 요청 차단
- 새 Codex 프로세스에서 실제 MCP 도구 호출 성공
서비스 구성
데이터 흐름

- 사용자가 Codex 같은 AI 클라이언트에서 사진 조회를 요청한다.
- 클라이언트는 사설 네트워크의 Photo MCP 컨테이너에 Bearer 토큰과 MCP 요청을 전달한다.
- MCP 서버는 읽기 전용으로 연결된 허용 사진 폴더에서 목록·메타데이터·축소 미리보기만 반환한다.
- 사용자가 승인한 결과만 클라우드 모델로 전달될 수 있다.
MCP 서버가 사설망에 있다는 사실과 사진 내용이 외부로 전송되지 않는다는 것은 같은 의미가 아니다.
MCP 서버와 사진 폴더는 사설 네트워크 안에 있다. 하지만 사진 미리보기나 추출 결과를 GPT 또는 Claude가 분석하려면 그 데이터는 클라우드 모델로 전송될 수 있다. 따라서 MCP가 사설망에 있다는 것과 사진 내용이 외부로 전송되지 않는다는 것은 같은 의미가 아니다.
OpenAI 공식 문서도 MCP 서버를 모델의 외부 도구와 데이터에 연결하는 수단으로 설명하며, 민감한 도구는 승인 절차로 제한할 수 있다고 안내한다. 사설 서버를 지원되는 OpenAI 제품에 연결할 때는 서버를 인터넷에 직접 공개하지 않고 Secure MCP Tunnel을 사용하는 방법도 제공한다. OpenAI MCP and Connectors
목표와 요구사항
이번 최소 기능 제품의 요구사항은 다음과 같았다.
- DSM 관리자 또는 마스터 계정을 사용하지 않는다.
- 별도의 테스트 사진 폴더만 허용한다.
- 목록, 메타데이터, 축소 미리보기 기능만 제공한다.
- 삭제, 이동, 업로드, 이름 변경과 원본 덮어쓰기는 제공하지 않는다.
- 컨테이너와 데이터 볼륨을 모두 읽기 전용 방향으로 제한한다.
- 토큰 인증을 통과한 사설망 클라이언트만 MCP를 호출한다.
- 정상 동작뿐 아니라 인증 실패와 쓰기 실패도 검증한다.
테스트 환경은 Synology DS224+와 Container Manager였다. 기존 서비스와 충돌하지 않도록 별도의 프로젝트와 디렉터리를 사용했다.
설계 결정과 이유
1. 관리자 대신 전용 서비스 계정
MCP 컨테이너에는 NAS 전체에 접근할 수 있는 관리자 권한이 필요하지 않다. 테스트 사진을 읽는 기능만 필요하므로, 관리자 그룹에 속하지 않은 별도 계정을 만들고 해당 공유 폴더에만 읽기 권한을 부여했다.
이것이 최소 권한 원칙이다. 계정이나 컨테이너가 침해되더라도 접근 가능한 범위를 필요한 만큼으로 줄인다.
2. 세 겹의 읽기 전용 제어
읽기 전용은 한 곳에만 설정하지 않았다.
- DSM 공유 폴더 권한: 전용 계정에 읽기만 허용
- Docker bind mount: 사진 폴더를
:ro로 연결 - MCP 도구 설계: 쓰기·이동·삭제 도구 자체를 제공하지 않음
한 방어선의 설정이 잘못되더라도 다른 방어선이 원본 변경을 막을 가능성을 높이는 방어 심층화 방식이다.
services:
photo-mcp:
read_only: true
user: "${MCP_RUN_UID}:${MCP_RUN_GID}"
security_opt:
- no-new-privileges:true
cap_drop:
- ALL
volumes:
- "${PHOTO_HOST_PATH}:/data/photos:ro"
mem_limit: 512m
위 예시는 공개용으로 주소, 실제 경로와 숫자 ID를 일반화한 것이다.
3. 작고 명확한 MCP 도구
서버는 다음 세 도구만 제공한다.
| 도구 | 반환 내용 | 사진 원본 내용 전송 여부 |
|---|---|---|
list_photos |
상대 경로, 파일 크기, 수정 시각 | 전송하지 않음 |
get_photo_metadata |
형식, 해상도, 파일 크기 | 이미지 픽셀은 전송하지 않음 |
get_photo_preview |
크기를 제한한 JPEG 미리보기 | 선택한 사진의 축소본 전송 가능 |
목록 도구에는 최대 반환 개수 제한을 두고, 메타데이터 도구는 위치 정보 같은 EXIF 개인정보를 기본 결과에 포함하지 않았다. 미리보기는 긴 변 기준 최대 1600px로 제한해 원본 전체를 그대로 전달하지 않도록 했다.
4. 경로 검증
사용자가 전달한 경로를 그대로 파일시스템에 연결하면 ../을 이용한 경로 순회 공격이나 외부 파일을 가리키는 심볼릭 링크 문제가 생길 수 있다.
그래서 서버는 다음을 검사한다.
- 절대 경로 거부
- 정규화한 최종 경로가 허용된 사진 루트 내부인지 확인
- 지원하는 이미지 확장자인지 확인
- 심볼릭 링크 파일은 목록에서 제외
5. 비밀정보 분리
MCP Bearer 토큰은 소스 코드나 Markdown에 저장하지 않았다.
- NAS 서버: 프로젝트의
.env - 로컬 클라이언트: 운영체제 키체인
- Codex 설정: 토큰 값이 아니라 환경변수 이름만 기록
환경변수가 화면에 평문으로 표시되는 관리 UI도 있으므로, 해당 화면은 스크린샷이나 블로그에 포함하지 않는 것이 좋다.
구축 과정
1. 테스트 데이터 경계 만들기
실제 가족 사진 전체를 연결하지 않고 별도의 테스트 공유 폴더를 만들었다. 초기 검증 데이터도 JPEG 두 장으로 제한했다.
2. 읽기 전용 MCP 서버 구현
Python 3.12 환경에서 MCP Python SDK와 Pillow를 사용했다. 서버 전송 방식은 Streamable HTTP이며, 토큰 검증에는 일정 시간 비교 함수를 사용했다.
컨테이너는 다음 조건으로 실행했다.
- 비루트 사용자
- 읽기 전용 루트 파일시스템
- Linux capability 전체 제거
no-new-privileges- 512MB 메모리 제한
- 임시 파일은 크기가 제한된
/tmptmpfs 사용
NAS 커널에서 Compose의 특정 CPU 제한 방식이 지원되지 않아 CPU 제한은 제거하고 메모리 제한은 유지했다. 기능 지원 여부는 Docker가 설치됐다는 사실만으로 판단하지 않고 실제 NAS 커널과 런타임에서 검증해야 한다.
3. DSM 전용 계정과 컨테이너 UID/GID 연결
처음에는 이미지에 정의한 임의의 비루트 UID로 실행했지만, DSM 공유 폴더 ACL과 연결되지 않아 사진을 읽지 못했다. 이후 DSM 전용 서비스 계정의 실제 UID/GID를 확인해 컨테이너 실행 사용자에 매핑했다.
이 과정은 별도의 문제 해결 글로 정리했다.
자세한 내용: Docker 컨테이너는 실행되는데 Synology 공유 폴더를 읽지 못한 이유
4. Codex에 MCP 등록
Codex에는 다음 정보만 등록했다.
- 사설망의 MCP URL
- Streamable HTTP 방식
- Bearer 토큰이 들어 있는 환경변수 이름
실제 URL과 토큰은 공개 문서에 포함하지 않는다. 실행 중이던 데스크톱 앱이 새 설정과 환경변수를 읽지 못하면 앱을 재시작해야 할 수 있다.
보안과 데이터 경계
데이터 흐름은 도구별로 다르다.
- 사진 목록 요청: 파일명과 크기 등 목록 정보만 AI 컨텍스트에 포함될 수 있다.
- 메타데이터 요청: 형식과 해상도 등이 포함될 수 있다.
- 미리보기 요청: 선택한 사진의 축소 이미지가 클라우드 모델에 전달될 수 있다.
따라서 폴더를 MCP에 연결했다는 이유만으로 모든 사진이 한꺼번에 AI로 전송되는 것은 아니다. 반대로 MCP 도구가 전체 파일을 반환하도록 구현하면 전체 내용이 전송될 수 있으므로, 데이터 최소화는 MCP 프로토콜이 자동으로 해결해 주는 기능이 아니라 서버 설계자의 책임이다.
OpenAI API를 직접 사용하는 경우 입력·출력 데이터의 학습 사용 여부, 오남용 모니터링 보관과 애플리케이션 상태 저장 조건은 공식 데이터 제어 문서를 확인해야 한다. ChatGPT·Codex 구독 환경과 Anthropic 제품은 각각 적용되는 계정 및 제품 정책을 별도로 확인해야 한다. OpenAI API 데이터 제어
검증 결과
기능이 동작하는지만 확인하지 않고 각 보안 경계를 따로 검증했다.
| 검증 항목 | 기대 결과 | 실제 결과 |
|---|---|---|
| 컨테이너 상태 확인 | 서비스 정상 | HTTP 200 |
| 토큰 없는 MCP 요청 | 인증 거부 | HTTP 401 |
| 테스트 사진 목록 | 허용된 파일만 반환 | JPEG 2장 반환 |
| 메타데이터 | 형식과 해상도 반환 | 두 파일 모두 4000×3000 확인 |
| 640px 미리보기 | 유효한 축소 JPEG 생성 | JPEG 시작·종료 바이트 확인 |
| 사진 폴더 파일 생성 | 실패 | 읽기 전용 파일시스템으로 차단 |
../ 외부 파일 접근 |
실패 | 단위 테스트 통과 |
| 외부 대상 심볼릭 링크 | 목록에서 제외 | 단위 테스트 통과 |
| 새 Codex 프로세스의 도구 호출 | 실제 MCP 결과 수신 | count: 2, read_only: true 확인 |
단위 테스트, 서비스 통합 테스트, 실제 AI 클라이언트를 통한 종단 간 테스트를 나눠 실행했다. 서버 코드의 함수가 성공하는 것과 AI 클라이언트가 인증·프로토콜·도구 호출 전 과정을 통과하는 것은 서로 다른 검증이기 때문이다.
연결되는 CS 개념
이번 실습에서 가장 중요했던 CS 개념은 UID/GID와 ACL이었다. 컨테이너가 비루트로 실행된다는 사실만으로 NAS 파일을 읽을 권한이 생기지는 않는다. 호스트 파일시스템이 확인하는 숫자 사용자 신분과 DSM의 권한 규칙이 일치해야 한다.
자세한 내용: Docker와 Synology 권한을 이해하는 UID, GID, ACL
그 밖에도 다음 개념이 연결된다.
- 인증과 인가
- bind mount와 읽기 전용 파일시스템
- 컨테이너 격리와 capability
- HTTP 상태 코드
- JSON-RPC와 MCP
- 단위·통합·종단 간 테스트
- 비밀정보 저장과 토큰 회전
주요 문제와 해결
가장 큰 문제는 컨테이너 자체는 정상 실행되지만 사진 디렉터리 목록 읽기가 거부된 것이었다. 원인은 애플리케이션 코드가 아니라 임의 UID와 DSM ACL의 불일치였다.
서비스의 상태 확인이 성공한다는 것은 프로세스와 HTTP 서버가 살아 있다는 뜻일 뿐, 마운트한 데이터까지 읽을 수 있다는 뜻은 아니었다. 그래서 상태, 인증, 읽기, 쓰기 차단을 서로 다른 테스트로 분리했다.
자세한 내용: Docker 컨테이너는 실행되는데 Synology 공유 폴더를 읽지 못한 이유
배운 점과 다음 단계
이번 실습을 통해 “AI에 NAS를 연결했다”보다 다음 내용을 설명할 수 있게 됐다.
- 왜 관리자 계정 대신 최소 권한 서비스 계정을 사용했는가?
- 왜 애플리케이션·컨테이너·DSM 세 계층에서 쓰기를 막았는가?
- 어떤 데이터가 사설망을 벗어나는가?
- 정상 기능뿐 아니라 실패 경로를 어떻게 검증했는가?
- 컨테이너와 NAS의 사용자 권한을 어떻게 연결했는가?
다음 단계는 Word와 Excel 문서를 대상으로 같은 원칙을 적용하는 것이다. 원본 전체를 무조건 보내기보다 NAS 또는 사설망 내부에서 검색·필터·집계를 수행하고, 질문에 필요한 문단이나 셀 범위만 AI에 제공하는 문서 MCP를 설계할 예정이다.
'AI 프로젝트 글 > 실생활 실습' 카테고리의 다른 글
| 매번 같은 설명을 반복하지 않기: AGENTS.md로 AI 프로젝트 규칙 관리하기 (0) | 2026.08.18 |
|---|
