← 개발 로그 목록

website: dbclient forced command permission denied 수정

/ 4분 분량 / 개발 로그

dbclient 계정으로 SSH 접속할 때 forced command가 permission denied로 죽는 문제를 고쳤다.

등록된 키를 가진 팀원이 dbclient로 접속하면 pubkey 인증은 통과하고 세션도 열리는데, forced command인 dbclient-sqlite-guard.sh exec 단계에서 바로 disconnect되는 증상이었다. authorized_keys에 command를 걸어두고 stage/prod 조회·작성 권한을 좁혀서 주는 구조라, 이 스크립트가 죽으면 dbclient 접속 자체가 무용지물이 되는 상황이었다.

먼저 스크립트 자체 권한을 의심했다. 서버에 들어가서 ls -l로 확인해보니 실행권한이 없었다. 그런데 과거에 누가 수동으로 chmod +x를 걸어놨을 가능성이 있었고, 실제로 그랬을 것 같았다. 문제는 git ls-tree로 레포에 커밋된 모드를 확인해보니 100644였다는 점이다. 즉 서버에 수동으로 실행권한을 걸어놨더라도, 그 뒤 git pull이든 재배포든 재체크아웃이 한 번이라도 지나가면 git이 기억하는 644로 조용히 되돌아간다. 이건 처음 겪는 패턴이 아니었다. backup-db.sh에서 07-13에 이미 똑같은 걸 겪었고 pm/docs/learnings.md에 교훈으로 남겨뒀던 사안이다. "서버에 지금 실행권한이 있다"는 사실이 "git에도 그렇게 기록돼 있다"는 뜻은 아니라는 걸 알고 있었는데도, forced command 스크립트를 새로 추가할 때 이 체크를 빼먹은 셈이었다.

원인 하나를 찾았다고 바로 끝내지 않고 /home/ubuntu 디렉터리 자체의 통과 권한도 다시 점검했다. 여기서 getfacl을 돌려보니 dbclient에게는 이미 setfacl -m u:dbclient:x /home/ubuntu 방식으로 개별 ACL이 걸려 있었다. 즉 디렉터리 통과는 애초에 문제가 아니었던 부분이다. 그런데 이걸 확인하는 과정에서 실수로 chmod o+x /home/ubuntu(other 전체 대상)를 걸어버렸다. 이러면 dbclient뿐 아니라 서버의 다른 로컬 계정(opc 등)까지 /home/ubuntu를 통과할 수 있게 될 뻔했다. 이것도 정확히 pm/docs/learnings.md에 이미 적혀 있던 사고 패턴("chmod o+x는 형제 디렉터리까지 다 뚫는다")을 그대로 재현할 뻔한 것이었다. 다행히 바로 알아채고 chmod o-x로 되돌린 다음 기존 ACL만 남기는 걸로 정리했다.

수정은 두 갈래로 했다. 서버에는 sudo chmod 755로 즉시 실행권한을 걸어 당장 접속이 되도록 복구했고, 레포에는 git update-index --chmod=+x infra/dbclient-sqlite-guard.sh로 트리 자체의 모드를 100755로 커밋했다. 서버에서만 chmod로 끝냈다면 다음 재배포에서 또 똑같이 벗겨질 게 뻔했기 때문에, 근본 수정은 git 쪽에서 해야 했다.

테스트는 sudo -u dbclient로 접속을 시뮬레이션해서 forced command가 정상적으로 select 1을 응답하는지 확인했고, opc 같은 다른 계정은 여전히 차단되는지도 같이 봤다. git ls-tree HEAD -- infra/dbclient-sqlite-guard.sh로 커밋된 모드가 100755로 바뀐 것도 확인했다.

문서 쪽은 infra/db-access.md에 "주의" 섹션으로 원인과 진단 과정, 재발 방지 방법을 남겼다. forced command로 쓰는 스크립트를 추가하거나 수정할 때는 항상 git ls-tree HEAD로 커밋된 모드가 100755인지 확인할 것, 그리고 제한 계정에 상위 디렉터리 접근을 열어줄 때는 chmod o+x로 전체 공개하기 전에 getfacl로 이미 걸린 개별 ACL이 없는지부터 보고, 새로 열더라도 setfacl -m u:계정:x로 계정 단위로만 좁히라는 내용이다. 이번 건도 결국 같은 레포 안에서 이미 한 번 문서화됐던 패턴 두 개가 그대로 반복된 경우였다. 문서에 적어두는 것과 별개로, forced command 스크립트를 다룰 때는 권한 확인을 체크리스트처럼 습관화할 필요가 있다는 걸 다시 확인한 셈이다.