termal.in

← 블로그

로컬 LLM에 서버 SSH 액세스를 안전하게 주는 법

· Termalin Team sshai-agentslocal-llmsecurity

로컬 모델에 SSH 액세스를 안전하게 주는 방법은 절대 키를 주지 않는 것입니다. 대신 도구를 호출하게 하세요 — 커스터디언 역할을 하는 MCP 서버로, 키를 보관하고(또는 단기 인증서를 발급하고), 내가 목록에 올린 호스트에만 닿고, 호스트별 명령 허용 목록을 강제하며, 하나하나를 로그로 남깁니다. 그러면 탈취된 프롬프트는 커스터디언을 통해 동작을 요청할 수 있을 뿐, 내 신원을 가로채거나 목록에 없는 호스트에 닿을 수는 없습니다. 사람들이 가장 먼저 오해하는 것: 모델을 내 하드웨어에서 돌리면 프롬프트는 보호되지만 서버는 보호되지 않습니다 — “로컬이니까 안전하다”는 말은 사실이 아니며, 그 모델이 셸을 쥐었을 때 벌어지는 일에 대해서는 아무것도 하지 않습니다.

로컬 모델이 전성기를 맞고 있습니다. 워크스테이션의 Ollama, 내 엔드포인트 뒤의 오픈 웨이트 모델, 자체 호스팅 코딩 에이전트 — 그럴 만한 이유로 돌립니다. 프라이버시, 비용, 요청 제한 없음, 비행기에서도 동작. 그리고 모델이 이미 내 프롬프트를 다루고 있으면, 다음 수순은 뻔하게도 그것을 내 인프라로 겨누는 것입니다. 로그를 tail 하게 하고, 서비스를 재시작하게 하고, 마이그레이션을 돌리게 하는 것 — 바로 여기서 진짜 질문이 떨어집니다.

“로컬”이라고 서버 액세스가 안전해지지는 않는다

모델이 데이터센터에서 돌든 책상 밑 서버에서 돌든, 똑같이 위험한 것이 두 가지 있습니다.

키는 여전히 소지자 자격 증명입니다. id_ed25519를 에이전트 환경에 넣어 직접 ssh를 실행하게 하면, 그 바이트를 쥔 사람이든 무엇이든 그 키를 신뢰하는 모든 호스트에서 곧 나 자신입니다. 모델을 로컬에서 돌린다고 그 점이 바뀌지는 않습니다. 복사본을 마침 내가 소유한 머신으로 옮길 뿐입니다. 그리고 여전히 되돌릴 수 없습니다. 키가 모델의 컨텍스트를 한 번 거치고 나면 — 환경 변수, 마운트된 파일, 도구 호출, 트랜스크립트 — 그것이 있어서는 안 될 곳으로 흘러가지 않았음을 더는 증명할 수 없습니다. “모델이 내 키를 봤나?”에 대한 유일하게 정직한 답은 모든 호스트에서 키를 교체하는 것입니다.

로컬 모델도 여전히 혼란에 빠집니다. 프롬프트 주입에 클라우드 모델이 필요한 것은 아닙니다. 오염된 로그 한 줄, 악의적인 파일명, 함정이 심긴 도구 결과, 지나치게 적극적인 계획 — 로컬 모델은 이 모두에 호스팅 모델만큼이나 선뜻 반응합니다. 오히려 위험은 더 큽니다. 사람들이 로컬 구성을 더 믿고, 보호 난간을 덜 두르고, 더 넓은 액세스를 내주기 때문입니다 — 바로 “내 머신에 있으니까”라는 이유로요. 그것은 잘못된 직감입니다. 가중치가 로컬에 있다고 해서 모델의 판단이 더 나아지지는 않습니다.

그러니 목표는 어떤 에이전트에서든 같습니다 — 모델이 자격 증명을 쥐지 않고도 일을 하게 하고, 모든 동작을 범위가 정해지고, 보이고, 되돌릴 수 있게 만드는 것입니다.

잘못하는 세 가지 방법

