SSD Nodes Learn Hosting plans →
가이드 Matt Connor작성자 Matt Connor · 업데이트됨 2026-08-26

AI 에이전트 API 키 유출 방지 및 보안 설정 방법

AI 에이전트가 환경 변수나 API 키를 외부로 유출하는 프롬프트 인젝션 위험을 방지합니다. 실제 키 대신 수명이 짧은 토큰과 자격 증명 게이트웨이를 사용하여 에이전트의 접근 권한을 최소화하고 보안을 강화하는 구체적인 전략을 확인하십시오.

AI 에이전트에서 비밀 정보를 분리해야 하는 이유

AI 에이전트는 명령어를 실행하는 일반적인 Linux 프로세스입니다. 해당 프로세스가 보유한 모든 환경 변수는 그 프로세스가 실행하는 코드에서 읽을 수 있으므로, 에이전트 환경에 포함된 API key는 에이전트가 접근 가능한 모든 호스트로 전송될 수 있는 키가 됩니다. 에이전트에서 비밀 정보를 분리한다는 것은 키 대신 핸들을 제공하는 것을 의미합니다. 즉, 수명이 짧고 범위가 제한된 토큰이나, 네트워크 경계에서 다른 무언가가 실제 값으로 교체해 줄 플레이스홀더를 사용하는 것입니다.

이는 모델이 적대적으로 변한다는 이야기가 아닙니다. 메커니즘은 훨씬 단순합니다. 에이전트는 지침이 포함된 웹 페이지, README 또는 이슈 댓글을 읽고 이를 따릅니다. 언어 모델 입장에서는 사용자가 작성한 텍스트와 에이전트가 가져온 텍스트 사이에 차이가 없기 때문입니다. 이것이 바로 프롬프트 인젝션입니다. 일단 이런 일이 발생하면 피해 규모는 오직 한 가지, 즉 해당 프로세스가 읽을 수 있는 범위에 의해 결정됩니다. 아직 경계를 설정하지 않았다면, 서버에서 코딩 에이전트를 안전하게 실행하는 방법에서 이 가이드의 기반이 되는 격리 단계들을 확인할 수 있습니다.

위협 모델의 단순한 이해

에이전트가 실행되는 사용자와 동일한 권한으로 이 명령을 실행하십시오.

tr '\0' '\n' < /proc/self/environ | grep -iE 'key|token|secret|password'

이 명령이 출력하는 모든 줄은 외부 서버로 전송될 수 있는 HTTP 요청 하나와 같습니다. 이제 에이전트 주변 디스크에 무엇이 있는지 확인하십시오.

grep -rIl --exclude-dir=.git -e 'API_KEY' -e 'SECRET' ~/projects
find ~ -maxdepth 3 -name '.env' -o -name 'credentials' -o -name '*.pem'

셸 권한을 가진 에이전트는 데이터를 외부로 유출하기 위해 복잡한 익스플로잇이 필요하지 않습니다. 다음 4가지 일반적인 경로를 사용하면 되며, 이 모든 작업은 로그상에서 정상적인 업무 활동처럼 보입니다.

  • 쿼리 문자열에 값을 포함하여 임의의 호스트로 보내는 아웃바운드 curl 또는 fetch 요청.
  • 에이전트가 쓰기 권한을 가진 저장소에 대한 git commitgit push 작업.
  • 에이전트 사용자의 권한으로 임의의 코드를 실행하는 패키지 설치 스크립트.
  • HTTP 외부 통신이 차단된 경우에도 유출이 가능한, 값이 포함된 호스트 이름에 대한 DNS 조회.

코드 리뷰만으로는 이 문제를 해결할 수 없습니다. 근본적인 해결책은 에이전트가 접근할 수 있는 범위 내에 가치 있는 정보가 없도록 만드는 것입니다.

작업 트리에 있는 비밀 정보는 컨텍스트 윈도우에도 노출됩니다

에이전트는 파일을 읽습니다. 작업 중인 저장소에 있는 .env 파일은 읽히게 되며, 일단 읽히면 컨텍스트 윈도우에 포함됩니다. 이는 곧 해당 내용이 트랜스크립트, 보관 중인 모든 로그, 그리고 에이전트가 다음에 작성하는 모든 내용에 포함된다는 뜻입니다.

이전 방식, 에이전트가 작업하는 트리 안에 키가 있는 경우:

cd ~/projects/billing
cat .env
# STRIPE_SECRET_KEY=sk_live_...
# DATABASE_URL=postgres://app:hunter2@db.internal:5432/billing

이후 방식, 파일을 접근할 수 없는 곳으로 옮긴 경우:

sudo install -d -m 750 -o root -g agent-review /etc/agent-review
sudo install -m 640 -o root -g agent-review ~/projects/billing/.env /etc/agent-review/billing.env
rm ~/projects/billing/.env

