[4편] QueryPie ACP 읽기 권한으로 UPDATE를 실행해 보면? — 쿼리 차단부터 권한 회수, 감사 로그까지
2026년 11월 8일
지난 편에서는 QueryPie에 DB를 등록하고 DBeaver로 주문 데이터를 조회했다. 접속 정보를 직접 넣는 방법과 Multi Agent에서 DBeaver를 여는 방법까지 써봤다.
조회가 되는 건 확인했으니, 이번에는 반대로 해보고 싶었다. 읽기 권한만 받은 개발자가 UPDATE를 실행하면 어떻게 될까? 관리자가 접근 권한을 거두면 이미 열어 둔 연결도 쓸 수 없게 될까?
테스트용 주문 한 건으로 수정 쿼리를 실행하고, 접속 권한을 회수한 뒤 관리자 감사 화면까지 확인했다. 사용한 환경은 QueryPie ACP Community 11.6.7, MySQL 8.0.42, DBeaver 26.2.4다. 데이터는 모두 실습용으로 만들었다.
1. MySQL에서는 수정할 수 있는 계정을 준비했다
먼저 지난 편의 설정을 조금 짚고 넘어가야 한다. 그때 만든 orders_reader 계정에는 MySQL에서도 SELECT 권한만 줬다. 이 계정으로 UPDATE가 실패하더라도 QueryPie가 막았는지, MySQL이 막았는지 결과만 보고 판단하기 어렵다.
그래서 이번에는 orders_control이라는 DB를 따로 만들었다. orders 테이블에 가상 주문 세 건을 넣고, control_writer 계정에는 이 테이블의 SELECT와 UPDATE만 허용했다. 지난 편에서 조회했던 orders_demo의 데이터와 권한은 그대로 뒀다.
확인할 주문은 4001번이다. 금액은 49,000원, 처음 상태는 PENDING이다. 이 주문을 SHIPPED로 바꾸는 쿼리를 직접 연결과 QueryPie 연결에서 각각 실행해 보기로 했다.
QueryPie에는 Orders Control Lab이라는 연결을 추가했다. DB 주소는 orders-db:3306, Database Name은 orders_control, DB 계정은 방금 만든 control_writer다. Test Connection으로 연결을 확인하고, 사용자 연결 목록에서 인증 정보를 숨기는 옵션도 켰다.

DB 계정은 수정할 수 있지만, 개발자에게는 조회만 허용할 생각이다. Databases → DB Access Control → Access Control에서 Demo Developer를 선택하고, Orders Control Lab에 Read-Only를 부여했다.

두 설정을 따로 해보니 구분이 분명해졌다. MySQL 계정이 가진 권한과, 그 계정을 통해 접속하는 사람에게 QueryPie가 허용한 작업은 같은 개념이 아니다. 이번에는 그 차이를 실제 쿼리로 확인하려고 한다.
2. DB에 직접 연결하면 UPDATE가 실행됐다
DBeaver에서 먼저 테스트 DB에 직접 연결했다. 실습용 MySQL을 Mac의 127.0.0.1:13306으로 열어 둔 상태라 이 주소와 control_writer 계정을 사용했다. DBeaver에 저장한 연결 이름은 orders_control이다.
현재 접속한 DB 계정과 주문 상태를 함께 조회했다.
SELECT CURRENT_USER() AS db_account, order_id, status, total_amountFROM orders_control.ordersWHERE order_id = 4001;

이어서 주문 상태를 바꿨다.
UPDATE orders_control.ordersSET status = 'SHIPPED'WHERE order_id = 4001;