원시 키를 붙여 넣기. 가장 직접적이고 가장 나쁜 방법입니다. 범위도, 만료도 없고, 앞서 말한 되돌릴 수 없음까지 더해집니다. 스테이징에 배포하는 키는 대개 두 홉 건너 프로덕션 데이터베이스에도 닿을 수 있습니다.

수명이 긴 토큰을 발급하기. 결코 만료되지 않는 배포 토큰이나 “자동화” 자격 증명. 키보다 깔끔해 보이지만, 단계만 더 붙은 같은 소지자 문제입니다. 무언가를 해지하는 일이 그것의 존재를 기억해 내는 일이라면, 그것은 자신을 만들어 낸 실험보다 더 오래 살아남습니다.

자체 root 로그인을 주고 손 떼기. 올바른 직감 — 별도의 신원 — 을 잘못된 방식으로 한 것입니다. 봇 사용자의 authorized_keys에 공개 키를 넣으면 감사 추적이 없는 액세스를 만든 셈입니다. 모델의 명령을 다른 누구의 것과도 구분할 수 없고, 새벽 2시에 뭔가 터지면 bash 기록과 감으로 그 세션을 재구성하게 됩니다.

공통점: 모델이 상주 자격 증명을 쥐고 있고, 관찰 가능성은 뒷전이라는 것입니다.

통하는 패턴: 복사본이 아니라 커스터디언

발상을 뒤집으세요. 모델은 자격 증명을 애초에 쥐어서는 안 됩니다.

  • 모델은 요청하고, 커스터디언이 서명합니다. 브로커가 키를 보관하고(또는 단기 인증서를 발급하고) 모델을 대신해 인증합니다. 모델의 컨텍스트가 뚫려도 얻는 것은 브로커를 통해 동작을 요청하는 능력일 뿐, 어디서든 나를 사칭하는 능력이 아닙니다.
  • 범위는 명시적입니다. 모델은 내가 목록에 올린 호스트에만 닿습니다. 새 호스트는 기본값이 아니라 새로운 결정입니다.
  • 명령은 통제됩니다. 호스트별로 모델에게 완전한 셸을 줄지, 명령 허용 목록을 줄지, 아무것도 주지 않을지 정하세요 — 그래서 “nginx 재시작”은 웹 계층에서 허용되고, “뭐든 다”는 결코 허용되지 않습니다.
  • 사람이 지켜볼 수 있습니다 — 실시간으로. 사후 분석에서만이 아니라, “모델이 이걸 했다”와 “내가 이걸 했다”를 구분하는 기록과 함께요.
  • 해지는 교체가 아니라 토글입니다. 애초에 공유된 것이 없으므로, 액세스를 끄는 데 드는 비용이 없습니다.

이 중 어느 것도 유별나지 않습니다 — 진지한 인프라 팀에서 인증서 기반 SSH가 이미 대략 이렇게 돌아갑니다. 늘 걸리는 점은 이걸 직접 엮는 일이 하나의 프로젝트라는 것이고, 그래서 사람들은 위의 나쁜 선택지 중 하나로 건너뜁니다.

로컬 모델에 연결하기

MCP — Model Context Protocol — 가 이를 깔끔하게 해내는 방법이며, 클라이언트를 가리지 않습니다. MCP를 지원하는 클라이언트라면 무엇이든 구동할 수 있으므로, 내 모델이 Claude든, Ollama 뒤의 오픈 웨이트 모델이든, 직접 호스팅하는 것이든 상관없습니다.

  1. 로컬 모델을 MCP 지원 클라이언트로 실행하세요(MCP를 쓰는 코딩 에이전트나 채팅 클라이언트).
  2. SSH를 앞단에서 처리하는 MCP 서버를 가리키게 하세요 — 모델에게 키를 넘기는 대신 모델을 대신해 인증하는 서버로요.
  3. 원하는 호스트만 켜고, 각 호스트의 명령 정책(전체 / 허용 목록 / 차단)을 정하세요.
  4. 세션을 눈에 두고 감사 로그에 기록되게 하면, 모델이 실행하는 모든 명령을 추적하고 다시 재생할 수 있습니다.