작업 트리에 파일이 더 이상 존재하지 않으므로 에이전트 사용자는 해당 파일을 열 수 없습니다. 에이전트 자체 설정의 거부 규칙은 첫 번째 방어선이 아닌 두 번째 방어선입니다. Claude Code는 프로젝트 내의 .claude/settings.json에서 권한 규칙을 읽습니다:

{
  "permissions": {
    "deny": ["Read(./.env)", "Read(./secrets/**)", "Read(./**/*.pem)"]
  }
}

이는 에이전트가 탐색 중에 파일을 여는 실수를 방지합니다. 하지만 주입된 명령어가 base64 .env을 실행하는 것까지 막지는 못합니다. 이는 파일 읽기가 아닌 셸 명령이기 때문입니다. 해당 명령 실행 전에 사용자에게 확인을 요청할지 여부는 세션의 권한 모드에 따라 결정되며, 2026년 8월부터는 auto 모드가 Claude Code의 기본값이 됩니다. 따라서 사용자가 지켜보고 있지 않은 서버는 그러한 명령을 더 많이 자동으로 실행하게 됩니다. 에이전트의 권한이 아닌 습관을 형성하는 요소에도 동일한 제한이 적용됩니다. 작동하는 최소한의 변경 사항만 유지하도록 에이전트를 제어하는 기술은 에이전트가 불필요한 파일을 여는 것을 방지하지만, 이는 모델이 설득을 통해 무시할 수 있는 조언일 뿐입니다. 설정을 가드레일로, 파일 시스템 권한을 벽으로 간주하십시오. 동일한 구분 방식이 컨테이너 내부에도 적용됩니다. Docker Compose의 env 파일 및 비밀 정보는 이 문제의 한 단계 아래 버전을 다룹니다.

모든 에이전트에 권한이 없는 별도의 사용자 계정 할당하기

에이전트가 사용자의 계정으로 실행되면 사용자의 SSH 키, 클라우드 자격 증명, 셸 기록을 그대로 상속받습니다. 별도의 사용자를 생성하는 것은 단 하나의 명령어로 가능하며, 이러한 위험 요소를 모두 제거할 수 있습니다.

sudo adduser --disabled-password --gecos "" agent-review
sudo chmod 700 /home/agent-review
sudo -u agent-review cat ~/.ssh/id_ed25519

마지막 줄은 cat: /home/you/.ssh/id_ed25519: Permission denied 오류와 함께 실패해야 합니다. 만약 키가 출력된다면 홈 디렉터리가 그룹이나 다른 사용자에게 읽기 권한이 열려 있는 상태이므로, chmod 700 ~ 명령어로 이를 수정해야 합니다. 에이전트 사용자를 sudo 그룹에 추가하지 마십시오. 또한, 에이전트가 반드시 필요한 명령어 외에 더 넓은 권한을 허용하는 NOPASSWD 규칙을 설정해서도 안 됩니다. VPS에서의 최소 권한 사용자 문서에서 그룹 및 sudoers 설정에 관한 상세 내용을 확인할 수 있습니다. 서버에서 두 개 이상의 세션을 실행할 때는 이러한 분리 원칙을 항상 유념해야 합니다. 하나의 Claude Code 세션은 다른 세션으로 텍스트를 직접 전송할 수 있으며, 첫 번째 세션이 보유한 모든 정보가 단일 메시지를 통해 해당 채널을 넘어갈 수 있기 때문입니다.

클라우드 VPS에서는 한 가지 경계 설정을 더 추가하는 것이 좋습니다. 인스턴스 메타데이터 서비스는 고정된 링크 로컬 주소에서 응답하며, 요청하는 모든 대상에게 역할 자격 증명을 제공하는 경우가 많습니다.

sudo iptables -A OUTPUT -m owner --uid-owner agent-review -d 169.254.169.254 -j REJECT

에이전트 측에서 이를 확인하십시오. 패킷이 서버를 떠나기 전에 거부되므로 sudo -u agent-review curl -s --max-time 3 http://169.254.169.254/ 명령은 아무것도 출력하지 않고 0이 아닌 종료 코드를 반환해야 합니다.

경계 지점에서 자격 증명 주입하기

이 문제를 해결하는 실제 패턴은 자격 증명 주입입니다. 에이전트는 실제 키를 직접 보유하지 않습니다. 에이전트가 요청을 로컬 게이트웨이로 보내면, 게이트웨이가 외부로 나가는 과정에서 자리 표시자(placeholder)를 실제 비밀 값으로 교체합니다. 비밀 값은 게이트웨이의 저장소에 존재하며, 에이전트와는 다른 프로세스에서 다른 사용자의 권한으로 관리됩니다.

