« Oracle 12c 多租户:PDB 支持 abort 关闭么? | Blog首页 | Oracle 12c:多租户数据库克隆 ORA-01276 错误处理一例 »
Oracle 12c多租户新特性:Common用户和Local用户的管理
链接:https://www.eygle.com/archives/2016/12/oracle_12c_user_common.html
编辑手记:这一节我们将介绍多租户架构中用户及权限的变化,全局用户和本地用户,管理方式和内部实现,这篇文章来自<深入解析Oracle>一书的摘录。云和恩墨 的很多客户已经采用多租户特性进行生产部署,这一技术早已经走入实践。
无论在CDB和Non-CDB数据库中,用户都拥有一个Schema,拥有一系列的Schema对象,在CDB中由于PDB的引入,用户范畴有所不同。
在CDB模式下,公用用户(Common User)和本地用户(Local User)两个概念被引入进来,公用用户可以在CDB和PDB中同时存在,能够连接ROOT和PDB进行操作;而本地用户则只在特定的PDB中存在,也只能在特定的PDB中执行操作;在PDB中不能创建公用用户,而在CDB中(CDB$ROOT中)同样不能创建本地用户。
在CDB中创建的公用用户要求以c##或C## 开头,以下测试以常规方式命名的用户将会创建失败,符合规则的用户可以被创建:
SQL> select banner from v$version; BANNER -------------------------------------------------------------------------------- Oracle Database 12c Enterprise Edition Release 12.1.0.1.0 - 64bit Production SQL> create user eygle identified by eygle; create user eygle identified by eygle * 第 1 行出现错误: ORA-65096: 公用用户名或角色名无效 SQL> create user c##eygle identified by eygle; 用户已创建。
当创建公用用户时,Oracle会向每个PDB中同时创建该用户,如果PDB未打开,则创建工作会以任务的方式延后。
以下查询显示数据库中只在容器1中存在新创建的用户:
SQL> select username,common,con_id from cdb_users where username like '%EYGLE%'; USERNAME COM CON_ID ------------------------------ --- ---------- C##EYGLE YES 1
此时打开PDB,则数据库会自动完成之前挂起的内部创建工作:
SQL> alter pluggable database enmo open; 插接式数据库已变更。 SQL> select username,common,con_id from cdb_users where username like '%EYGLE%'; USERNAME COM CON_ID ------------------------------ --- ---------- C##EYGLE YES 1 C##EYGLE YES 3 SQL> drop user c##eygle; 用户已删除。
下图描述了公用用户和本地用户的区别:
在拥有了CREATE SESSION权限后,公用用户能够登陆包括Root在内的任何Container。公用用户一般在每个PDB中都存在对应的用户信息,在PDB中不能存在与公用用户重名的用户,如初始的SYS和SYSTEM用户都属于公用用户。也只有公用用户能够授权或被授权相应的公用角色和权限。
公用权限是指对所有Container都有效的系统或者对象权限,例如一个公用用户被授予了公用权限 CREATE ANY TABLE WITH ADMIN OPTION 可以将这个权限转授给其他公用用户.公用用户之外的权限被称为本地权限(Local Privilege).
公用角色是指在所有Container中都可见的角色,这些角色可能包含全局和本地权限。本地角色只能包含本地权限。授予公用角色的公用权限,对于具有该角色的用户在任何可以连接的Container中都将具有该权限。
以下是一些相关的常识性介绍:
- 一个公用用户在不同Container中的Schema可以不同;
- 本地用户只能在各自的PDB中进行操作,在不同PDB中可以存在同名的本地用户;
- PDB中的本地用户不能登陆其他PDB或ROOT;
- PDB的本地用户只需要在本PDB内保持用户名唯一;
- 本地用户能否访问一个公用Schema中的对象取决于其拥有的具体权限;
- PDB能够通过DB Link访问其他的PDB;
在CDB、PDB模式下,一个权限在被授权的Container中存在。因此,在PDB中授予的本地权限和角色和在Non-CDB中没有不同,例如,在PDB HRPDB中授予本地用户HR的 SELECT ANY TABLE权限,仅在该PDB中生效。
相对而言,公用权限和角色可以跨越Container生效,当需要跨Container进行操作时,需要公用权限或角色,并且这些权限需要在现有和将来创建的Container中生效。
在CDB中,每个权限或者是在某个Container中的本地权限,或者是在所有Container中生效的公用权限。公用权限确保公用用户无需在不同PDB中重复授权。
类似CREATE ANY TABLE的权限,其自身既不是公用权限也不是本地权限,如果一个用户通过CONTAINER=CURRENT方式授权,则被授权用户拥有的是本地权限;如果一个权限通过CONTAINER=ALL方式授权,则用户获得的是公用权限。因此,一个权限称其为本地或公用权限,完全依赖于其授权方式。
在CDB中,每个角色或者是基于PDB的本地角色,或者是对全体PDB生效的公用角色,所有系统提供的角色(如DBA)都属于公用角色。
在视图DBA_USERS和CDB_USERS中都包含了一个字段COMMON,用于标识公用用户和本地用户。
SQL> select username,common from dba_users; USERNAME COM ------------------------------ --- AUDSYS YES SYSKM YES XS$NULL YES XDB YES WMSYS YES DBSNMP YES SYSDG YES SYSBACKUP YES SYS YES SYSTEM YES
以下查询显示SYSTEM作为公用用户在四个容器中存在:
SQL> select username,common,con_id from cdb_users where username='SYSTEM'; USERNAME COM CON_ID ------------------------------ --- ---------- SYSTEM YES 1 SYSTEM YES 2 SYSTEM YES 3 SYSTEM YES 4
数据库中存在17个公用用户:
SQL> select count(distinct username) from cdb_users where common='YES'; COUNT(DISTINCTUSERNAME) ----------------------- 17
以下查询列出了数据库中的本地用户:
SQL> select username,con_id from cdb_users where common='NO'; USERNAME CON_ID ------------------------------ ---------- ENMO 3 EYGLE 3 JULIA 3 ENMO 4 EYGLE 4 JULIA 4
通过指定CONTAINER可以限定创建用户的类型,当使用ALL选项时,以下命令就创建了一个名为APPADMIN的公用用户:
SQL> create user c##admin identified by appadmin container=ALL; User created. SQL> select username,common,con_id from cdb_users where username='C##ADMIN'; USERNAME COM CON_ID ------------------------------ --- ---------- C##ADMIN YES 1 C##ADMIN YES 3 C##ADMIN YES 4
查询dba_users视图,可以看到APPADMIN的相关用户属性:
SQL> select username,common from dba_users where username='C##ADMIN'; USERNAME COM ------------------------------ --- C##ADMIN YES
注意,在CDB$ROOT中不能创建本地用户或角色:
SQL> create user appdba identified by appdba container=CURRENT; create user appdba identified by appdba container=CURRENT * 第 1 行出现错误: RA-65049: 不允许在 CDB$ROOT 中创建本地用户或角色
在PDB中才可以创建本地用户,以下测试首先连接到PDB(名称为ENMO)中,连接用户具备DBA权限可以创建用户:
SQL> connect eygle/eygle@enmo Connected. SQL> show con_id con_name CON_ID ------------------------------ 3 CON_NAME ------------------------------ ENMO
当然在PDB中也不允许创建公用用户:
SQL> create user appdba identified by appdba container=ALL; create user appdba identified by appdba container=ALL * 第 1 行出现错误: ORA-65050: 只允许在 CDB$ROOT 中执行公用 DDL 同样在PDB中也不能删除公用用户:
SQL> drop user c##eygle; drop user c##eygle * 第 1 行出现错误: ORA-65050: 只允许在 CDB$ROOT 中执行公用 DDL
以下SQL成功在PDB下创建了本地用户:
SQL> create user appdba identified by appdba container=CURRENT; User created. SQL> select username,common,con_id from cdb_users where username='APPDBA'; USERNAME COM CON_ID ------------------------------ --- ---------- APPDBA NO 3
类似的,本地用户不能被授予公用权限或角色,以下尝试在全局授权的命令会返回明确的错误:
SQL> select username,common from dba_users where username='APPDBA'; USERNAME COM ------------------------------ --- APPDBA NO SQL> grant create session to appdba container=ALL; grant create session to appdba container=ALL * 第 1 行出现错误: ORA-65030: 用户无法向本地用户或角色授予公用权限
在PDB内授予本地权限之后,新创建的用户可以登陆本地PDB数据库:
SQL> grant create session to appdba ; Grant succeeded. SQL> connect appdba/appdba@enmo Connected. SQL> show con_id con_name CON_ID ------------------------------ 3 CON_NAME ------------------------------ ENMO
下面来研究一下角色。在CDB_ROLES视图可以查询CDB的角色信息,以下查询可以看到由于PDB的引入,角色记录大大增加:
SQL> select count(distinct role),count(*) from cdb_roles; COUNT(DISTINCTROLE) COUNT(*) ------------------- ---------- 44 174
对于DBA公用角色来说,在每个Container中都存在相应的信息记录:
SQL> select role,common,con_id from cdb_roles where role='DBA'; ROLE COM CON_ID ------------------------------ --- ---------- DBA YES 1 DBA YES 2 DBA YES 3 DBA YES 4
而对于PDB_DBA角色,仅在PDB中存在:
SQL> select role,common,con_id from cdb_roles where role='PDB_DBA'; ROLE COM CON_ID ------------------------------ --- ---------- PDB_DBA NO 3 PDB_DBA NO 4 SQL> select con_id,name from v$pdbs; CON_ID NAME ---------- ------------------------------ 2 PDB$SEED 3 ENMO 4 YUNH
同用户管理类似,在CDB$ROOT中可以建立公用角色,但是不能创建本地角色,公用角色在每个PDB中都存在,同样需要以c##为前缀开头:
SQL> show con_id con_name CON_ID ------------------------------ 1 CON_NAME ------------------------------ CDB$ROOT SQL> create role APPROLE container=ALL; create role APPROLE container=ALL * 第 1 行出现错误: ORA-65096: 公用用户名或角色名无效 SQL> create role C##ROLE container=ALL; 角色已创建。 SQL> select role,common,con_id from cdb_roles where role='C##ROLE'; ROLE COM CON_ID ------------------------------ --- ---------- C##ROLE YES 1 C##ROLE YES 3 C##ROLE YES 4 SQL> create role APPADMIN container=CURRENT; create role APPADMIN container=CURRENT * 第 1 行出现错误: ORA-65049: 不允许在 CDB$ROOT 中创建本地用户或角色
在PDB中,同样不能创建公用角色,仅能创建本地角色:
SQL> connect sys/oracle@enmo as sysdba Connected. SQL> select count(role) from dba_roles; COUNT(ROLE) ----------- 45 SQL> create role COMMON_ROLE container=ALL; create role COMMON_ROLE container=ALL * ERROR at line 1: ORA-65050: Common DDLs only allowed in CDB$ROOT SQL> create role APPENMO container=CURRENT; Role created. SQL> select role,common from dba_roles where role='APPENMO'; ROLE COM ------------------------------ --- APPENMO NO SQL> select count(role) from dba_roles; COUNT(ROLE) ----------- 46
对于系统权限和对象权限,CDB相应的增加了对应视图用于存储这些信息:
SQL> connect / as sysdba Connected. SQL> desc system_privilege_map Name Null? Type ----------------------------------------- -------- ---------------------------- PRIVILEGE NOT NULL NUMBER NAME NOT NULL VARCHAR2(40) PROPERTY NOT NULL NUMBER SQL> desc table_privilege_map Name Null? Type ----------------------------------------- -------- ---------------------------- PRIVILEGE NOT NULL NUMBER NAME NOT NULL VARCHAR2(40) SQL> desc cdb_sys_privs Name Null? Type ----------------------------------------- -------- ---------------------------- GRANTEE VARCHAR2(128) PRIVILEGE VARCHAR2(40) ADMIN_OPTION VARCHAR2(3) COMMON VARCHAR2(3) CON_ID NUMBER SQL> desc cdb_tab_privs Name Null? Type ----------------------------------------- -------- ---------------------------- GRANTEE VARCHAR2(128) OWNER VARCHAR2(128) TABLE_NAME VARCHAR2(128) GRANTOR VARCHAR2(128) PRIVILEGE VARCHAR2(40) GRANTABLE VARCHAR2(3) HIERARCHY VARCHAR2(3) COMMON VARCHAR2(3) TYPE VARCHAR2(24) CON_ID NUMBER
在CDB中可以像在NON-CDB的数据库中一样进行权限授予与回收:
SQL> connect sys/oracle@enmo as sysdba Connected. SQL> select grantee,privilege,common,con_id from cdb_sys_privs where grantee='APPDBA'; GRANTEE PRIVILEGE COM CON_ID -------------------- ---------------------------------------- --- ---------- APPDBA CREATE SESSION NO 3 SQL> grant create table to appdba; Grant succeeded. SQL> select grantee,privilege,common,con_id from cdb_sys_privs where grantee='APPDBA'; GRANTEE PRIVILEGE COM CON_ID -------------------- ---------------------------------------- --- ---------- APPDBA CREATE TABLE NO 3 APPDBA CREATE SESSION NO 3 SQL> revoke create table from appdba; Revoke succeeded. SQL> select grantee,privilege,common,con_id from cdb_sys_privs where grantee='APPDBA'; GRANTEE PRIVILEGE COM CON_ID -------------------- ---------------------------------------- --- ---------- APPDBA CREATE SESSION NO 3
欢迎加入『云和恩墨大讲堂』,参与我们的学习和讨论。
历史上的今天...
>> 2011-12-02文章:
>> 2007-12-02文章:
>> 2006-12-02文章:
>> 2005-12-02文章:
By eygle on 2016-12-02 18:23 | Comments (0) | Oracle12c/11g | 3219 |