명령 실행 도구
이 도구들은 AI 에이전트가 하나 이상의 서버에서 셸 명령과 검증된 스크립트를 실행하고, 이미 실행된 명령을 조회할 수 있게 합니다. “web-01에서 df -h를 실행하고 결과를 알려줘”, “이 설정을 스테이징 플릿의 모든 서버에 배포해줘”, “방금 업로드한 배포 스크립트를 실행해줘” 같은 요청을 처리합니다.
명령 실행은 항상 호출자에게 ACL 권한이 있어야 합니다. 규칙 관리 방법은 명령 ACL을 참고하세요. 호출자가 MCP OAuth나 브라우저 세션으로 인증하는 경우, 서버는 command 범위를 포함한 활성 작업 세션도 요구합니다. 정적 API 토큰과 서비스 토큰은 이 요구 사항을 우회합니다. 명령을 특정 세션에 연결하려면 work_session_id를 전달하거나, 인자를 생략했을 때 사용할 기본값으로 ALPACON_WORK_SESSION 환경 변수를 설정하세요.
모든 도구는 workspace(필수)와 region(선택, 기본값은 설정된 리전)을 받습니다. 이 공통 파라미터는 아래 표에서 생략합니다.
요약
| 도구 | 설명 | 접근 수준 |
|---|---|---|
list_commands | 최근 명령 실행 이력 조회 | 읽기 전용 |
execute_command | 서버에서 명령을 실행하고 결과 대기 | 추가적 |
execute_command_multi_server | 여러 서버에서 동일한 명령 실행 | 추가적 |
execute_file | 서버에 이미 있는 검증된 스크립트 실행 | 추가적 |
state_command_purpose | 명령의 대기 중인 목적 요청에 응답 | 추가적 |
명령 이력
list_commands
서버에서 실행된 최근 명령을 상태, 출력, 타임스탬프와 함께 조회합니다. server_id로 필터링하면 특정 서버의 이력만 볼 수 있습니다. 새 명령을 실행하기 전 기존 실행 이력을 검토하거나, 이전에 제출한 명령의 결과를 확인할 때 사용합니다.
접근 수준: 읽기 전용
파라미터
| 파라미터 | 타입 | 필수 | 설명 |
|---|---|---|---|
server_id | string | 아니오 | 이 서버에서 실행된 명령으로 결과를 필터링 |
limit | integer | 아니오 | 반환할 최대 결과 수 (기본값: 20) |
예시
“db-01 서버에서 실행된 최근 명령 10개를 보여줘”
에이전트는 server_id를 db-01의 UUID로, limit=10으로 설정해 list_commands를 호출하고, 각 명령의 상태·출력·타임스탬프를 반환합니다.
명령 실행
execute_command
서버에서 셸 명령을 실행하고 결과를 기다려, stdout·stderr·종료 코드를 한 번의 호출로 반환합니다. 명령을 실행하는 권장 방법은 이 도구이며, list_commands는 이력만 조회할 뿐 아무것도 실행하지 않습니다. 이 도구는 timeout초(기본값 300, 즉 5분)까지 완료를 폴링하며, 명령이 실제로 실행 중일 때는 마감 시간을 초기화하고, 무한 대기를 막기 위해 timeout의 3배를 상한으로 둡니다.
의존성 체인(run_after), 예약 실행(scheduled_at), stdin 입력(data)을 지원합니다. 명령이 결과를 만들지 못하고 종료 상태(denied, rejected, stuck)에 도달하면, 이 도구는 타임아웃을 기다리지 않고 즉시 폴링을 멈추고 오류를 반환합니다.
명령 자체가 실행되기 전에 사람의 승인이 필요한 경우(아래에서 설명하는 sudo 처리와는 별개인 작업 세션 승인 절차), 이 도구는 awaiting_approval 상태의 구조화된 승인 대기 결과를 반환합니다. 승인 대기 중에는 명령을 다시 실행하지 마세요. 재제출은 별도의 승인이 필요하며, 원래 요청이 승인되면 명령이 중복 실행될 위험이 있습니다. 승인을 기다린 뒤 list_commands로 결과를 확인하세요.
명령에 sudo가 필요한데 비대화형 거부가 발생하면, 이 도구는 항상 거부 사유를 설명하는 자유 텍스트 힌트를 반환합니다. 사람이 직접 해결할 수 있는 세 가지 거부 사유(작업 세션 sudo 정책 부재, 필요한 MFA 재인증, 승인 대기 중인 sudo 요청)에 대해서는 이 힌트에 더해 구조화된 승인 대기 블록도 함께 반환하므로, 에이전트가 텍스트를 해석하지 않고 안정적인 카테고리로 분기할 수 있습니다. 사람은 Alpacon 웹 콘솔이나 CLI의 work-session update --sudo로 세션의 sudo 정책에 명령을 추가하거나, 재인증을 완료하거나, 요청을 승인한 뒤 다시 실행할 수 있습니다. SUDO_RISK_DENIED는 여기에 포함되지 않습니다. 런타임 위험 평가에 의한 강한 거부로 재시도나 승인 대상이 아니며, 이 경우에는 자유 텍스트 힌트만 반환됩니다.
일상적이지 않은 명령은 실행되는 대신 purpose_required 결과로 돌아올 수 있습니다. 서버가 이 명령이 왜 필요한지 묻는 것입니다. 미리 purpose를 전달하면(호출자가 이미 준 맥락을 반복하지 않고, 이 호스트에 구체적인 이유를 한두 문장으로) 명령이 곧바로 통과할 수 있습니다. 생략했는데 서버가 물어본다면 1분 이내에 state_command_purpose로 응답하세요.
접근 수준: 추가적
파라미터
| 파라미터 | 타입 | 필수 | 설명 |
|---|---|---|---|
server_id | string | 예 | 대상 서버 ID |
command | string | 예 | 실행할 셸 명령 |
shell | string | 아니오 | 명령을 실행할 셸 (기본값: system) |
username | string | 아니오 | 명령을 실행할 시스템 사용자 |
groupname | string | 아니오 | 명령을 실행할 시스템 그룹 (기본값: alpacon) |
env | object | 아니오 | 명령에 설정할 환경 변수 |
run_after | array | 아니오 | 이 명령이 실행되기 전에 완료되어야 하는 명령 ID |
scheduled_at | string | 아니오 | 즉시 실행 대신 미래 시각으로 예약 |
data | string | 아니오 | 명령의 stdin으로 전달할 데이터 |
timeout | integer | 아니오 | 완료를 기다릴 시간(초), 초과 시 타임아웃 (기본값: 300) |
work_session_id | string | 아니오 | 감사를 위해 이 명령을 연결할 작업 세션. 생략 시 ALPACON_WORK_SESSION을 사용 |
purpose | string | 아니오 | 이 명령이 이 호스트에 왜 필요한지, 한두 문장으로. purpose_required 결과를 미리 막아 대기 없이 통과시킵니다 |
command에 인라인 credential(시크릿 성격의 KEY=VALUE, 패스워드 플래그, 패스워드가 포함된 connection string)이 있으면, 서버는 명령을 저장하기 전에 command_inline_credential로 호출을 거부합니다. 시크릿은 env로 전달하세요. env는 쓰기 전용이라 명령 이력이나 감사 로그에 남지 않습니다.
스크립트, 히어독, bash /path/to/file 형태로 실행하던 것이라면 execute_file을 대신 사용하세요. 승인된 스크립트는 다시 승인받지 않고도 변경 없이 재실행할 수 있지만, 셸 한 줄로는 그럴 수 없습니다.
예시
“web-01에서
df -h를 실행하고 디스크 사용량을 보여줘”
에이전트는 server_id를 web-01의 UUID로, command="df -h"로 설정해 execute_command를 호출하고 결과를 기다린 뒤 stdout을 사용자에게 보고합니다.
“현재 작업 세션 안에서 api-02의 nginx를 재시작해줘”
에이전트는 work_session_id를 전달하거나(또는 ALPACON_WORK_SESSION에 의존해) 재시작이 해당 세션에 감사 기록으로 남도록 합니다.
execute_command_multi_server
여러 서버에서 동일한 셸 명령을 병렬(기본값)로, 또는 parallel=false로 순차 실행합니다. 서버별 성공/실패 상태를 반환합니다. 이 도구는 명령을 제출만 할 뿐 결과를 기다리지 않으므로, 이후 각 명령의 상태는 list_commands로 확인하세요.
설정 변경 배포, 버전 확인, 여러 서버에서 동일한 진단을 실행하는 등 플릿 전체에 걸친 작업을 execute_command를 반복 호출하지 않고 한 번에 처리할 때 사용합니다.
접근 수준: 추가적
파라미터
| 파라미터 | 타입 | 필수 | 설명 |
|---|---|---|---|
server_ids | array | 예 | 대상 서버 ID 목록 |
command | string | 예 | 실행할 셸 명령 |
shell | string | 아니오 | 명령을 실행할 셸 (기본값: system) |
username | string | 아니오 | 명령을 실행할 시스템 사용자 |
groupname | string | 아니오 | 명령을 실행할 시스템 그룹 (기본값: alpacon) |
env | object | 아니오 | 명령에 설정할 환경 변수 |
parallel | boolean | 아니오 | 모든 서버에 동시 제출 (기본값: true). false로 설정하면 순차 제출 |
work_session_id | string | 아니오 | 감사를 위해 이 명령들을 연결할 작업 세션. 생략 시 ALPACON_WORK_SESSION을 사용 |
예시
“웹 서버 3대 모두에서
systemctl status nginx를 실행해줘”
에이전트는 server_ids를 세 서버의 UUID로 설정하고 command="systemctl status nginx"로 execute_command_multi_server를 호출한 뒤, 어떤 서버가 성공하고 실패했는지 보고합니다.
검증된 스크립트 실행
execute_file
서버에 이미 있는 스크립트를 검증된 실행으로 실행합니다. 스크립트의 정확한 내용을 경로와 함께 제출하면, 호스트 디스크에 있는 바이트가 제출한 내용과 여전히 일치할 때만 실행됩니다. 한 줄짜리 명령을 넘어서는 작업(배포 스크립트, 히어독, bash /path/to/file로 실행하던 것)에는 execute_command보다 이 도구를 우선 사용하세요.
일반 셸 한 줄과 비교한 이점은 재실행에서 드러납니다. 검토자가 스크립트를 한 번 승인하면, 이후 변경 없는 재실행(같은 바이트, 같은 서버, 같은 계정, 같은 인자)은 다시 승인을 기다리지 않고 진행할 수 있습니다. execute_command에 전달한 셸 한 줄은 이런 대우를 절대 받지 못합니다. 경로 하나만으로는 실제로 무엇이 실행될지 증명할 수 없기 때문입니다. 승인은 정확히 그 바이트를, 그 서버에서, 그 계정으로, 그 인자로 실행하는 것만을 허용합니다. 한 바이트라도 바뀌면 다시 검토 대상이 됩니다. 인터프리터, 그 라이브러리, 스크립트가 런타임에 가져오거나 실행하는 것은 스크립트 자신의 책임이며, 검증 대상은 이 진입점 하나뿐입니다.
파일은 실행 전에 대상 호스트의 path에 이미 존재해야 합니다. 먼저 webftp_upload_content 등으로 업로드하세요. content는 끝의 줄바꿈까지 포함해 디스크에 있는 내용과 바이트 단위로 동일해야 합니다. 일치하지 않으면 추측하지 않고 그대로 실행이 실패합니다. path와 interpreter는 절대 경로여야 합니다(예: /opt/deploy.sh, /bin/bash). bash 같은 명령 이름만으로는 거부됩니다. 파이프, 리다이렉션, &&, 환경 변수는 스크립트 안에 넣으세요. 검증된 파일 주변에서 자유롭게 셸을 조합하는 방식은 이 경로에서 지원하지 않으며, 그런 일회성 조합이 필요하면 execute_command를 사용하세요.
그 외에는 execute_command와 동일하게 동작합니다. 스크립트 안의 sudo는 같은 승인·거부 처리를 거치고, awaiting_approval 결과는 실행 전에 사람이 개입해야 한다는 뜻이며, 목적을 묻는 결과는 state_command_purpose로 응답합니다.
접근 수준: 추가적
파라미터
| 파라미터 | 타입 | 필수 | 설명 |
|---|---|---|---|
server_id | string | 예 | 대상 서버 ID |
path | string | 예 | 서버에 있는 스크립트의 절대 경로. 이미 존재해야 함 |
content | string | 예 | 스크립트의 정확한 내용, 디스크에 있는 그대로 바이트 단위로(최대 64 KB). 이 값이 검토 대상이며 서버로 업로드되지는 않음 |
interpreter | string | 아니오 | 인터프리터의 절대 경로(기본값: /bin/bash) |
args | array | 아니오 | 스크립트에 전달할 인자 |
username | string | 아니오 | 스크립트를 실행할 시스템 사용자 |
groupname | string | 아니오 | 스크립트를 실행할 시스템 그룹 (기본값: alpacon) |
run_after | array | 아니오 | 이 실행이 시작되기 전에 완료되어야 하는 명령 ID |
scheduled_at | string | 아니오 | 즉시 실행 대신 미래 시각으로 예약 |
timeout | integer | 아니오 | 완료를 기다릴 시간(초), 초과 시 타임아웃 (기본값: 300) |
work_session_id | string | 아니오 | 감사를 위해 이 실행을 연결할 작업 세션. 생략 시 ALPACON_WORK_SESSION을 사용 |
purpose | string | 아니오 | 이 실행이 이 호스트에 왜 필요한지. 목적 요청을 미리 막아 대기 없이 통과시킵니다 |
예시
“방금 /opt/deploy.sh에 올린 배포 스크립트를 web-01에서 실행해줘”
에이전트는 server_id를 web-01의 UUID로, path="/opt/deploy.sh"로, content를 스크립트의 정확한 텍스트로 설정해 execute_file을 호출합니다. 검토자가 그 서버에 대해 그 스크립트를 승인하면, 이후 변경 없는 재실행은 다시 승인을 거치지 않고 진행됩니다.
state_command_purpose
명령의 대기 중인 목적 요청에 응답한 뒤 결과를 기다립니다. execute_command나 execute_file이 목적을 묻는 결과를 반환했을 때 사용하며, 여기에 전달할 command_id는 그 응답 안에 들어 있습니다. 명령은 전달한 목적과 함께 한 번 더 판단되며, 이 호출은 그 결과(통과하면 명령의 출력, 아직 사람이 필요하면 승인 대기 결과, 거부되면 오류)를 그대로 반환합니다.
빨리 응답하세요. 요청은 약 1분 후 만료되며, 응답은 명령당 한 번만 가능합니다. 늦은 응답이나 두 번째 응답은 거부되고, 원래 명령을 제출한 호출자만 응답할 수 있습니다. 이 호스트에 구체적이고 실제적인 이유를 작성하세요. 호출자가 이미 준 맥락을 반복해도 결과는 바뀌지 않습니다.
접근 수준: 추가적
파라미터
| 파라미터 | 타입 | 필수 | 설명 |
|---|---|---|---|
command_id | string | 예 | 목적을 물은 결과에 담긴 명령 ID |
purpose | string | 예 | 이 명령이 이 호스트에 왜 필요한지 |
timeout | integer | 아니오 | 재판단된 결과를 기다릴 시간(초) (기본값: 300) |
예시
“재시작 명령이 이유를 묻고 있어, 어젯밤 인시던트에서 보고된 메모리 누수를 해결하는 거라고 답해줘”
에이전트는 대기 중인 command_id와 purpose="인시던트 #482에서 보고된 메모리 누수를 해결하기 위해 재시작"으로 state_command_purpose를 호출하고, 명령이 실행된 뒤 결과를 보고합니다.