작업 공간 GitLab 인증
원천 · framework/evomind/web/workflow-project-evo-service기준 · 릴리스 v0.12.0커밋 · 2e32c6cc파일 · docs/operations/workspace-token.md기준선 · 2026-11-12
웹 채팅의 workflow 작업 공간(workspace-runner.md)은 사용자를 대신해 GitLab 에 clone·push·MR 을 한다. 이 문서는 그 실행이 어떤 GitLab 계정·토큰으로 도는지, 토큰을 어떻게 보관·전달하는지, 설정과 남은 한계를 적는다.
1. 두 가지 인증 출처
섹션 제목: “1. 두 가지 인증 출처”| 출처 | source |
무엇 |
|---|---|---|
| 사용자별 등록 | user |
사용자가 설정 화면에서 직접 등록한 자기 GitLab 토큰. 권장. |
| 배포 설정 | local |
WORKSPACE_GITLAB_TOKEN 환경 변수 하나. 사용자별 등록을 쓰지 않는 구성·개발 환경의 대체 수단. |
- 사용자가 등록한 토큰이 있으면 그것을 쓰고, 없으면 로컬 토큰으로 돌아간다.
- 둘 다 없으면 그 사용자의 실행 인증이 없다(
configured=false). 실행을 거부하는 판단은 호출 쪽이 한다. - 사용자 계정이 비활성이면 등록한 토큰도 쓰지 않는다.
- 토큰은 어떤 경우에도 환경 변수로만 받고, DB·볼륨·이미지·로그·응답·감사·문서에 원문을 남기지 않는다.
2. 설정
섹션 제목: “2. 설정”| 환경 변수 | 기본값 | 설명 |
|---|---|---|
WORKSPACE_ENABLED |
false |
기능 스위치. 꺼져 있으면 실행 인증을 만들지 않고 등록 API 도 거절한다. |
WORKSPACE_TOKEN_KEY |
(비움) | 사용자별 토큰을 암호화하는 AES-GCM 키(base64, 16·24·32바이트). 비우면 사용자별 등록을 열지 않는다. |
WORKSPACE_GITLAB_HOST |
(비움) | GitLab 허용 호스트. https 여야 한다. 토큰 등록 때 이 호스트로만 사용자 조회를 한다. 작업 이미지의 clone 허용 호스트(RUNNER_ALLOWED_GIT_HOSTS)와 같은 서버다. |
WORKSPACE_GITLAB_TOKEN |
(비움) | 로컬(공용) 토큰. 비밀이며 값은 문서·로그·이슈에 적지 않는다. |
WORKSPACE_GITLAB_USER_NAME |
(비움) | 로컬 토큰의 커밋 작성자 이름. 비우면 git 작성자 변수를 넘기지 않는다. |
WORKSPACE_GITLAB_USER_EMAIL |
(비움) | 로컬 토큰의 커밋 작성자 메일. |
WORKSPACE_GITLAB_TOKEN_EXPIRES_AT |
(비움) | 로컬 토큰의 만료일(ISO-8601). 날짜만(2026-12-31)도 받고 그날 끝까지 유효로 본다. |
WORKSPACE_TOKEN_EXPIRY_WARNING |
14d |
만료일이 이 기간 안이면 화면에 경고를 담는다. |
- 키 만드는 법:
openssl rand -base64 32. 값은 배포 서버의.env에만 두고 저장소·이슈·MR·문서에 적지 않는다. - 키를 바꾸면 이미 등록된 토큰은 복호화되지 않는다. 등록 행은 지우지 않지만 쓰지 않고 “등록 없음”으로 다루므로 사용자가 다시 등록해야 한다.
- 기능을 켰는데 암호화 키도 로컬 토큰도 없으면 기동할 때 값이 아니라 빠진 항목만 경고 로그로 알린다.
deploy/.env.example·deploy/docker-compose.yml에 같은 이름으로 전달한다.
3. 보관 형식
섹션 제목: “3. 보관 형식”- 테이블
workspace_gitlab_tokens(V31): 사용자당 한 행.token_cipher에 base64(nonce‖암호문‖태그) 만 둔다. - 알고리즘 AES/GCM/NoPadding, nonce 12바이트(등록할 때마다 새로), 태그 128비트. 복호화는 실행 인증을 만들 때 한 번뿐이다.
- 함께 남기는 값: GitLab 사용자 id·사용자 이름·프로필 이름·메일·만료일(등록할 때 GitLab 이 확인해 준 값), 등록 시각.
- 원문을 되돌려 주는 API 는 없다. 화면에도 등록 직후에도 다시 보여 주지 않는다.
- 삭제는 행을 지운다. 이후 실행에는 그 토큰이 쓰이지 않는다. GitLab 에서 토큰을 폐기(revoke)하는 것은 사용자가 한다 — 화면이 안내한다.
4. 등록 절차 (서버)
섹션 제목: “4. 등록 절차 (서버)”POST /api/workspace/auth/token {"token": "glpat-…"} (인증 필요)
- 기능 스위치 · 암호화 키 · https 호스트 확인 (아니면
409) - 토큰 형식 검사 — URL 안전 문자만, 8~255자 (
400 invalid_token_format) - 배포 설정의 GitLab 호스트에
GET /api/v4/user(PRIVATE-TOKEN) — 사용자 id·이름·프로필 이름·메일 확인.GET /api/v4/personal_access_tokens/self로 만료일을 덧붙인다(권한이 없으면 만료일만 모른다).- 거절(401·403) →
400 invalid_token - 닿지 못함·비정상 응답 →
502 gitlab_unreachable
- 거절(401·403) →
- AES-GCM 으로 암호화해 저장하고, 상태(
AuthStatusView)를 돌려준다.
- 어떤 토큰 종류든 된다(personal·project·group). 이슈 조회와 push 에는
api범위(또는 push 만이면write_repository)가 필요하다. - 등록한 토큰의 GitLab 사용자가 지금 에이전트 ID 의 소유자와 다르면 상태의
agentIdMismatch가 true — 화면이 “에이전트 ID 를 다시 등록하세요”를 안내한다. 에이전트 ID 등록은 등록 당시 토큰의 GitLab 사용자 id 를workspace_agent_ids.gitlab_user_id에 함께 남긴다. - 실패 로그에는 사용자 이름과 GitLab 사용자 id 만 남긴다. 토큰·암호문·호스트는 남기지 않는다.
DELETE /api/workspace/auth/token (인증 필요) — 등록을 지우고 상태를 돌려준다(로컬 토큰이 있으면 그쪽으로 돌아간다).
5. 실행에 전달하는 방법
섹션 제목: “5. 실행에 전달하는 방법”호출 쪽이 runner 의 /v1/exec·/v1/repo/* 요청 env 에 아래 값을 싣는다 — 그 실행의 프로세스에만 전달되고
디스크에 쓰지 않는다. runner 는 요청의 환경 변수를 자식에게만 넘기고 감사에 값을 남기지 않는다.
| 변수 | 설명 |
|---|---|
GITLAB_TOKEN |
glab 인증. glab 은 이 값으로 GITLAB_HOST 의 API 를 부른다. |
GITLAB_HOST |
glab 이 쓸 GitLab 호스트(https). |
GIT_ASKPASS |
/usr/local/bin/git-askpass — git 이 https 자격증명을 물을 때 환경 변수만 읽어 답한다(작업 이미지에 들어 있다). |
GLAB_CONFIG_DIR |
호출 쪽이 사용자 홈 안의 휘발성 설정 폴더를 정해 넘긴다(토큰은 env 로만 가고 설정 폴더에 쓰지 않는다). |
GIT_AUTHOR_NAME·GIT_AUTHOR_EMAIL·GIT_COMMITTER_NAME·GIT_COMMITTER_EMAIL |
커밋 작성자. GitLab 프로필 값(사용자 등록) 또는 설정 값(로컬 토큰)이 있을 때만 넣는다. |
- git(clone·push)은
GIT_ASKPASS도우미로만 자격증명을 받는다. 사용자 이름은oauth2(또는GIT_ASKPASS_USERNAME), 비밀번호는GITLAB_TOKEN이다. 토큰이 원격 주소·.git/config·credential 저장소에 남지 않는다(이미지 설정이credential.helper =로 저장소를 끈다). - 작업 이미지의
git-askpass는 토큰이 없으면 빈 값을 낸다 — 인증 없이 실행하면 git 이 묻지 않고 실패한다.
6. 상태 API
섹션 제목: “6. 상태 API”GET /api/workspace/auth (인증 필요) — 설정 화면과 작업 공간 창이 실행에 쓰는 GitLab 계정·만료를 안내한다.
{"enabled": true, "source": "user", "configured": true, "gitlabUserName": "Hong Gil Dong", "expiresAt": "2026-12-31T00:00:00Z", "warning": null, "canRegister": true, "agentIdMismatch": false}source—user(내가 등록) ·local(배포 설정 토큰).configured— 이 사용자의 실행에 인증을 실을 수 있는지(기능·토큰·계정 활성).warning—expiring(만료 임박) ·expired(지남) ·invalid_expiry(만료일 형식 오류) ·null.canRegister— 암호화 키가 있어 등록 폼을 열 수 있는지.agentIdMismatch— 등록한 에이전트 ID 의 GitLab 사용자와 지금 토큰의 GitLab 사용자가 다른지(둘 다 알 때만 판단).- 토큰·GitLab 주소는 응답에 없다.
7. 화면
섹션 제목: “7. 화면”설정 > 작업 공간(SettingsModal → WorkspaceAuthSection) — 지금 쓰는 출처·GitLab 사용자·만료일과
경고, 토큰 등록 폼(비밀번호 입력), 등록한 토큰 삭제. 입력한 토큰은 등록 뒤 즉시 비우고 다시 보여 주지 않는다.
8. 확인 (수용 기준 대응)
섹션 제목: “8. 확인 (수용 기준 대응)”| 기준 | 확인 방법 |
|---|---|
| 토큰 원문이 로그·감사·응답·이미지·볼륨에 없다 | 앱 로그·감사 테이블에서 토큰 문자열 검색, GET /api/workspace/auth 응답에 없음, DB 행은 token_cipher 만, 이미지에 값을 넣지 않음 |
| 삭제하면 이후 쓰이지 않는다 | 삭제 뒤 configured=false(로컬 토큰이 없을 때), 다음 실행 env 에 없음 |
| 등록 토큰으로 이슈 조회·push | 시험 계정으로 등록 → 작업 공간에서 glab issue view·git push |
| 비활성 계정은 토큰을 쓰지 않는다 | credentialsFor 가 빈 값, configured=false |
| 토큰 종류·사용자·만료 표시, 불일치 경고 | 등록 응답·화면에 GitLab 사용자·만료일, 다른 사용자 토큰으로 바꾸면 agentIdMismatch=true |
9. 남은 한계
섹션 제목: “9. 남은 한계”- 토큰 폐기(revoke)를 GitLab 에 대신 요청하지 않는다 — 삭제는 서버 보관만 지운다. 화면이 GitLab 에서 폐기하도록 안내한다.
- 로컬 토큰 단계의 에이전트 ID 는 소유자를 모르므로(
gitlab_user_id가 비어 있음) 불일치 판단을 하지 않는다. - 토큰 범위(scope)를 서버가 검사하지 않는다 — GitLab 이 주는 만료일·프로필만 확인하고, 실제 권한은 첫 실행에서 드러난다.
답변은 문서를 근거로 만들지만 틀릴 수 있습니다. 출처 문서를 함께 확인하세요.