创建和配置数据库本地角色
内置角色是全局的,并适用于所有数据库
一个常见的错误假设是角色可以分配给数据库上的用户,例如将读者角色分配给数据库 db1 上的用户 user_a。但角色和它们适用的数据库彼此之间并不独立。每个角色不仅包含其权限,还包含它具有访问权限的数据库。权限本身可以限定为特定数据库。
因此,内置角色适用的数据库已经设置好并且是不可变的:它们包括全局数据库访问,并且它们的权限适用于过去、现在和将来所有数据库。授予读者角色的用户是将来在该 dbms 上创建的每个数据库的读者。
其他内置角色也是如此。它们并不适合在本地数据库级别使用。
在谈到每个数据库的访问和角色时,最好考虑权限,而不是内置角色。因此,不要考虑将读者角色授予数据库 db1 上的用户 user_a,而是考虑创建一个在新角色上具有读取权限和访问权限的角色,并在 db1 上授予该角色。
我们可以复制内置角色并调整其数据库访问权限
我们可以使用内置角色作为模板,而不必从头开始创建新角色,因为我们只需要一个限定到特定数据库或数据库的内置角色。
我们可以将现有角色复制为新角色。然后,我们可以撤销全局数据库访问权限,然后授予该角色应具有访问权限的数据库或数据库的访问权限。
因此,要创建等效的读者角色,但要针对数据库 db1,并将它授予用户 user_a,我们可以从系统数据库执行以下操作
CREATE ROLE db1_reader AS COPY OF reader;
REVOKE GRANT ACCESS ON DATABASES * FROM db1_reader;
GRANT ACCESS ON DATABASE db1 TO db1_reader;
GRANT ROLE db1_reader TO user_a;
当然,user_a 和数据库 db1 必须首先存在,才能使此操作成功。
这授予了等效于读者角色的权限,但将用户的访问权限限制在数据库 db1。
请注意,来自多个角色的权限可以组合
重要的是要注意,db1_reader 角色实际上并没有限定到 db1 的读取权限。它们仍然在所有数据库上拥有完全的读取权限(如从内置读者角色复制的那样),只是目前,它们的角色只允许访问 db1。我们只是撤销了来自所有数据库的 ACCESS,而不是 READ 权限。
如果用户被授予了另一个角色,该角色授予了对不同数据库的访问权限,并且没有以某种方式限制其权限,那么 db1_reader 角色中固有的全局读取权限将使他们能够读取新数据库上的所有内容。
让我们通过添加一个新角色 db2_accessor 并将其授予用户 user_a 来说明这一点
CREATE ROLE db2_accessor;
GRANT ACCESS ON DATABASE db2 TO db2_accessor;
GRANT ROLE db2_accessor TO user_a;
即使 db2_accessor 角色只是提供了对数据库的访问权限,没有读取、写入或其他任何权限,由于来自 db1_reader 的全局读取权限,用户 user_a 可以读取 db2 上的所有内容。
让我们检查 user_a 的权限以进行验证
SHOW USER user_a PRIVILEGES;
╒═════════╤══════════╤════════════════╤═══════╤═════════════════╤══════════════╤════════╕ │"access" │"action" │"resource" │"graph"│"segment" │"role" │"user" │ ╞═════════╪══════════╪════════════════╪═══════╪═════════════════╪══════════════╪════════╡ │"GRANTED"│"read" │"all_properties"│"*" │"NODE(*)" │"db1_reader" │"user_a"│ ├─────────┼──────────┼────────────────┼───────┼─────────────────┼──────────────┼────────┤ │"GRANTED"│"traverse"│"graph" │"*" │"NODE(*)" │"db1_reader" │"user_a"│ ├─────────┼──────────┼────────────────┼───────┼─────────────────┼──────────────┼────────┤ │"GRANTED"│"read" │"all_properties"│"*" │"RELATIONSHIP(*)"│"db1_reader" │"user_a"│ ├─────────┼──────────┼────────────────┼───────┼─────────────────┼──────────────┼────────┤ │"GRANTED"│"traverse"│"graph" │"*" │"RELATIONSHIP(*)"│"db1_reader" │"user_a"│ ├─────────┼──────────┼────────────────┼───────┼─────────────────┼──────────────┼────────┤ │"GRANTED"│"access" │"database" │"db1" │"database" │"db1_reader" │"user_a"│ ├─────────┼──────────┼────────────────┼───────┼─────────────────┼──────────────┼────────┤ │"GRANTED"│"access" │"database" │"db2" │"database" │"db2_accessor"│"user_a"│ └─────────┴──────────┴────────────────┴───────┴─────────────────┴──────────────┴────────┘
我们可以使用 DENY 来屏蔽权限
权限组合的能力不一定是障碍。有时它可能非常有用。
例如,如果我们对拥有这种组合的读取访问权限感到满意,但我们希望确保无论使用哪个数据库,该用户都无法读取或匹配 :Person 节点上的 SSN 属性。我们可以为这种限制添加一个特殊角色。
CREATE ROLE ssn_blind;
DENY MATCH {ssn, SSN} ON GRAPH * NODES Person TO ssn_blind;
GRANT ROLE ssn_blind TO user_a;
狭义限定权限可使权限更易于预测
如果我们想要最严格的安全性,则需要对权限进行限定,以便授予新角色(以及访问新数据库)不会意外地授予广泛的权限,那么我们需要放弃在创建新角色时复制内置角色的想法。它们的权限是数据库范围的,这可能对我们的需求来说过于宽泛。
相反,我们需要手动授予权限,并将它们限定到相关的数据库或数据库。
让我们删除 db1_reader 角色,并使用更狭义限定的权限重新创建它
CREATE OR REPLACE ROLE db1_reader;
GRANT ACCESS ON DATABASE db1 TO db1_reader;
GRANT MATCH {*} ON GRAPH db1 to db1_reader;
GRANT ROLE db1_reader TO user_a;
The https://neo4j.ac.cn/docs/cypher-manual/current/access-control/manage-privileges/#access-control-graph-privileges[MATCH 权限] 是 READ 和 TRAVERSE 权限的简写,因此这为我们节省了一行。
现在让我们再次检查 user_a 的权限
SHOW USER user_a PRIVILEGES;
╒═════════╤══════════╤════════════════╤═══════╤═════════════════╤══════════════╤════════╕ │"access" │"action" │"resource" │"graph"│"segment" │"role" │"user" │ ╞═════════╪══════════╪════════════════╪═══════╪═════════════════╪══════════════╪════════╡ │"GRANTED"│"read" │"all_properties"│"db1" │"NODE(*)" │"db1_reader" │"user_a"│ ├─────────┼──────────┼────────────────┼───────┼─────────────────┼──────────────┼────────┤ │"GRANTED"│"traverse"│"graph" │"db1" │"NODE(*)" │"db1_reader" │"user_a"│ ├─────────┼──────────┼────────────────┼───────┼─────────────────┼──────────────┼────────┤ │"GRANTED"│"read" │"all_properties"│"db1" │"RELATIONSHIP(*)"│"db1_reader" │"user_a"│ ├─────────┼──────────┼────────────────┼───────┼─────────────────┼──────────────┼────────┤ │"GRANTED"│"traverse"│"graph" │"db1" │"RELATIONSHIP(*)"│"db1_reader" │"user_a"│ ├─────────┼──────────┼────────────────┼───────┼─────────────────┼──────────────┼────────┤ │"GRANTED"│"access" │"database" │"db1" │"database" │"db1_reader" │"user_a"│ ├─────────┼──────────┼────────────────┼───────┼─────────────────┼──────────────┼────────┤ │"GRANTED"│"access" │"database" │"db2" │"database" │"db2_accessor"│"user_a"│ ├─────────┼──────────┼────────────────┼───────┼─────────────────┼──────────────┼────────┤ │"DENIED" │"read" │"property(SSN)" │"*" │"NODE(Person)" │"ssn_blind" │"user_a"│ ├─────────┼──────────┼────────────────┼───────┼─────────────────┼──────────────┼────────┤ │"DENIED" │"read" │"property(ssn)" │"*" │"NODE(Person)" │"ssn_blind" │"user_a"│ └─────────┴──────────┴────────────────┴───────┴─────────────────┴──────────────┴────────┘
我们可以看到,尽管 user_a 具有对 db1 和 db2 数据库的访问权限,但我们授予 db1_reader 的读取和遍历权限仅限定到 db1。用户 user_a 可以访问 db2,但实际上无法执行任何操作,除非我们向其现有角色之一授予更多权限,或者通过新角色授予权限。
此页面是否有帮助?