{#security-security} # 보안 AgensGraph의 보안 모델은 PostgreSQL의 것입니다. 롤·`pg_hba.conf`·TLS·`GRANT`·행 수준 보안이 모두 거기서와 똑같이 동작하며, [PostgreSQL의 클라이언트 인증](https://www.postgresql.org/docs/18/client-authentication.html) 장과 [데이터베이스 롤](https://www.postgresql.org/docs/18/user-manag.html) 장이 레퍼런스입니다. 이 페이지가 더하는 것은 그 장치들이 그래프에 어떻게 내려앉는가입니다. 그래프는 스키마이고 레이블은 테이블이므로, Cypher 쿼리에 필요한 권한이 짐작한 것과 늘 같지는 않습니다. {#security-authentication} ## 인증 데이터 디렉터리의 `pg_hba.conf`가 누가 어디서 어느 데이터베이스에 어떻게 접속할 수 있는지 정합니다. 규칙은 위에서 아래로 대조하며 먼저 맞는 것이 이깁니다. ``` # TYPE DATABASE USER ADDRESS METHOD local all all peer host mydb appuser 10.0.0.0/24 scram-sha-256 hostssl mydb analyst 0.0.0.0/0 scram-sha-256 host all all 0.0.0.0/0 reject ``` 고친 뒤에는 reload 하십시오: ```shell ag_ctl -D $AGDATA reload ``` 서버가 외부에서 닿을 수 있게 되기 전에 바로잡아야 할 것 셋입니다: **기본 `trust` 규칙을 바꾸십시오.** `initdb`는 로컬 접속에 `trust`를 써 두는데, 이는 셸 계정이 있는 사람이면 누구나 슈퍼유저를 포함해 어떤 롤로도 접속할 수 있다는 뜻입니다. 로컬 유닉스 소켓 접속에는 `peer`를, 네트워크를 지나는 것에는 `scram-sha-256`을 쓰십시오. **`md5`가 아니라 `scram-sha-256`을 쓰십시오.** 비밀번호를 만들거나 바꾸기 전에 `password_encryption = scram-sha-256`을 설정해, 저장되는 검증자가 강한 쪽이 되게 하십시오. **네트워크 접속에는 TLS를 요구하십시오.** 규칙에는 `hostssl`을, `postgresql.conf`에는 `ssl = on`과 인증서·키를 둡니다. 가로채기를 실제로 막는 것은 클라이언트의 `sslmode=verify-full`입니다. `require`는 암호화만 합니다. 쓸 수 있는 방식은 PostgreSQL의 전체 목록 — `peer`·`scram-sha-256`·`cert`·`ldap`·`gss`· `sspi`·`pam`·`radius`·`ident`·`trust`·`reject` — 이며 옵션도 같습니다. [PostgreSQL의 인증 방식 장](https://www.postgresql.org/docs/18/auth-methods.html)을 참고하십시오. 접속이 거부되면 서버 로그가 이유를 말해 주며, 그 메시지는 클라이언트가 받는 것보다 구체적입니다. 규칙을 고치기 전에 그것을 확인하십시오. {#security-roles} ## 롤 롤은 클러스터 전체의 것입니다. 데이터베이스가 아니라 서버에 속합니다. `LOGIN`을 가진 롤이 다른 시스템에서 말하는 사용자입니다. ```sql CREATE ROLE appuser LOGIN PASSWORD 'secret'; CREATE ROLE readonly; -- a group, no LOGIN GRANT readonly TO appuser; ``` 운영상 중요한 속성은 `SUPERUSER`·`CREATEDB`·`CREATEROLE`·`REPLICATION`·`BYPASSRLS`입니다. 애플리케이션 롤에는 그중 무엇도 주지 마십시오. `ALTER ROLE … SET`은 롤에 설정을 고정하는데, `graph_path`를 강제하거나 정비용 롤 말고는 `enable_graph_dml`을 꺼 두는 깔끔한 방법입니다: ```sql ALTER ROLE appuser SET graph_path = moviekb; ALTER ROLE appuser SET enable_graph_dml = off; ``` {#security-permissions-on-a-graph} ## 그래프에 대한 권한 그래프는 스키마이고 각 레이블은 테이블이므로 권한도 평범한 것들입니다. 놀랄 일은 다른 데서 옵니다. Cypher 쿼리는 자기가 이름을 댄 레이블보다 많은 객체에 손을 댑니다. {#security-reading} ### 읽기 읽기에는 그래프 스키마에 대한 `USAGE`와, 손대는 각 레이블에 대한 `SELECT`가 필요합니다. 어느 지점에서 어떤 권한이 필요해지는지 다음 순서로 확인하십시오. 스키마만 준 상태에서 시작합니다: ```sql CREATE ROLE analyst; GRANT USAGE ON SCHEMA moviekb TO analyst; ``` ```psql SET ROLE analyst; ``` 이제 Cypher 읽기가 레이블 이름과 함께 테이블 권한 오류로 실패합니다: ```cypher MATCH (m:movie) RETURN count(m); ``` ``` ERROR: permission denied for table movie ``` 레이블에 권한을 주면 동작합니다: ```psql RESET ROLE; GRANT SELECT ON moviekb.movie TO analyst; SET ROLE analyst; ``` ```cypher MATCH (m:movie) RETURN count(m); ``` ``` count ------- 18 ``` **레이블 없는 패턴에는 `ag_vertex`도 필요합니다.** `MATCH (n)`은 그래프의 부모인 `ag_vertex`와 그 아래의 모든 레이블을 스캔하므로, `movie`는 읽을 수 있지만 `ag_vertex`는 읽지 못하는 롤은 이것을 실행하지 못합니다: ```cypher MATCH (n) RETURN count(n); ``` ``` ERROR: permission denied for table ag_vertex ``` 레이블 없는 간선에 대해서도 `ag_edge`에 같은 것이 적용됩니다. 그러므로 읽기 전용 분석가 롤에는 레이블을 하나씩 주기보다 스키마 전체에 주십시오: ```psql RESET ROLE; ``` ```sql GRANT SELECT ON ALL TABLES IN SCHEMA moviekb TO analyst; ALTER DEFAULT PRIVILEGES IN SCHEMA moviekb GRANT SELECT ON TABLES TO analyst; ``` 다음 달에 만들어질 레이블까지 읽히게 하는 것이 `ALTER DEFAULT PRIVILEGES` 줄입니다. {#security-writing} ### 쓰기 정점이나 간선을 만들려면 레이블에 대한 `INSERT`와 **그 레이블 id 시퀀스에 대한 `USAGE`**가 필요합니다. 두 번째 것을 빠뜨리기 쉽습니다. `INSERT`만 준 경우입니다: ```psql RESET ROLE; ``` ```sql GRANT INSERT ON moviekb.movie TO analyst; ``` ```psql SET ROLE analyst; ``` ```cypher CREATE (:movie {title: 'X'}); ``` ``` ERROR: permission denied for sequence movie_id_seq ``` 시퀀스를 더하면 쓰기가 통과합니다: ```psql RESET ROLE; ``` ```sql GRANT USAGE ON SEQUENCE moviekb.movie_id_seq TO analyst; ``` `SET`과 `REMOVE`에는 레이블에 대한 `UPDATE`가 필요합니다. `DELETE`에는 `DELETE`가 필요합니다. 그리고 `DETACH DELETE`에는 `ag_edge`에 대한 권한이 필요합니다. 지울 간선을 그것으로 찾기 때문입니다: ``` ERROR: permission denied for table ag_edge ``` `ag_edge`나 `ag_vertex`를 가리키는 오류는 행 보안의 결과가 아니라 그래프의 부모 레이블에 대한 권한이 없다는 뜻입니다. 앞의 것으로 읽기 쉬우므로 알아 둘 만합니다. 그래프 전체를 읽고 쓰는 롤에 쓸 만한 권한 묶음입니다: ```sql GRANT USAGE ON SCHEMA moviekb TO appuser; GRANT SELECT, INSERT, UPDATE, DELETE ON ALL TABLES IN SCHEMA moviekb TO appuser; GRANT USAGE ON ALL SEQUENCES IN SCHEMA moviekb TO appuser; ALTER DEFAULT PRIVILEGES IN SCHEMA moviekb GRANT SELECT, INSERT, UPDATE, DELETE ON TABLES TO appuser; ALTER DEFAULT PRIVILEGES IN SCHEMA moviekb GRANT USAGE ON SEQUENCES TO appuser; ``` {#security-creating-labels} ### 레이블 만들기 레이블을 만들려면 그래프 스키마에 대한 `CREATE`가 필요합니다. 그래프를 만들려면 데이터베이스에 대한 `CREATE`가 필요합니다. {#security-row-level-security} ## 행 수준 보안 행 수준 보안은 레이블에서 동작하므로, 정책으로 어떤 롤이 어떤 정점이나 간선을 보고 쓰는지 제한할 수 있습니다: ```sql ALTER TABLE moviekb.movie ENABLE ROW LEVEL SECURITY; CREATE POLICY movie_visible ON moviekb.movie FOR SELECT TO analyst USING ((properties->>'genre') = 'Sci-Fi'); ``` ```{warning} **2.17에서 쓰던 RLS 정책은 다시 시험하십시오.** 2.18 이전에는 그래프 쓰기에 정책이 제대로 적용되지 않았습니다. `UPDATE`나 `DELETE` 정책의 `USING` 절이 결코 스캔되지 않는 릴레이션에 붙어 있어 아무것도 거르지 못했고, `DELETE` 정책이 아예 없는 롤이 행을 지울 수 있었습니다. `INSERT` 정책은 엉뚱한 행을 대상으로 검사됐고, 간선 생성은 아예 검사되지 않아 행 보안이 걸린 간선 레이블이 모든 삽입을 받아들였습니다. 2.18은 그 전부를 적용합니다. 그것이 올바른 동작이며, 지금 애플리케이션이 하고 있는 쓰기가 거부되기 시작할 수 있다는 뜻입니다. 업그레이드한 뒤가 아니라 전에 시험하십시오. [릴리스 노트](#218-stricter-validation)를 참고하십시오. ``` 실무에서 알아 둘 것 둘입니다: * 정책 표현식은 레이블의 컬럼을 읽으므로 `properties`에서 동작하고, [승격된 컬럼](../querying/typed-columns.md)에서도 동작합니다. 뒤쪽이 더 빠르고 정책이 인덱스를 쓸 수 있게 합니다. * `BYPASSRLS`와 테이블 소유권은 둘 다 정책을 건너뜁니다. 애플리케이션 롤은 둘 다 가져서는 안 됩니다. {#security-two-settings-that-are-part-of-the-security-posture} ## 보안 태세의 일부인 설정 둘 `enable_graph_dml`과 `enable_graph_ddl`은 기본으로 꺼져 있으며, Cypher가 아니라 SQL로 레이블에 쓰는 것과 레이블의 모양을 바꾸는 것을 막습니다. 꺼 두면 애플리케이션이 Cypher 경로에 머무르고, 그래프 자신의 검사 — 이를테면 간선의 양 끝점이 있는지 — 가 그대로 돕니다. 다만 이 설정이 그래프 정합성의 전부는 아니며, 그렇게 읽어서는 안 됩니다. `COPY`는 두 설정을 보지 않고 레이블에 씁니다. 설정과 무관하게 모든 경로에서 지켜지는 것은 행의 id가 그 행을 담은 레이블을 가리킨다는 것입니다. 이를 깨뜨리는 쓰기는 Cypher든 `INSERT`든 `UPDATE`든 `COPY`든 복제 반영이든 거부됩니다. 정비 작업 때 켰다가 다시 끄거나, `ALTER ROLE … SET`으로 롤마다 꺼 두십시오. `cypher_allow_unsafe_ddl`도 마찬가지입니다. [서버 설정](../reference/guc.md)을 참고하십시오. {#security-encryption-at-rest} ## 저장 데이터 암호화 AgensGraph는 데이터 파일 자체를 암호화하지 않습니다. 파일시스템이나 블록 장치 암호화를 쓰거나, 투명 데이터 암호화가 요구되는 곳에는 [Agens TDE](https://tech.skaiworldwide.com/docs/en/agens-tde/16/)를 쓰십시오. 컬럼 수준 암호화는 `pgcrypto`가 다루며, 속성은 평범한 `jsonb` 값이므로 다른 컬럼과 마찬가지로 `pgcrypto` 암호문을 담을 수 있습니다.