수정은 성공했다. DB에서도 4001번 주문이 SHIPPED로 바뀐 것을 확인했다. 이 계정에 UPDATE 권한이 있다는 뜻이다. 다음 비교를 위해 주문 상태는 다시 PENDING으로 돌려뒀다.
3. QueryPie를 거치자 같은 UPDATE가 막혔다
이번에는 개발자 계정 demo-dev의 권한으로 QueryPie 프록시에 접속했다. 3편에서 사용한 Agentless Proxy 방식이다. DB 연결의 Proxy Usage를 켜고 등록된 DB 계정을 사용하도록 설정한 뒤, 개발자 화면의 Proxy Info에서 토큰을 발급받았다.
이번 연결에 할당된 프록시 주소는 127.0.0.1:40001이었다. DBeaver에는 원본 DB 비밀번호 대신 발급받은 토큰을 넣었다. 직접 연결과 헷갈리지 않도록 연결 이름도 Orders Control - QueryPie로 정했다.
앞에서 쓴 SELECT부터 실행했다. 주문이 조회됐고, CURRENT_USER()도 똑같이 control_writer@%로 나왔다. QueryPie가 등록된 DB 계정을 사용해 연결한 것을 확인할 수 있었다.

그 상태에서 앞서 성공했던 UPDATE를 그대로 실행했다. 이번에는 결과가 달랐다.

SQL Error [1317] [ERROR]: [ENGINE] No permission to execute UPDATE statement. Please check your privileges.
UPDATE를 실행할 권한이 없다는 메시지다. MySQL 계정에는 수정 권한이 있지만, QueryPie에서 이 개발자에게 준 권한은 Read-Only다. 직접 연결에서 수정이 되는 것을 먼저 확인했기 때문에 이번 차단을 DB 계정의 권한 부족과 구분할 수 있었다.
오류만 보고 끝내지 않고 주문을 다시 조회했다. 4001번 주문은 여전히 PENDING이었다. 이때 연결 번호도 함께 확인해 뒀다. 이어서 같은 연결을 열어 둔 채 접근 권한을 회수해 볼 생각이었다.

4. 접속한 상태에서 권한을 거두면 어떻게 될까?
회사에서는 계정을 만드는 것만큼 권한을 거두는 일도 자주 생긴다. 프로젝트가 끝나거나 담당자가 바뀌면 접근 권한을 정리해야 한다. 그런데 이미 DBeaver를 켜놓고 접속해 있는 사람은 어떻게 될까?
DBeaver는 그대로 두고 관리자 화면으로 돌아갔다. Demo Developer의 접근 권한 목록에서 Orders Control Lab만 선택한 뒤 Revoke를 눌렀다. 확인 창에서 OK를 누르자 해당 연결이 권한 목록에서 사라졌다.

다시 DBeaver로 돌아와, 열려 있던 SQL 에디터에서 같은 SELECT를 실행했다. 이번에는 주문 데이터 대신 Communications link failure라는 연결 오류가 나왔다.

연결을 새로 맺으면 다시 접속할 수 있을지도 확인해 봤다. DBeaver에서 연결을 끊고 재접속했지만, Cannot obtain session 메시지와 함께 접속이 차단됐다. 기존 연결뿐 아니라 새로 접속하는 경우에도 회수한 권한이 그대로 적용됐다.
직접 해보면서 눈에 띈 건 관리자가 권한을 회수하는 것만으로 이미 열려 있던 연결까지 통제할 수 있었다는 점이다. 이번 실습에서는 별도로 세션 종료 버튼을 누를 필요가 없었다. 프로젝트가 끝나거나 담당자가 바뀌었을 때, 사용자가 DBeaver를 닫기를 기다리지 않고 관리자가 접근을 정리할 수 있다는 점이 유용해 보였다.
이번 실습에서는 QueryPie에서 회수한 권한이 기존 연결과 재접속 모두에 적용됐다. 접근을 허용하는 것부터 필요 없어진 접근을 거두는 것까지, 관리자가 한곳에서 처리할 수 있다는 점이 QueryPie의 장점으로 느껴졌다.
5. DBeaver에서 실행한 쿼리가 감사 화면에 남았다
마지막으로 Audit → Databases → Query Audit를 열었다. 실행 시각을 맞춰 보니 방금 사용한 Demo Developer의 기록이 나왔다. 성공한 SELECT와 실패한 UPDATE를 각각 찾을 수 있었다.
UPDATE 기록은 Result가 Failure였고, 목록의 Prevented 항목도 Prevented로 표시됐다. 해당 행을 열어 상세 내용을 확인했다.

