---
title: "토큰 명령어 매칭"
description: "토큰의 명령어 규칙이 입력한 명령줄, 와일드카드, 실행 계정 및 sudo와 어떻게 매칭되는지 확인합니다. 거부 코드와 감사 기록으로 원인을 구분합니다. 실제 실행 전에 명령어가 허용되지 않거나 권한 상승이 막혔을 때 어떤 규칙을 확인하고 어떻게 수정할지 미리 알아보세요."
---

> Full documentation index: https://docs.alpacax.com/llms.ko.txt

# 토큰 명령어 매칭

토큰이 명령어를 허용하는지 확인할 때 이 규칙을 사용하세요. 자동화 작업에 앞서 [서비스 토큰의 허용 명령어를 설정](/use/iam/applications/service-tokens/command-patterns/)하세요.

## 명령 규칙은 어떻게 매칭되나요

허용 명령 규칙은 토큰별로 설정합니다. [기존 개인 API 토큰](/use/settings/api-tokens/#acl-규칙)과 [서비스 토큰](/use/iam/applications/service-tokens/)을 참고하세요. 제출한 명령줄을 허용하는 규칙과 서버의 권한 상승 허용 여부는 각각 확인합니다. `sudo`로 시작하는 명령에는 규칙에도 `sudo`가 있어야 합니다. 두 권한은 설정 위치가 다르고 적용 방식도 반대여서 자동 배포가 여기서 멈추는 경우가 가장 많습니다.

- 규칙을 **제출한 명령줄 전체**와 처음부터 끝까지 비교합니다. 일부만 일치하면 허용하지 않습니다.
- 와일드카드는 `*`만 사용할 수 있습니다. 규칙 맨 끝에 단독으로 오는 `*`는 나머지 인수 전체와 일치하고, `*` 하나만 있는 규칙도 아래의 첫 단어 제한을 따릅니다. 그 밖의 `*`는 단어 하나 안에서만 일치하며 공백과 `$`, `` ` ``, `*`, `?`, `[`, `{`와는 일치하지 않습니다. 따라서 `deploy-*`는 `deploy-web`은 허용하지만 `deploy-web --force`는 허용하지 않습니다. `*`를 따옴표로 감싸거나 이스케이프한 규칙은 어떤 명령줄과도 일치하지 않습니다. 규칙의 첫 단어에 `*`가 있으면 환경 변수 대입(`NAME=value …`)이나 셸 접두어(`time`, `!`, `if`, `then`, `else`, `elif`, `while`, `until`, `do`, `{`)로 시작하는 명령줄과는 일치하지 않습니다. 첫 단어가 `*` 하나뿐이어도 마찬가지입니다. 이런 명령어를 허용하려면 규칙에 접두어를 그대로 적어야 합니다.
- 단어 안에서 고정 문자열 뒤에 오는 `*`는 상위 디렉터리 구간(`..` 뒤에 `/`, `:`, `,`, 공백이 오거나 단어가 끝나는 경우)과 일치하지 않습니다. 따라서 `rm -rf /tmp/build-*` 규칙은 `rm -rf /tmp/build-x/sub`와 일치하지만 `rm -rf /tmp/build-x/../../etc`와는 일치하지 않습니다. 단어 맨 앞의 `*`는 `cp * /dst`처럼 상위 디렉터리 구간과도 일치하며, `git log v1..*`처럼 규칙에 직접 적힌 `..`는 문자 그대로 비교합니다.
- 명령줄에서 `&&`, `||`, `|`, `;`, `&`, 줄바꿈으로 여러 명령어를 연결하면 각 부분을 따로 비교하며, **모든**
  부분이 규칙 중 하나에 일치해야 합니다.
- 리디렉션이 있는 명령줄은 규칙과 관계없이 거부합니다. `*` 하나뿐인 규칙도 마찬가지입니다. `>`, `>>`, `<`, `>|`뿐 아니라
  `2>&1`, `2>/dev/null`, `<<` 같은 형태도 해당합니다. 규칙으로는 명령어가 어떤 파일을 읽거나 쓸 수 있는지 정할 수
  없기 때문입니다. 제출하는 명령줄에서 리디렉션을 빼거나, 서버의 스크립트 안으로 옮기고 그 스크립트 이름을 규칙에 등록해야 합니다.
  프로세스 치환(`<(...)`)은 리디렉션이 아니며 다른 명령과 똑같이 검사합니다.
- 단어 맨 앞의 `#`부터는 셸과 같이 주석으로 처리합니다. 그 줄의 나머지는 무시되며 규칙과 일치하는 데 쓰이지 않고,
  다음 줄은 다시 비교합니다. 단, `$(...)`나 서브셸 `(...)` 안의 `#`는 주석으로 보지 않고 줄 전체를 거부합니다.
- 셸마다 따옴표를 다르게 해석하는 명령줄은 거부합니다. 예를 들어 `"${x:-...}"` 안의 작은따옴표가 해당합니다.
- 비교 전에 따옴표를 제거하고 연속된 공백을 하나로 줄입니다. 따라서 `echo "hello world"`는
  `echo hello world`로, `echo  hello`(공백 두 개)는 `echo hello`로 비교합니다.
- 일치하는 규칙이 없으면 서버에서는 아무 명령어도 실행되지 않습니다. Alpacon Cloud에서는 명령이 접수된 뒤
  실행 전에 `command_acl_denied`로 거부되고, 자체 호스팅 배포에서는 요청이 `api_token_acl_not_allowed`로
  거부됩니다. [거부 메시지](#거부-메시지)를 참고하세요.

### 끝의 와일드카드는 인자를 요구합니다

` *`로 끝나는 규칙은 인수를 하나 이상 요구합니다. 와일드카드 앞의 공백도 규칙에 포함되기 때문입니다.

| 규칙 | 허용하는 명령어 | 허용하지 않는 명령어 |
| --- | --- | --- |
| `docker` | `docker` | `docker ps` |
| `docker *` | `docker ps`, `docker compose up -d` | `docker`(인수 없음) |
| `systemctl status *` | `systemctl status nginx` | `systemctl restart nginx` |

인수가 없는 명령어와 인수가 있는 명령어를 모두 허용하려면 `docker`와 `docker *` 규칙을 각각
추가하세요.

### 규칙의 사용자와 그룹

각 규칙은 명령어를 실행할 수 있는 시스템 사용자와 그룹도 지정합니다.

| 토큰 유형 | 사용자 이름을 비운 경우 | 사용자 이름이 `*`인 경우 | 사용자 이름이 `deploy`인 경우 |
| --- | --- | --- | --- |
| API 액세스 토큰 | 토큰 소유자만 허용 | 모든 사용자 허용 | `deploy`만 허용 |
| 서비스 토큰 | **모든 사용자 허용** | 모든 사용자 허용 | `deploy`만 허용 |

서비스 토큰은 개인이 아닌 애플리케이션에 속하므로 기본값으로 사용할 소유자가 없습니다. 서비스 토큰
규칙에서 사용자 이름을 비워 두면 **모든** 시스템 사용자가 허용됩니다. 한 계정으로 제한하려면 사용자
이름을 명시하세요.

## 명령 규칙과 sudo 정책은 정반대입니다

Alpacon에서는 명령 패턴을 **sudo 정책**에도 씁니다. 이 정책은 어떤 사용자가 어떤 서버에서 권한을
높일 수 있는지 결정합니다. 두 패턴은 비슷해 보이지만 검사 시점과 비교 대상이 달라, 같은 명령에도
서로 반대되는 패턴을 써야 합니다.

|  | 허용 명령 규칙 | sudo 정책 |
| --- | --- | --- |
| 적용 대상 | 토큰 하나 | 선택한 서버의 Alpacon 사용자 |
| 검사 시점 | 명령을 서버로 보내기 전 | 서버가 Alpacon에 권한 상승 승인을 요청할 때 |
| 비교 대상 | `sudo`를 포함해 입력한 명령줄 | `sudo`를 제외하고 root 권한으로 실행할 명령 |
| `sudo systemctl restart nginx`의 패턴 | `sudo systemctl restart nginx` | `systemctl restart nginx` |
| 패턴 앞의 `sudo` | 필요 | 정책 저장 시 거부됨 |
| 일치하지 않을 때 | 명령이 거부되고 아무것도 실행되지 않음 | 권한 상승이 거부되고 `sudo`가 오류를 내며 종료됨 |

`sudo`로 시작하는 패턴이 들어 있는 sudo 정책은 저장할 때 `sudo_policy_pattern_has_sudo_prefix`
오류가 납니다. 의도적으로 그렇게 설계했습니다. 이런 패턴은 어떤 명령에도 일치할 수 없으므로, 몇 주
뒤 이유도 모른 채 거부되는 것보다 입력할 때 오류를 알려주는 편이 낫습니다.

sudo 정책을 만들고 사용하는 방법은 [sudo with MFA](/use/work-sessions/terminal/sudo-with-mfa/)를 참고하세요.

## 거부 메시지

권한 상승이 거부되면 터미널에 `Alpacon denied this sudo command (CODE).`가 표시되고 `sudo`가 0이
아닌 종료 상태로 끝납니다.

| 코드 | 의미 | 해결 방법 |
| --- | --- | --- |
| `SUDO_RISK_DENIED` | 명령의 위험도가 심각으로 평가되었거나 워크스페이스에서 허용하는 수준을 넘었으며, 승인한 사람이 없음 | 사람이 명령 자체를 승인해야 함. 작업 세션에서 실행하면 보류된 명령에 대한 승인이 해당 명령의 `sudo`에도 적용됨. 또는 명령을 더 작은 범위로 나누어 실행해야 함 |
| `SUDO_COMMAND_NOT_AUTHORIZED` | 이 배포 환경에서는 sudo 명령어의 실행 주체를 사람으로 확인할 수 없음 | 로그인한 사람이 권한을 받아 명령어를 실행해야 함. 자체 호스팅의 기본 서비스 토큰 sudo 결과임 |
| `SUDO_NO_WORKSESSION_POLICY` | 이 명령과 일치하는 sudo 정책이 없음 | 명령어 패턴이 일치하는 작업 세션에서 실행해야 함. 패턴 추가에는 승인이 필요할 수 있음 |
| `SUDO_POLICY_MFA_REQUIRED` | 일치하는 sudo 정책에 MFA가 필요하지만 비대화형 명령어에서는 완료할 수 없음 | 대화형 터미널에서 MFA를 완료하고 명령어를 실행해야 함 |
| `WORK_SESSION_SCOPE_NOT_ALLOWED` | 작업 세션에 sudo 범위가 포함되지 않음 | 세션을 만들 때 sudo 범위를 요청해야 함 |

토큰의 허용 명령 규칙이 명령을 거부했다면 다른 문제입니다. 이 경우에는 서버에 아무것도 전달되지 않으며,
거부가 드러나는 방식은 배포 환경에 따라 다릅니다.

Alpacon Cloud에서는 API가 명령을 접수한 뒤, 실행 전에 `command_acl_denied`로 거부합니다. [명령어](/use/audit/events/commands/#거부-사유-확인) 기록에서 명령을 열고
**거절 이유**에서 사유를 확인하세요.

자체 호스팅 배포에서는 명령을 보내기 전에 API가 `api_token_acl_not_allowed`를 반환합니다.
응답은 원인과 관계없이 같습니다. 거부된 명령은 [명령](/use/audit/events/commands/) 기록에 남고, 그
**거절 사유**를 보면 아래 세 원인 중 무엇인지 알 수 있습니다.

- `Command contains a redirection (>, >>, <); ...`: 어떤 규칙으로도 허용할 수 없는 명령줄입니다. 리디렉션을 빼거나
  서버의 스크립트 안으로 옮기세요.
- `Command quoting or a comment cannot be read the same way by every shell, ...` 또는
  `Command contains shell quoting that could obfuscate substitutions.`: 이것도 규칙으로 허용할 수 없습니다.
  따옴표를 단순하게 바꾸고 `$'...'`와 `$"..."`를 피하거나, 주석을 `$(...)`나 `(...)` 밖으로 옮기세요.
- 그 밖의 사유는 입력한 명령줄과 일치하는 허용 명령 규칙이 없다는 뜻입니다.
  [실행하는 명령 그대로 규칙 작성하기](/use/iam/applications/service-tokens/command-patterns/#실행하는-그대로-규칙을-작성하세요)를
  다시 확인하세요.

같은 `api_token_acl_not_allowed` 코드라도 서버, 명령어 또는 파일 접근이 거부된 경우일 수 있습니다. 보고된 검사 단계와 명령어 거부 사유를 확인한 뒤 해당 규칙을 수정하세요. 명령어가 거부되었다면 허용 명령어를, 서버나 파일이 거부되었다면 해당 접근 규칙을 확인하세요.

## 관련 문서

- [서비스 토큰으로 명령어 허용](/use/iam/applications/service-tokens/command-patterns/)
- [개인 API 토큰 관리](/use/settings/api-tokens/)
- [alpacon token acl command](/reference/cli/token/acl-command/)
- [접근 제어 목록 API](/reference/api/acl/)
- [명령어 기록](/use/audit/events/commands/)

Source: https://docs.alpacax.com/ko/reference/tokens/command-patterns/
