권한과 가드
내 PC에 셸 권한을 가진 에이전트를 남에게 열어 주는 법. 그리고 멈추는 것도 기능입니다.
제 PC를 마음대로 만질 수 있는 물건을 남에게 열어 주는 방법입니다. 그리고 «멈추는 것»도 기능입니다.
문제부터 — 이건 위험한 물건입니다
이 물건은 제 컴퓨터에서 명령을 실행할 수 있습니다. 파일을 읽고, 쓰고, 프로그램을 돌립니다.
그걸 메신저로 열어 둔다는 건, 그 메신저에 들어온 사람이 제 컴퓨터에 말을 걸 수 있다는 뜻입니다.
그래서 누가 무엇까지 할 수 있는지를 먼저 정해야 합니다.
세 등급으로 갈랐습니다
| 등급 | 어디서 | 할 수 있는 것 |
|---|---|---|
| 주인(저) | 어디서나 | 전부 |
| 조직 멤버 | 지정된 채널 | 정해진 폴더만, 읽기만 |
| 손님 | 초대된 채널 | 허용 목록에 적힌 폴더만. 명령 실행 금지 |
제일 중요한 한 줄 — 「읽기를 막으면 다른 길로 읽습니다」
여기가 이 글에서 제일 값나가는 자리입니다.
손님에게 파일 읽기를 제한했다고 해 봅시다. 그런데 명령 실행은 열어 뒀습니다.
그러면 어떻게 되냐면 — 명령으로 파일을 읽습니다.
「파일을 열어라」는 막혔는데, 「이 명령을 실행해라」로 같은 파일을 볼 수 있습니다. 도착지가 같으면 길을 하나 막아도 소용이 없습니다.
간접 경로가 하나라도 열려 있으면, 직접 경로를 막은 의미가 없습니다.
그래서 손님 등급에서는 명령 실행도, 도구 실행도, 하위 작업 생성도 같이 막습니다. 셋 다 「다른 길로 읽기」가 되기 때문입니다.
이런 건 하나씩 볼 때는 안 보입니다. 「파일은 막았으니 됐다」로 넘어갑니다. 「이 목적지에 닿는 길이 몇 개인가」를 세어 봐야 보입니다.
조직 설정은 파일 한 장입니다
파일 하나 = 조직 하나입니다. 그 안에 이게 다 들어 있습니다.
- 누가 멤버인가
- 어느 채널에 붙는가
- 어느 폴더를 읽을 수 있는가
- 어떤 명령을 쓸 수 있는가
- 시간당 몇 번까지
파일 한 장에 모아 둔 이유는 한눈에 보이게 하기 위해서입니다. 설정이 여러 군데 흩어져 있으면 「이 사람이 지금 뭘 할 수 있지?」에 답할 수가 없습니다.
설정을 몰래 고치면 되돌리고 알립니다
누군가 설정 파일을 직접 고치면, 되돌리고 주인에게 알립니다.
「막는다」가 아니라 「되돌리고 알린다」인 게 중요합니다. 막기만 하면 누가 시도했는지 안 남습니다.
그리고 「멈추는 것」도 기능입니다
마지막이 이 물건의 성격을 정합니다.
긴 작업을 이어서 할 때, 이 물건은 선택지와 그 대가를 먼저 보여 주고 멈춥니다. 제가 승인해야 실행합니다.
그리고 바깥으로 나가는 일은 전부 그렇습니다.
| 무엇 | 어디까지 자동 | 어디부터 사람 |
|---|---|---|
| 글 발행 | 원고 준비까지 | 올리기 |
| 코드 올리기 | 정리·검사까지 | 올리기 |
| 티켓 등록 | 초안 작성까지 | 등록 |
전부 준비는 끝내 놓고 멈춰서 기다립니다.
이유는 하나입니다 — 되돌리기 어려운 일과 되돌리기 쉬운 일은 다르게 다뤄야 합니다. 파일 하나 읽는 건 잘못돼도 다시 하면 되고, 한번 밖으로 나간 것은 못 주워 담습니다.
그래서 자동화의 목표를 「끝까지 혼자 한다」가 아니라 「사람이 판단할 지점까지 다 준비해 둔다」로 잡았습니다.
여기부터는 자세한 기록입니다
내 PC에 셸 권한을 가진 에이전트는 챗봇과 위험 등급이 다르다. 그래서 제일 오래 걸린 게 에이전트 루프가 아니라 가드였다.
| 티어 | 어디서 | 할 수 있는 것 |
|---|---|---|
| 오너 | DM · 모든 채널 | 전권 — 셸 · 파일 · 스킬 |
| 조직 멤버 | 바인딩된 채널 | 그 조직 파일에 적힌 폴더만, 읽기 전용 |
| 손님 | 초대된 채널 | 허용 목록 폴더만. Bash · Skill 차단 |
읽기를 막으면 셸로 읽는다
손님 티어에서 Bash를 같이 막는 게 핵심이다. 파일 읽기 권한만 잠그고 셸을 열어 두면, 셸로 파일을 읽는다. 같은 이유로 스킬 실행과 하위 작업 생성도 막는다 — 간접 실행 경로가 하나라도 열려 있으면 직접 경로를 막은 의미가 없다.
여기서 실무적인 함정이 하나 있었다. 차단 규칙이 468개까지 늘어난다. 이걸 명령줄로 넘기면 셸의 명령줄 길이 한계에 걸려 실행 자체가 안 된다. 에러 메시지는 “명령줄이 너무 깁니다” 한 줄이라 원인을 짚기 어렵다. 지금은 설정 파일로 넘긴다.
그리고 매니페스트가 비어 있으면 전부 허용이 아니라 전부 차단이다. 실수로 파일을 비웠을 때 잠기는 쪽이 열리는 쪽보다 낫다.
조직은 파일 한 장이다
파일 하나 = 조직 하나. 그 안에 멤버, 바인딩된 채널, 읽을 수 있는 폴더, 쓸 수 있는 명령, 시간당 상한이 들어 있다.
해석 순서가 정해져 있다 — 오너 > 명시 멤버 > 채널 바인딩 > 무소속. 그리고 조직끼리는 격리되고, 조직 파일은 읽기 전용이다.
파일로 둔 이유는 손으로 열어 볼 수 있어야 하기 때문이다. 권한 설정이 데이터베이스나 명령 이력에만 있으면, “지금 이 사람이 뭘 볼 수 있나”에 답하려면 도구를 돌려야 한다. 파일이면 열어 보면 된다.
자격증명은 되돌리지 않고 알린다
설정 파일을 직접 고치면 되돌리고 오너에게 알린다.
절반만 적용된 자격증명이 아예 안 바꾼 것보다 나쁘기 때문이다. 반쯤 바뀐 상태로 도는 에이전트는 어느 계정으로 무엇을 했는지가 흐려진다.
이 가드에 내가 한 번 걸렸다. 토큰을 손으로 넣었는데 다음에 보니 사라져 있어서 “저장이 안 됐다”고 오진하고 한 시간을 썼다. 되돌릴 때 알림이 오는데 그걸 먼저 안 봤다. 가드가 잘 돌아서 생긴 혼란이라, 지금은 “사라졌으면 알림부터 확인”이 첫 단계다.
멈추는 것도 기능이다
긴 파이프라인을 스레드에서 재개할 때, Loki는 선택지와 그 대가를 먼저 보여주고 멈춘다. 승인해야 실행한다.
이 게이트에는 성질이 두 개 있다.
게이트는 두뇌를 부르지 않는다. 그래서 구독 한도가 바닥나 있어도 확인까지는 정상 동작한다. 한도가 없어서 재개를 못 하는 상황에서 재개 확인이 안 되면, 그건 두 번 막히는 것이다.
대기 상태는 디스크에 남는다. 처음엔 메모리에 15분만 들고 있었는데 첫 실사용에서 바로 깨졌다 — 물음 15:27, 답 16:53. 85분 뒤였다. 만료된 확인이 조용히 두뇌로 새어 들어갔고, 두뇌는 “수동으로 실행할까요?“라고 지어냈다.
15분이 짧아서 틀린 게 아니다. 재개는 한도 리셋을 기다렸다 하는 일이라 분 단위 수명이 현실과 안 맞았고, 워커 재기동에도 살아남아야 했다.
낡은 답의 위험은 시간으로 막지 않는다. 답이 왔을 때 선택지를 다시 계산해 물었을 때와 같은지 대조하고, 다르면 실행 대신 되묻는다. 만료된 것도 조용히 흘리지 않고 “만료됐다”고 알린다.
바깥으로 나가는 것
발행, push, 티켓 등록. 전부 준비까지는 자동으로 하고 멈춰서 사람을 기다린다.
기준이 하나다 — 이 기계 밖에 흔적이 남는가. 파일을 고치는 건 되돌릴 수 있고, 올라간 글은 되돌려도 본 사람이 있다.