DBAs auf PDB-Ebene einrichten
Im heutigen Blog geht es mal wieder um Multitenant, und um Security. Seit der Einführung von Multitenant und Pluggable Databases gibt es auch eine Art neuen Datenbanknutzer, den PDBADMIN. Genau der wird das Thema sein. Die Idee hinter diesem Nutzer ist, dass jede PDB einen eigenen Administrator haben soll, der diese PDB verwaltet. Wird eine neue leere PDB angelegt, muss zwingend dieser Benutzer definiert werden, wie man der Dokumentation entnehmen kann.
Wie zu sehen, können dem Administrator noch Rollen zugewiesen werden. Dieser Teil ist jedoch optional.
Wie genau funktioniert das nun aber? Die Dokumentation bringt auch da Licht ins Dunkle.
Heißt also, der Administratornutzer wird in der PDB angelegt und erhält immer die PDB_DBA Rolle zugewiesen.
An der Stelle muss noch erwähnt werden, dass man nicht immer einen PDB-Admin-Nutzer haben muss. Wird die PDB durch ein Cloning oder Plug einer non-CDB erstellt, dann existiert kein solcher Nutzer. Man kann bzw. sollte diesen dann aber im Zuge der Migration mit anlegen und ihm die PDB_DBA-Rolle geben.
Was hat der Nutzer dann am Ende also nun für Berechtigungen, wenn man sonst keine weiteren Rollen angibt?
SQL> create pluggable database ORCL12PDB3 admin user pdbadmin identified by "********";
Pluggable database created.
SQL> alter pluggable database ORCL12PDB3 open;
Pluggable database altered.
SQL> connect pdbadmin/********@vm160/orcl12pdb3.support.robotron.de
Connected.
SQL> select * from session_roles;
ROLE
--------------------------------------------------------------------------------
PDB_DBA
SQL> select * from session_privs;
PRIVILEGE
----------------------------------------
SET CONTAINER
CREATE PLUGGABLE DATABASE
CREATE SESSION
Im Grunde darf der PDBADMIN also praktisch nichts außer sich an der PDB anzumelden. Wir können dem Nutzer also an der Stelle nur nachträglich weitere Rechte geben in dem wir die nötigen Rechte entweder direkt an den Benutzer oder die Rolle PDB_ADMIN granten.
Besser ist es also, direkt beim Anlegen einer PDB die benötigten Rollen festzulegen. Es können eine oder auch mehrere Rollen angegeben werden, nicht aber Systemprivilegien. Diese müssen im Nachgang feingranular vergeben werden.
SQL> create pluggable database orcl12pdb2 admin user pdbadmin identified by "********" roles=(CONNECT, RESOURCE);
Pluggable database created.
SQL> alter pluggable database orcl12pdb2 open;
Pluggable database altered.
SQL> connect pdbadmin/********@vm160/orcl12pdb2.support.robotron.de
Connected.
SQL> select * from session_roles;
ROLE
--------------------------------------------------------------------------------
CONNECT
RESOURCE
PDB_DBA
SODA_APP
SQL> select * from session_privs;
PRIVILEGE
----------------------------------------
CREATE SESSION
CREATE TABLE
CREATE CLUSTER
CREATE SEQUENCE
CREATE PROCEDURE
CREATE TRIGGER
CREATE TYPE
CREATE OPERATOR
CREATE INDEXTYPE
CREATE PLUGGABLE DATABASE
SET CONTAINER
11 rows selected.
Soll der PDBADMIN ein richtiger DBA werden, dann geben wir ihm natürlich die DBA-Rolle. Damit sollte der Nutzer dann vollumfänglich mit Rechten ausgestattet sein.
SQL> create pluggable database orcl12pdb1 admin user pdbadmin identified by "********" roles=(DBA);
Pluggable database created.
SQL> alter pluggable database orcl12pdb1 open;
Pluggable database altered.
SQL> connect pdbadmin/********@vm160/orcl12pdb1.support.robotron.de
Connected.
SQL> select * from session_roles;
ROLE
--------------------------------------------------------------------------------
DBA
PDB_DBA
SELECT_CATALOG_ROLE
EXECUTE_CATALOG_ROLE
CAPTURE_ADMIN
EXP_FULL_DATABASE
IMP_FULL_DATABASE
DATAPUMP_EXP_FULL_DATABASE
DATAPUMP_IMP_FULL_DATABASE
GATHER_SYSTEM_STATISTICS
OPTIMIZER_PROCESSING_RATE
EM_EXPRESS_BASIC
EM_EXPRESS_ALL
SCHEDULER_ADMIN
HS_ADMIN_SELECT_ROLE
HS_ADMIN_EXECUTE_ROLE
XDBADMIN
XDB_SET_INVOKER
WM_ADMIN_ROLE
JAVA_ADMIN
JAVA_DEPLOY
OLAP_XS_ADMIN
OLAP_DBA
23 rows selected.
SQL> select count(*) from session_privs;
COUNT(*)
----------
238
Einzige Einschränkung hierbei ist die Tatsache, dass der PDBADMIN sich eher wie SYSTEM in non-CDB Datenbanken verhält. Er ist eben nicht SYS und darf daher auch keine Rechte auf SYS-Objekte an andere Nutzer weitergeben, obwohl er "GRANT ANY" Privilegien besitzt.
SQL> show user
USER is "PDBADMIN"
SQL> select * from session_privs where privilege like 'GRANT%';
PRIVILEGE
----------------------------------------
GRANT ANY ROLE
GRANT ANY PRIVILEGE
GRANT ANY OBJECT PRIVILEGE
SQL> grant execute on sys.dbms_lock to test;
grant execute on sys.dbms_lock to test
*
ERROR at line 1:
ORA-01031: insufficient privileges
SQL> grant select on sys.v_$session to test;
grant select on sys.v_$session to test
*
ERROR at line 1:
ORA-01031: insufficient privileges
An dieser Stelle kommt man also nicht umhin, den SYS-Benutzer zu bemühen, um die Rechte zu vergeben. Man kann die Rechte beispielsweise an den PDBADMIN geben und die Weitergabe an andere Nutzer erlauben.
SQL> conn / as sysdba
Connected.
SQL> alter session set container=orcl12pdb1;
Session altered.
SQL> grant select on sys.v_$session to pdbadmin with grant option;
Grant succeeded.
SQL> grant execute on dbms_lock to pdbadmin with grant option;
Grant succeeded.
SQL> connect pdbadmin/********@vm160/orcl12pdb1.support.robotron.de
Connected.
SQL> grant execute on dbms_lock to test;
Grant succeeded.
SQL> grant select on sys.v_$session to test;
Grant succeeded.
Nur Objekte im SYS-Schema darf man mit dem PDBADMIN nach wie vor nicht anlegen. Manchmal braucht man das aber, z.B. für eine Password Verify Function, die im SYS-Schema liegen soll damit das Profile Zugriff darauf hat. Aber muss die Funktion tatsächlich im SYS-Schema liegen?
SQL> show user
USER is "PDBADMIN"
SQL> REM password verify function von Oracle im Schema PDBADMIN anlegen
SQL> @?/rdbms/admin/catpvf
SQL> create profile RDS_PROFILE limit password_verify_function ORA12C_STIG_VERIFY_FUNCTION;
Profile created.
SQL> alter user test profile RDS_PROFILE;
User altered.
SQL> connect test/test@vm160/orcl12pdb1.support.robotron.de
Connected.
SQL> alter user test identified by "Test" replace "test";
alter user test identified by "Test" replace "test"
*
ERROR at line 1:
ORA-28003: password verification for the specified password failed
ORA-20001: Password length less than 15
SQL> alter user test identified by "G4nz_K0mpliziert!" replace "test";
User altered.
Offenbar funktioniert die Password Verify Function auch, wenn sie nich im SYS-Schema ist. Damit ist dieses Security Feature auch ohne Verwendung von SYS nutzbar.
Am Ende kann man den PDBADMIN recht gut mit Rechten ausstatten um die täglichen administrativen Arbeiten in einer PDB zu übernehmen. Lediglich das Granten von Rechten auf SYS-Objekte wie Views oder Packages bleibt ein Thema. Hier wird zumindest zum initialen Setup der echte SYS-Nutzer benötigt. Das sollte in den meisten Fällen kein Problem sein, es sei denn, man hat keinen Zugriff darauf wie beispielsweise in der Autonomous Database in der Oracle Cloud. Dort erhält man nur einen PDBADMIN mit doch recht weitreichenden Berechtigungen. Hat Oracle daran gedacht?
SQL> show user
USER is "ADMIN"
SQL> show con_name
CON_NAME
------------------------------
PPA2OTADQX9XMML_MMIATP
SQL> select host_name from v$instance;
HOST_NAME
----------------------------------------------------------------
SQL> select owner, privilege, count(*) anz from dba_tab_privs where grantable='YES' and grantee=user group by owner, privilege
2 order by 1,2;
OWNER PRIVILEGE ANZ
-------------------- ---------------------------------------- ----------
AUDSYS EXECUTE 1
AUDSYS READ 8
C##ADP$SERVICE EXECUTE 6
C##ADP$SERVICE READ 17
C##ADP$SERVICE UNDER 1
C##CLOUD$SERVICE EXECUTE 11168
C##CLOUD$SERVICE READ 33
C##CLOUD$SERVICE SELECT 17
CTXSYS EXECUTE 10
CTXSYS READ 4
CTXSYS SELECT 1
DVSYS SELECT 1
GSMADMIN_INTERNAL EXECUTE 15
GSMADMIN_INTERNAL READ 3
LBACSYS EXECUTE 35
LBACSYS READ 19
LBACSYS SELECT 38
MDSYS SELECT 1
OUTLN SELECT 3
SYS EXECUTE 1313
SYS FLASHBACK 14
SYS READ 1695
SYS SELECT 4718
SYS USE 1
SYS WRITE 2
SYSTEM READ 1
SYSTEM SELECT 8
XDB DELETE 4
XDB EXECUTE 13
XDB INSERT 4
XDB READ 1
XDB SELECT 5
XDB UPDATE 3
33 rows selected.
SQL> create user test identified by "G4nz_K0mpliziert!";
User created.
SQL> grant create session to test;
Grant succeeded.
SQL> grant execute on dbms_lock to test;
Grant succeeded.
SQL> grant select on v$session to test;
Grant succeeded.
SQL> conn test/"G4nz_K0mpliziert!"@mmiatp_high
Connected.
SQL> show user
USER is "TEST"
SQL> show con_name
CON_NAME
------------------------------
PPA2OTADQX9XMML_MMIATP
SQL> select sid, username from v$session;
SID USERNAME
---------- --------------------
10457 TEST
SQL> set timing on
SQL> exec dbms_lock.sleep(10);
PL/SQL procedure successfully completed.
Elapsed: 00:00:10.04
Offenbar ja, den der ADMIN Benutzer in der PDB meiner Autonomous Database hat ganz offenbar zahlreiche Objektberechtigungen, die er auch weitergeben darf. Inwiefern die dann nützlich sind, ist ein anderes Thema, wie man an der Beispielabfrage auf V$SESSION sieht.
Fazit: Man kann die Berechtiungen innerhalb der PDB recht gut steuern und einstellen, muss sich aber des Themas SYS-Objekt-Berechtigungen bewusst sein. Aber auch dieses Thema ist lösbar. Weiterhin sollte bei der Migration von non-CDBs immer direkt ein PDBADMIN-Nutzer eingerichtet werden um später darauf zurückgreifen zu können.
Update 09.12.2022
Heute gibt es noch ein Update zu dem oben beschriebenen Vorgehen. Unsere Kollegin Berit Richert hat das Thema Password Verify Function nochmals näher beleuchtet. Dabei hat sich herausgestellt, dass die verwendete Funktion ORA12C_STIG_VERIFY_FUNCTION bereits initial mit vorhanden ist. Daher kann man auch ein Profile mit dieser Funktion erstellen. Selbst definierte Password Verify Functions müssen aber im SYS-Schema liegen, das sagt auch die Dokumentation:
PASSWORD_VERIFY_FUNCTION
You can pass a PL/SQL password complexity verification script as an argument to CREATE PROFILE by specifying PASSWORD_VERIFY_FUNCTION. Oracle Database provides a default script, but you can write your own function or use third-party software instead.
For function, specify the name of the password complexity verification routine. The function must exist in the SYS schema and you must have EXECUTE privilege on the function.
Specify NULL to indicate that no password verification is performed.
Da führt auch leider kein Weg daran vorbei. Auch mit einem Public Synonym kann man das nicht umgehen, wir haben es getestet.
SQL> create or replace function rds_pw_verify(username in varchar2, password in varchar2, old_password in varchar2) return boolean
2 is
3 begin
4 return false;
5 end;
6 /
Function created.
SQL> create profile RDS_PROFILE limit password_verify_function rds_pw_verify;
create profile RDS_PROFILE limit password_verify_function rds_pw_verify
*
ERROR at line 1:
ORA-07443: function RDS_PW_VERIFY not found
SQL> create public synonym rds_pw_verify for rds_pw_verify;
Synonym created.
SQL> create profile RDS_PROFILE limit password_verify_function rds_pw_verify;
create profile RDS_PROFILE limit password_verify_function rds_pw_verify
*
ERROR at line 1:
ORA-07443: function RDS_PW_VERIFY not found
Es bleibt also tatsächlich nur die Möglichkeit, als SYS eine Password Verify Function anzulegen. Möglicherweise ist das von Oracle auch so gewollt, damit die lokalen PDBADMINs nicht selbstständig das Securitylevel der Datenbank negativ beeinflussen können.
Kommentare
Sehr gut und detailiert beschrieben. Besonders die weiteren Rechte und Rollen waren sehr wichtig.
Danke auch an Ihre Kollegin Berit Richert zur PW-Funktion, da habe wir einige Zeit "gebastelt"
ohne positive Ergebnisse, aber nun ist es OK. ;-)