CREATE USER 'readonly'@'10.0.0.%' IDENTIFIED BY '${READONLY_PASSWORD}';
GRANT SELECT ON *.* TO 'readonly'@'10.0.0.%';
FLUSH PRIVILEGES;
계정 식별자는 사용자@호스트 쌍이다. 같은 사용자 이름이라도 접속 출처가 다르면 다른 계정이므로, 호스트 부분을 되도록 좁게 준다. '%' 는 어디서든 붙을 수 있다는 뜻이라 관리 대상 계정에는 권하지 않는다.
GRANT · REVOKE · CREATE USER 는 권한 테이블을 즉시 반영하므로 FLUSH PRIVILEGES 가 꼭 필요하지는 않다. 권한 테이블을 UPDATE 로 직접 고쳤을 때만 필요하다.
특정 데이터베이스나 테이블로 좁히려면 범위를 바꾼다.
GRANT SELECT ON salesdb.* TO 'readonly'@'10.0.0.%';
GRANT SELECT (id, name) ON salesdb.users TO 'readonly'@'10.0.0.%';
부여된 권한 확인은 다음과 같다.
SHOW GRANTS FOR 'readonly'@'10.0.0.%';
리포팅 도구나 백업 계정은 SELECT 외에 다음이 더 필요할 때가 있다.
| 권한 | 필요한 상황 |
|---|---|
SHOW VIEW |
뷰의 정의를 읽을 때. mysqldump 가 뷰를 덤프할 때 필요 |
PROCESS |
SHOW PROCESSLIST 로 다른 세션을 볼 때. InnoDB 상태 조회 |
REPLICATION CLIENT |
복제 지연 확인 |
EXECUTE |
저장 프로시저를 호출할 때 |
LOCK TABLES |
일관된 덤프를 뜰 때 |
읽기 전용이라는 이름과 달리 PROCESS 는 다른 세션의 질의문을 볼 수 있게 하므로, 필요할 때만 준다.
빈 비밀번호로 계정을 만드는 방법이 돌아다니지만, 네트워크에서 접근 가능한 서버에서는 하지 않는다. 인증 없이 전체 데이터를 읽을 수 있는 통로가 된다. 비밀번호를 애플리케이션에 심기 싫다면 다음 중 하나를 쓴다.
같은 서버의 OS 계정과 묶는다. 로컬에서만 붙는 배치라면 소켓 인증이 비밀번호보다 안전하다.
-- MariaDB
CREATE USER 'batch'@'localhost' IDENTIFIED VIA unix_socket;
GRANT SELECT ON salesdb.* TO 'batch'@'localhost';
-- MySQL 8
CREATE USER 'batch'@'localhost' IDENTIFIED WITH auth_socket;
옵션 파일에 둔다. 명령줄에 비밀번호를 적으면 ps 에 노출되고 셸 이력에도 남는다.
[client]
user=readonly
password=${READONLY_PASSWORD}
chmod 600 ~/.my.cnf
mysql --defaults-file=~/.my.cnf -h db.example.com salesdb
mysql -u readonly -h db.example.com -p salesdb -e "SELECT 1"
쓰기가 실제로 막히는지도 확인한다.
CREATE TABLE t_test (id INT);
ERROR 1142 (42000): CREATE command denied to user ... 가 나오면 의도대로 된 것이다.