상세 화면에는 Demo Developer, Orders Control Lab, Read-Only와 Select 권한, DB 계정 control_writer가 표시됐다. Client Name은 DBeaver였다. 아래쪽에서는 실제로 실행한 UPDATE 본문과 “No permission to execute UPDATE statement. Please check your privileges.”라는 오류 메시지도 확인했다.
DB에는 공통으로 등록한 control_writer 계정으로 접속했지만, QueryPie 기록에서는 그 작업을 한 사용자를 Demo Developer로 구분할 수 있었다. 도입 담당자라면 공용 DB 계정을 쓰는 환경에서도 사람별 작업을 어디까지 추적할 수 있는지 이런 식으로 확인해 보면 좋겠다.
조회 성공 기록도 함께 남아 있었다. 다만 DBeaver가 테이블 정보를 읽기 위해 자동 실행한 쿼리도 목록에 들어와 있었다. 실제 업무에서 필요한 기록을 찾으려면 사용자와 실행 시각, 연결 이름을 기준으로 좁혀 보는 방법에 익숙해져야겠다.
6. 직접 해보니, 권한 설정 다음에 볼 것이 생겼다
이번에 확인한 결과는 다음과 같다.
확인한 작업실제 결과
수정 가능한 DB 계정으로 직접 UPDATE | 주문 1건 수정 성공 |
QueryPie Read-Only로 SELECT | 조회 성공 |
QueryPie Read-Only로 같은 UPDATE | 권한 오류로 차단, 주문 상태 유지 |
접근 권한 회수 후 기존 연결에서 SELECT | 연결 오류로 조회 실패 |
권한 회수 후 새로 접속 | 세션을 얻지 못해 접속 실패 |
Query Audit 확인 | SELECT 성공 및 UPDATE 차단 기록 확인 |
설정 화면에서 Read-Only를 고르는 것과, 실제 사용하는 도구에서 수정이 막히는 것을 보는 건 느낌이 달랐다. 이번에는 DBeaver를 그대로 사용하면서 조회는 되고 수정은 안 되는 차이를 확인할 수 있었다.
직접 연결에서 UPDATE가 성공했던 장면도 기억해 둘 만하다. QueryPie를 거치지 않고 DB에 바로 들어갈 수 있는 길과 원본 DB 자격증명이 남아 있다면, 그 경로에는 QueryPie 사용자 권한이 적용되지 않는다. 회사에 도입할 때는 DB가 접속을 받아줄 출발지를 제한하고 원본 계정도 함께 관리해야 한다.
또 읽기 전용이라고 데이터 유출까지 막는 것은 아니다. 어떤 데이터를 얼마나 볼 수 있는지, 결과를 복사하거나 내보낼 수 있는지는 따로 확인해야 한다. 이번 편은 조회와 UPDATE, 권한 회수에 범위를 두고 시험했다.
도입을 검토한다면 설정 항목을 보는 데서 끝내지 말고, 개발팀이 쓰는 도구로 같은 테스트를 해보면 좋겠다. 제한한 쿼리가 막히는지, 권한을 거두면 기존 연결이 어떻게 되는지, 그 작업을 관리자 화면에서 다시 찾을 수 있는지까지 이어서 확인하는 식이다.
다음에는 필요한 권한을 요청해서 받아보려고 한다
이번에는 관리자가 개발자에게 직접 권한을 주고 회수했다. 실제 회사에서는 매번 관리자에게 따로 연락해서 처리하기보다, 사용자가 필요한 접근을 요청하고 담당자가 승인하는 절차가 필요할 것이다.
다음 편에서는 개발자가 DB 접근을 요청하고 관리자가 승인하는 과정을 따라가 보려고 한다. 필요한 기간만 권한을 주는 방법과, 승인 후 사용자 화면에서 무엇이 달라지는지도 함께 확인할 생각이다.
![[3편] QueryPie ACP에 첫 DB 연결하기 — 개발자의 접속 방식은 어떻게 바뀔까?](/assets/content/acp-lab-notes/first-database-connection/01.webp)
![[5편] QueryPie ACP에서 DB 권한 요청하고 승인받기 — DBeaver 조회까지 직접 해봤다](/assets/content/acp-lab-notes/database-access-request/01.webp)