OneCLI는 이를 구현한 오픈 소스 도구 중 하나로 Apache-2.0 라이선스를 따르며, 에이전트 옆에서 컨테이너 형태로 실행됩니다. 2026년 7월 기준으로 해당 프로젝트는 이 구성을 다음과 같이 문서화하고 있습니다.

git clone https://github.com/onecli/onecli.git
cd onecli
docker compose -f docker/docker-compose.yml up -d --wait

대시보드는 10254 포트에서, 게이트웨이는 10255 포트에서 대기합니다. 실제 자격 증명을 한 번 저장한 뒤, 각 에이전트에는 키 대신 자리 표시자 값과 고유한 범위의 액세스 토큰을 부여합니다. 에이전트는 이 토큰을 Proxy-Authorization 헤더에 담아 전송합니다. 게이트웨이는 호스트와 경로를 기준으로 나가는 요청을 매칭하고, 일치하는 자격 증명을 복호화하여 치환합니다. 따라서 에이전트의 환경에는 탈취할 가치가 있는 정보가 남지 않습니다.

이 방식의 핵심 가치는 암호화 그 자체가 아닙니다. "이 에이전트가 무엇을, 언제 사용했는가"라는 질문을 로그 쿼리로 확인할 수 있다는 점입니다. 6개의 환경 중 어디에 키 사본이 있는지 추측할 필요 없이, 단 하나의 감사 추적(audit trail)만 읽으면 됩니다.

비밀 값을 환경 변수가 아닌 프로세스에 직접 전달하기

systemd에서 에이전트를 실행하면 환경 변수를 전혀 사용할 필요가 없습니다. LoadCredential=는 해당 서비스만 읽을 수 있는 전용 디렉터리에 비밀 값을 배치하며, 유닛 파일에서는 %d으로, 프로세스 내부에서는 $CREDENTIALS_DIRECTORY로 노출됩니다. 이 값은 /proc/<pid>/environ에 절대 나타나지 않으므로 ps eww로도 확인할 수 없으며, 서비스가 중지되면 해당 디렉터리도 사라집니다.

먼저 자격 증명을 해당 머신용으로 암호화하십시오. 다음 명령어들은 systemd 문서에서 제공하는 방식이며, Ubuntu 24.04와 Debian 13을 포함한 systemd 250 이상 버전에서 작동합니다.

echo -n 'sk-example-value' > /tmp/plain.txt
sudo systemd-creds encrypt --name=api_key /tmp/plain.txt /etc/credstore/api_key.cred
shred -u /tmp/plain.txt
sudo systemd-run -P --wait -p LoadCredentialEncrypted=api_key:/etc/credstore/api_key.cred \
  systemd-creds cat api_key

마지막 명령어는 sk-example-value을 출력합니다. 이는 암호화된 파일이 현재 호스트에서 복호화됨을 증명합니다. 그런 다음 유닛 파일에서 이를 참조하십시오.

[Service]
User=agent-review
LoadCredentialEncrypted=api_key:/etc/credstore/api_key.cred
Environment=AGENT_KEY_FILE=%d/api_key
ExecStart=/usr/local/bin/agent-worker

에이전트 코드는 값이 필요할 때 $AGENT_KEY_FILE에 있는 파일을 엽니다. 파일 읽기는 일시적인 작업입니다. 반면 환경 변수는 프로세스가 생성한 모든 자식 프로세스에서 프로세스의 수명 내내 유지됩니다.

장기 키보다 단기 토큰을 우선 사용하십시오

만료되지 않는 키는 몇 달 뒤 로그나 기록에서 발견되더라도 여전히 유효합니다. 서비스에서 세션 토큰을 제공한다면 해당 토큰을 사용하고, 작업에 필요한 가장 짧은 유효 기간을 설정하십시오.

aws sts assume-role \
  --role-arn arn:aws:iam::123456789012:role/agent-readonly \
  --role-session-name agent-review \
  --duration-seconds 900

AWS STS(Security Token Service)에서 허용하는 최소 시간은 15분이며, 이는 일반적으로 에이전트 작업 한 번을 수행하기에 충분합니다. GitHub의 경우, 에이전트 사용자에게 별도의 gh 로그인을 부여하고 작업 대상인 단일 저장소로 범위를 제한한 세분화된 토큰을 발급하십시오. 이렇게 하면 해당 세션 내의 gh auth token은 다른 어떤 것에도 접근할 수 없게 됩니다. 먼저 리소스 단위로 범위를 제한하고, 그다음 시간 단위로 제한하십시오.

확인하고, 또 확인하십시오

에이전트 설정을 변경한 후에는 세 가지 점검을 수행해야 합니다. 본인 계정이 아닌 에이전트 사용자의 권한으로 실행하십시오.

sudo -u agent-review env | grep -iE 'key|token|secret'
sudo -u agent-review ls -la /home/you/ 2>&1 | head -3
sudo -u agent-review curl -s -o /dev/null -w '%{http_code}\n' --max-time 5 https://api.github.com/user

