관리자 PAT 단일 방식의 문제
서비스 계정이 SYS_ADMIN 이면 AI 는 모든 프로젝트를 봅니다. 사용자는 A·B·C 만 접근
가능한데 결과에는 D·E·F 가 섞여 나옵니다. 정보 유출입니다.
bbmcp 는 Bitbucket Server 앞에 두는 MCP 게이트웨이입니다. Keycloak 으로 사용자를 인증하고, 요청자 본인의 Bitbucket 유효 권한을 매 호출마다 확인한 뒤에만 저장소와 풀 리퀘스트에 접근합니다. 서비스 계정의 넓은 권한은 데이터를 가져오는 수단일 뿐, 사용자의 권한으로 간주하지 않습니다.
Bitbucket Server 6.9.1 에는 GitLab 의 sudo 같은 범용 impersonation 이 없고, 관리자가
사용자를 대신해 개인 액세스 토큰을 만들어 줄 수도 없습니다. 그래서 흔히 쓰는 방법이
관리자 PAT 하나로 모든 REST 호출인데, 이 방식은 AI 에게 사용자가 볼 수 없는 저장소까지
보여 줍니다.
서비스 계정이 SYS_ADMIN 이면 AI 는 모든 프로젝트를 봅니다. 사용자는 A·B·C 만 접근
가능한데 결과에는 D·E·F 가 섞여 나옵니다. 정보 유출입니다.
모든 도구 호출 전에 요청자 본인의 유효 권한을 판정하고, 목록 결과도 요청자 기준으로 걸러서 돌려줍니다. 서비스 계정은 전송 수단일 뿐입니다.
최초 1회만 preferred_username 으로 Bitbucket 사용자를 정확히 일치 검색하고, 이후에는
Keycloak sub ↔ Bitbucket user.id 를 영구 기준으로 사용합니다. 검색 결과의 첫 번째
사용자를 집는 일은 없습니다.
요청 하나가 통과해야 하는 관문입니다. 하나라도 막히면 Bitbucket 에 아무 요청도 나가지 않습니다.
MCP 클라이언트의 OAuth 액세스 토큰 또는 개인 API 키를 검증하고 역할을 읽습니다.
Keycloak 주체를 Bitbucket 사용자 ID 에 연결합니다. 매핑이 없으면 권한이 필요한 도구는 거부됩니다.
관리자가 정한 프로젝트·저장소·브랜치 허용/차단과 위험도 상한을 평가합니다.
Bitbucket 권한 플러그인(권장) 또는 REST 폴백으로 요청자의 실제 READ/WRITE/ADMIN 을 확인합니다.
머지 대상 브랜치의 read-only 제한과 예외 사용자·그룹을 확인합니다.
쓰기·실행 등급은 인자 해시와 PR version 에 묶인 승인을 요구합니다. 바뀌면 즉시 무효입니다.
서비스 계정 PAT 으로 호출하고, 요청자·대리 계정·도구·대상·결과를 모두 감사 로그에 남깁니다.
유효 권한 = Bitbucket 사용자 권한
∩ MCP 접근 정책(프로젝트/저장소/브랜치)
∩ 도구 역할·스코프
∩ 승인(쓰기·실행 등급)
운영에 필요한 것을 기본으로 갖춘 상태로 배포됩니다.
Client ID 와 Secret 만 넣으면 디스커버리로 자동 구성됩니다. 로그인 화면에서 숨은 프레임으로
prompt=none 을 시도해, 기존 SSO 세션이 있으면 클릭 없이 들어갑니다.
클라이언트가 401 응답에서 인가 서버를 스스로 찾아 PKCE 로 로그인합니다. RFC 9728·8414·7591 을 지원하고, 토큰의 대상(aud/azp)과 스코프까지 검증합니다.
조회·작성·실행 3단계로 나뉘며 고수준 컨텍스트 도구를 포함합니다.
bitbucket_pr_review_context 하나로 PR·diff·커밋·댓글·활동을 한 번에 수집합니다.
사용자별 API 키 발급·회전·폐기를 제공합니다. 회전 시 유예 시간 동안 기존 키가 함께 동작해 무중단 교체가 가능합니다.
역할(스코프 묶음)을 관리자가 자유롭게 정의하고 수정합니다. 역할의 스코프를 줄이면 이미 발급된 키에도 즉시 반영됩니다.
승인은 호출 인자 해시와 PR version 에 묶입니다. 승인 뒤 인자가 바뀌거나 새 커밋이 올라오면
APPROVAL_STALE 로 거부합니다.
저장소에서 읽은 모든 내용에 출처와 trust: untrusted 를 붙여 반환하고, 모델에게
그 내용을 지시로 취급하지 말 것을 명시합니다.
Anthropic Messages 와 OpenAI 호환 두 형식을 지원하며 항상 스트리밍으로 중계합니다. 최대 출력 토큰은 256k 까지 설정할 수 있습니다.
요청자·Bitbucket 사용자·서비스 계정·도구·대상·승인·결과·지연을 기록합니다. 토큰과 소스·diff
본문은 기록하지 않습니다. /metrics 로 Prometheus 지표를 제공합니다.
서비스 설정은 관리자 콘솔에서, 키·토큰·승인·활동 기록은 개인 화면에서 관리합니다. 모든 화면은 한국어가 기본입니다.
가독성을 위해 본문 기본 글자 크기를 16px 이상으로 잡았고, 사용자가 90~140% 범위에서 조정할 수 있습니다.
환경변수는 네 개뿐입니다. Keycloak·Bitbucket·AI·정책을 포함한 나머지 설정은 모두 관리자 콘솔에서 입력하며, 비밀값은 AES-256-GCM 으로 암호화되어 PostgreSQL 에 저장됩니다.
docker load -i bbmcp-v0.2.1.tar.gz
docker images | grep bbmcp
# bbmcp v0.2.1 ...
| 변수 | 설명 | 예시 |
|---|---|---|
DATABASE_URL | PostgreSQL DSN | postgres://bbmcp:…@postgres:5432/bbmcp?sslmode=disable |
BOOTSTRAP_ADMIN | 최초 관리자 아이디 | admin |
BOOTSTRAP_ADMIN_PASSWORD | 최초 관리자 비밀번호 | 충분히 긴 임의 문자열 |
ENCRYPTION_KEY | 비밀값 암호화 키(32바이트) | openssl rand -base64 32 |
cp deploy/.env.example deploy/.env
$EDITOR deploy/.env
docker compose -f deploy/docker-compose.yml --env-file deploy/.env up -d
curl -fsS http://localhost:8080/healthz
백업은 두 가지를 함께 보관하십시오. PostgreSQL 덤프와 ENCRYPTION_KEY.
키를 분실하면 저장된 Client Secret·서비스 PAT·사용자 PAT 을 복호화할 수 없습니다.
{
"mcpServers": {
"bbmcp": {
"type": "http",
"url": "https://bbmcp.company.local/mcp",
"headers": { "Authorization": "Bearer bbmcp_xxx_yyy" }
}
}
}
Keycloak OAuth 를 쓰는 클라이언트는 /.well-known/oauth-protected-resource 메타데이터로
인가 서버를 자동 발견합니다.
Bitbucket Server 6.9.1 앞에 두는 MCP 게이트웨이입니다. AI 에이전트가 MCP 로 저장소·커밋·풀 리퀘스트를 읽고 쓸 때, Keycloak 으로 인증된 요청자 본인의 Bitbucket 유효 권한을 먼저 확인한 뒤에만 호출을 수행합니다.
노출되지 않습니다. 서비스 계정 PAT 은 REST 호출 수단일 뿐이며, 모든 도구 호출 전에 요청자 본인의 프로젝트·저장소 유효 권한을 따로 판정합니다. 목록 조회 결과도 요청자가 읽을 수 있는 항목만 남기고 걸러서 반환합니다.
필요하지 않습니다. 기본값은 중앙 서비스 계정 모드입니다. Bitbucket 에 남는 작성자를 본인 이름으로 만들어야 하는 경우에만, 사용자가 자신의 개인 액세스 토큰을 선택적으로 등록할 수 있습니다. 등록된 토큰은 AES-256-GCM 으로 암호화되어 저장됩니다.
OAuth 를 지원하는 클라이언트라면 URL 만 등록하면 됩니다. 인증 없이 호출하면 bbmcp 가 401 과 함께 보호 리소스 메타데이터 주소를 알려 주고, 클라이언트는 그 정보로 Keycloak 을 찾아 PKCE 로그인을 수행합니다. Keycloak 의 동적 등록이 막혀 있으면 bbmcp 가 사전 등록된 공개 클라이언트 ID 를 대신 내려 줍니다. OAuth 를 지원하지 않는 클라이언트는 개인 API 키를 사용합니다.
Keycloak 은 리다이렉트 URI 를 문자열 그대로 비교하므로 후행 슬래시, 대소문자,
:443 명시 같은 사소한 차이도 거부 사유가 됩니다. bbmcp 는 보내는 값을 항상
정규화해 저장하고, 관리 콘솔의 연결 점검 화면에서 Keycloak 에 그대로 등록할 문자열을
복사 버튼과 함께 보여 줍니다. 로그아웃용 post_logout_redirect_uri 는 관리자가
명시적으로 설정했을 때만 전송하므로, 등록하지 않아 발생하던 오류도 나지 않습니다.
없습니다. bbmcp 는 서명과 발급자, 만료에 더해 토큰의 대상(aud) 또는 인가된
당사자(azp)가 허용된 클라이언트인지 확인합니다. 필요하면 필수 스코프를 지정해
범위를 더 좁힐 수 있습니다.
필수는 아닙니다. 플러그인이 없으면 REST 폴백 모드로 전역·프로젝트·저장소·그룹 권한을 조합해
판정합니다. 다만 상속과 공개 저장소까지 Bitbucket 과 100% 동일하게 맞추려면 동봉된 권한
플러그인(plugin/) 설치를 권장합니다.
머지·승인·거절은 실행 등급으로 분류되어 기본 비활성 상태이며, 활성화하더라도 승인 없이 실행할 수 없습니다. 승인은 호출 인자 해시와 PR version 에 묶이므로, 승인 이후 인자가 바뀌거나 새 커밋이 올라오면 자동으로 무효화됩니다. 브랜치 제한도 별도로 확인합니다.
저장소에서 읽은 README·소스·커밋 메시지·PR 설명·댓글은 모두 신뢰할 수 없는 데이터로 표시해 반환합니다. 권한·정책·승인 판정은 모델이 아니라 서버가 수행하므로, 저장소 안의 지시문이 도구 실행으로 이어지지 않습니다.
Bitbucket 접근은 BitbucketAdapter 인터페이스 뒤에 분리되어 있습니다. 업그레이드 시
어댑터와 권한 플러그인만 교체하면 되고, MCP 도구·Keycloak 연동·관리 콘솔은 그대로 유지됩니다.
조회 등급(1차)과 고수준 컨텍스트 도구는 기본 활성, 쓰기 등급(2차)은 활성이지만 승인 필요, 실행 등급(3차: 머지·승인·거절)은 기본 비활성입니다. 관리자가 도구별로 조정할 수 있습니다.