모델은 도구를 얻고 — 세션 열기, 명령 실행, 파일 읽기·쓰기 — 인증은 커스터디언이 합니다. 내 키는 내 머신에서든 다른 어디서든 모델의 환경에 절대 들어가지 않습니다. 그리고 자격 증명을 모델이 아니라 커스터디언이 쥐고 있으므로, 대신 호스팅 에이전트로 손을 뻗는 순간에도 같은 구성이 그대로 이어집니다 — SSH로 쓰는 Claude Code와 SSH로 쓰는 OpenAI Codex가 반대편에 클라우드 모델을 두고 이 동일한 패턴을 앞단에서 씁니다.

Termalin은 이를 어떻게 하나

Termalin은 내장 MCP 서버를 갖춘 SSH 클라이언트이므로, 이 패턴이 프로젝트가 아니라 기본값입니다.

  • 내 머신에서는 번들된 로컬 서버를 에이전트에 등록하세요(claude mcp add termalin -- <path>/termalin-mcp, 또는 다른 MCP 클라이언트에 맞는 동등한 명령). 모델은 내가 켠 호스트에만 닿으며 — 에이전트 액세스는 기본적으로 꺼져 있습니다 — 인증은 Termalin의 키 커스터디언(사용자 대신 키를 보관하고 서명하는 구성 요소)을 거칩니다. 키를 한 번 잠금 해제하면 Termalin이 모델을 대신해 서명하고, 모델이 읽을 키 파일은 어디에도 없습니다.
  • 호스트별로 정책을 정합니다 — 전체 액세스, 명령 허용 목록, 또는 차단 — 그래서 혼란에 빠진 로컬 모델이 그 서버에서 내가 승인한 적 없는 것을 실행할 수 없습니다.
  • 벌어지는 일을 지켜봅니다. 에이전트 세션은 실시간 터미널 탭으로 실행되고, 워치 그리드가 이를 미러링하며, 모델이 조작하는 타일이 빛납니다. 모든 명령은 세션 녹화에 표시되고 — 출력만, 키 입력은 절대 담지 않습니다 — 출처 기기와 IP와 함께 감사 로그에 기록됩니다.
  • 앱이 실행 중이 아닌가요? 특정 서버로 범위가 제한되고, 만료 기간이 있고, 명령이 통제되며, 실행마다 단기 인증서로 인증하는 API 키로 모델을 Termalin의 호스팅 MCP 엔드포인트에 가리키게 하세요 — 그러면 유출된 키조차 목록에 없는 호스트에 닿거나 허용된 명령 밖으로 실행될 수 없습니다.

어느 쪽이든, 원하던 속성이 유지됩니다. 내 로컬 모델은 내 서버를 운용할 수 있고, 키는 한 번도 본 적이 없습니다.

심심한 호스트 하나로 시작하세요

프로덕션으로 시작하지 마세요. 위험이 낮은 서버 — 스테이징 서버나 장난감 VPS — 를 등록하고, 허용 목록으로 설정한 뒤, 모델에게 진짜 잡일을 주세요. 오류가 나타날 때까지 로그를 tail 하고, 설정을 고치고, 서비스를 재시작하는 일 말입니다. 작업하는 동안 그리드를 열어 두세요. 첫 한 시간 동안 알게 되는 것 — 어떻게 행동하는지, 어디서 머뭇거리는지, 모호함을 어떻게 다루는지 — 이 두 번째 호스트를 등록할지, 그리고 얼마만큼 풀어 줄지를 알려 줍니다.

그것이 커스터디언 모델의 조용한 보상입니다. 한 번에 호스트 하나씩 넓혀 가는데, 내딛는 어떤 걸음도 되돌릴 수 없는 것이 아니기 때문입니다 — 모델이 어디서 실행되든 말이죠.


Termalin은 내장 MCP 서버, 키 커스터디언, 호스트별 에이전트 정책을 갖춘 무료 크로스 플랫폼 SSH 클라이언트입니다 — 다운로드하거나, 키를 안전하게 다루는 방법을 읽어 보세요.

호스트 한 대에서 먼저 써 보세요.

Termalin은 여러분과 여러분의 에이전트를 위한 빠른 SSH 클라이언트입니다.

무료 요금제 · Pro 14일 무료 체험 · 요금

Google에서 Termalin을 선호 소스로 추가