첫 번째 명령은 아무것도 출력하지 않아야 합니다. 두 번째 명령은 ls: cannot open directory '/home/you/': Permission denied를 출력해야 합니다. 세 번째 명령은 에이전트의 네트워크 경로가 어떤 자격 증명을 제시하는지 알려줍니다. 이는 게이트웨이 패턴이 해결하고자 하는 핵심 질문입니다. 401는 에이전트가 자체적인 GitHub 자격 증명을 가지고 있지 않음을 의미하며, 200은 자격 증명을 가지고 있음을 의미하므로 어떤 토큰인지 파악하고 있어야 합니다. 에이전트를 무인으로 실행하는 경우, VPS에서 AI 에이전트 비용 제어하기에서 이러한 접근 제한과 함께 설정해야 할 예산 한도를 다룹니다.

FAQ

모델이 내 키를 유출하지 않을 것이라고 믿어도 됩니까?

아니요, 이 위협 모델에서 모델은 공격자가 아니기 때문입니다. 에이전트는 웹 페이지, 저장소, 이슈 트래커에서 텍스트를 읽어 들이며, 해당 텍스트에는 명령이 포함될 수 있습니다. 모델은 사용자의 명령과 자신이 가져온 텍스트를 구분할 신뢰할 만한 방법을 가지고 있지 않습니다. 모델의 올바른 선택에 의존하는 모든 제어 방식은 주입된 명령이 설득력을 갖추는 순간 실패하므로, 제어 장치는 운영 체제나 네트워크 계층에 위치해야 합니다.

에이전트 비밀 정보를 환경 변수에 저장하는 것이 정말 나쁜가요?

환경 변수는 상속된다는 점에서 치명적입니다. 에이전트가 생성하는 모든 자식 프로세스(빌드 스크립트, 테스트 러너, 패키지 설치 훅 등)는 환경 변수의 복사본을 전달받습니다. 또한 해당 변수는 동일한 사용자의 /proc/<pid>/environ을 통해 읽을 수 있으므로, 에이전트가 직접 전달하지 않아도 에이전트가 실행하는 모든 프로세스가 이를 읽을 수 있습니다. 사용 시점에 LoadCredential=이나 게이트웨이를 통해 파일을 읽는 방식은 노출 범위를 해당 시점으로 제한합니다.

비밀 정보를 볼트(vault)에 넣는 것만으로 해결됩니까?

부분적으로만 해결됩니다. 볼트는 저장소 문제를 해결할 뿐입니다. 볼트를 직접 호스팅한다면 별도의 강화 작업이 필요합니다. Vaultwarden 서버는 보통 암호화된 항목 자체가 아니라 관리자 토큰이나 백업 파일을 통해 침해되기 때문입니다. 또한 볼트에서 비밀 정보를 꺼내 에이전트에게 환경 변수로 전달하는 마지막 단계의 문제는 해결하지 못하며, 이는 다시 원점으로 돌아가는 결과를 낳습니다. 중요한 것은 누가 치환을 수행하느냐입니다. 에이전트가 비밀 정보를 가져오면 에이전트가 그 정보를 소유하게 됩니다. 게이트웨이나 init 시스템이 에이전트 프로세스 외부에서 치환을 수행하면 에이전트는 비밀 정보를 결코 소유하지 않습니다.

에이전트가 이미 정보를 유출했는지 어떻게 알 수 있습니까?

보통 사후에는 알 수 없으며, 이것이 바로 게이트웨이가 필요한 이유입니다. 게이트웨이가 없다면 증거는 셸 히스토리, 에이전트 기록, 그리고 아마도 기록하고 있지 않을 아웃바운드 연결 로그에 흩어져 있을 것입니다. 자격 증명 게이트웨이를 사용하면 자격 증명을 사용할 때마다 에이전트 식별자와 타임스탬프가 포함된 한 줄의 로그가 남습니다. 유출이 의심된다면 조사를 수행하기 전에 먼저 키를 교체하십시오. 키 교체는 비용이 적게 들지만, 확신은 그렇지 않습니다.

오늘 당장 해야 할 최소한의 조치는 무엇입니까?

모든 .env 파일을 에이전트가 작업하는 디렉터리 밖으로 옮기고, 에이전트마다 권한이 없는 별도의 사용자를 생성하십시오. 이 두 가지 변경 사항은 약 10분 정도 소요되며, 코드 옆에 있을 이유가 없는 자격 증명 파일을 에이전트가 읽는 가장 흔한 경로를 차단합니다. 게이트웨이와 단기 토큰 도입은 첫 번째 단계가 아니라 그다음 단계입니다. 동일한 시작점은 VPS에서 자율 에이전트를 안전하게 실행하는 것을 포함한 모든 에이전트 런타임에 적용됩니다.