Pythian Blog: Technical Track

Token-Based Authentication for ADB with IAM: Part 2

In Part 1, we discussed the essentials of DB token-based authentication and looked at examples to set up authentication for IAM users with exclusive or shared schema mappings. In this second  part, we’ll look at use cases for setting up authentication for IAM Groups with global roles.

 

3. IAM Groups with Global Roles

We currently have a setup where any IAM user added to the IAM Group CONNECT_ONLY will have the privileges to connect to ADB using db-token based authentication. However, we haven’t granted any grants to these users. Now suppose we have IAM Users who need to be given the privilege to read data from a few tables to generate sales reports. For this, we could create a global role called SALES_REPORT on our Database, and along with the IAM group CONNECT_ONLY, we could add the IAM users to the SALES_REPORT role. This will grant them the privileges required to generate reports.

Similarly, we could create an IAM group for DB admins, which is mapped with a global role with DBA privileges. Then the IAM users who are database administrators for your organization could be added to this IAM group along with the CONNECT_ONLY group, which would grant them DBA privileges. This eliminates the need to set up a dedicated database account with DBA roles separately on each database for each administrator. Also, every time a new DBA joins your team, all you need to do is add their IAM user to the required IAM groups.

Let’s take a look at both of these examples.

Creating an external Role in the database

 

SQL>  CREATE ROLE SALES_REPORT identified globally as 'IAM_GROUP_NAME=SALES_REPORT';

Role created.

SQL> grant select on  scott.emp to SALES_REPORT;

Grant succeeded.

Creating the IAM Group and granting it the required IAM User

## Create IAM Group SALES_REPORT

root@kala:~/.oci/instantclient_21_6# oci iam group create --name SALES_REPORT --description "IAM Group grant privileges to pull Sales Report"

root@kala:~/.oci/instantclient_21_6#  export user_ocid=$(oci iam user list --name akala | jq -r '.data[0]."id"') 
root@kala:~/.oci/instantclient_21_6#  export group_ocid=$( oci iam group list --name SALES_REPORT | jq -r '.data[0]."id"')

## Add the user to the desired group

root@kala:~/.oci/instantclient_21_6#  oci iam group add-user --user-id "$user_ocid" --group-id "$group_ocid"


##The Verify IAM user should be in CONNECT_ONLY and SALES_REPORT IAM Groups 
root@kala:~/.oci/instantclient_21_6# oci iam user list-groups --user-id $user_ocid | jq -r '.data[]."name"'
CONNECT_ONLY
SALES_REPORT
Administrators


## Check if the policy to allow access to ADB For the group is in place via CONNECT_ONLY Group 
root@kala:~/.oci/instantclient_21_6#  export compartment_id=$(oci iam user list --all | jq -r  '.data[0]."compartment-id"')
root@kala:~/.oci/instantclient_21_6#  oci iam policy list --compartment-id $compartment_id | jq -r '.data[]."statements"'| grep -i autonomous-database-family
"allow group CONNECT_ONLY to use autonomous-database-family in tenancy"

 

Get DB Token and establish a connection

The role SALES_REPORT has read-only privileges, and hence the user cannot modify the records. Also, note the session roles view that can list the roles that have been granted to the connected user:

# Fetch the db-token 

root@kala:~/.oci/instantclient_21_6#  oci iam db-token get
Private key written at /root/.oci/db-token/oci_db_key.pem
db-token written at: /root/.oci/db-token/token
db-token is valid until 2022-05-08 23:38:59


# Establish connection 
root@kala:~/.oci/instantclient_21_6#  sqlplus /@dblab01_low

SQL*Plus: Release 21.0.0.0.0 - Production on Sun May 8 22:39:02 2022
Version 21.6.0.0.0

Copyright (c) 1982, 2022, Oracle.  All rights reserved.

Last Successful login time: Sun May 08 2022 22:38:05 +05:30

Connected to:
Oracle Database 19c Enterprise Edition Release 19.0.0.0.0 - Production
Version 19.15.0.1.0

SQL> SELECT SYS_CONTEXT('USERENV','IDENTIFICATION_TYPE') FROM DUAL;

SYS_CONTEXT('USERENV','IDENTIFICATION_TYPE')
--------------------------------------------------------------------------------
GLOBAL SHARED

SQL> SELECT * FROM SESSION_ROLES;

ROLE
--------------------------------------------------------------------------------
CONNECT
SALES_REPORT

SQL> select count(*) from scott.emp;

  COUNT(*)
----------
         4

SQL> update scott.emp set name ='John';
update scott.emp set name ='John'
             *
ERROR at line 1:
ORA-01031: insufficient privileges

Groups that can be used across multiple ADBs

Now let’s take this a step further and create an IAM group mapped to multiple ADB instances.

For this example, we have 2 ADB databases, DBLAB01 and DBLAB02. We’ll create a database role called IAM_DBAS_ROLE on both the ADBs. This role will have the required privileges to manage the PDB instance, and then we will map this role to a global IAM Role called DB_ADMINS. We will use our common schema “SHARED_SCHEMA” in the database as our landing schema for the admins.

Create a DB admins role in the database DBLAB01:

 

SQL> create role IAM_DBAS_ROLE identified globally as 'IAM_GROUP_NAME=DB_ADMINS';

Role created.

SQL> Grant pdb_dba to IAM_DBAS_ROLE;

Grant succeeded.

Preparing the database DBLAB02

Since we haven’t used this ADB instance with OCI_IAM, we will need to enable the external authentication with OCI_IAM, and create a landing schema for the connections and the required roles.

Also, you will need to download the regional wallet and confirm that the WALLET_LOCATION path in sqlnet.ora is correct and that the TNS_ALIAS has the (TOKEN_AUTH=OCI_TOKEN)

 

## Connect as Admin user 
 
SQL> select name from v$pdbs;

NAME
--------------------------------------------------------------------------------
GAD9DCE9730527A_DBLAB02


SQL> exec DBMS_CLOUD_ADMIN.ENABLE_EXTERNAL_AUTHENTICATION(type => 'OCI_IAM',force => TRUE );

PL/SQL procedure successfully completed.

SQL> SELECT NAME, VALUE FROM V$PARAMETER WHERE NAME='identity_provider_type';

NAME                        VALUE
-----------                --------------------------------------------------------------------------------
identity_provider_type     OCI_IAM

SQL> CREATE USER SHARED_SCHEMA IDENTIFIED GLOBALLY AS 'IAM_GROUP_NAME=CONNECT_ONLY';

User created.

SQL> grant connect to SHARED_SCHEMA;

Grant succeeded.


SQL> create role IAM_DBAS_ROLE identified globally as 'IAM_GROUP_NAME=DB_ADMINS';

Role created.

SQL> Grant pdb_dba to IAM_DBAS_ROLE;

Grant succeeded.

 

Creating the IAM Group and granting it to the desired IAM User

We are adding our IAM user “akala”  to the group DB_ADMINS. This should grant akala administrative privileges on both the ADBs.

 

## Create IAM Group DB_ADMINS

root@kala:~/.oci/instantclient_21_6# oci iam group create --name DB_ADMINS --description "IAM Group that grant privileges to Database Administrators"

root@kala:~/.oci/instantclient_21_6#  export user_ocid=$(oci iam user list --name akala | jq -r '.data[0]."id"')
root@kala:~/.oci/instantclient_21_6#  export group_ocid=$( oci iam group list --name DB_ADMINS | jq -r '.data[0]."id"')

## Add the user to the desired group

root@kala:~/.oci/instantclient_21_6#  oci iam group add-user --user-id "$user_ocid" --group-id "$group_ocid"


##The Verify IAM user should be in CONNECT_ONLY and DB_ADMINS IAM Groups
root@kala:~/.oci/instantclient_21_6# oci iam user list-groups --user-id $user_ocid | jq -r '.data[]."name"' 
CONNECT_ONLY
SALES_REPORT
DB_ADMINS
Administrators 

## Check if the policy to allow access to ADB For the group is in place via CONNECT_ONLY Group
root@kala:~/.oci/instantclient_21_6# export compartment_id=$(oci iam user list --all | jq -r '.data[0]."compartment-id"') 
root@kala:~/.oci/instantclient_21_6# oci iam policy list --compartment-id $compartment_id | jq -r '.data[]."statements"'| grep -i autonomous-database-family
"allow group CONNECT_ONLY to use autonomous-database-family in tenancy"

Get DB Token and establish a connection to the first ADB

Validating the TNS Alias for both the autonomous databases:

root@kala:~/.oci/instantclient_21_6#  grep -i OCI tnsnames.ora
dblab01_low = (description= (retry_count=20)(retry_delay=3)(address=(protocol=tcps)(port=1522)(host=*****.ap-mumbai-1.oraclecloud.com))(connect_data=(service_name=g********_dblab01_low.adb.oraclecloud.com))(security=(ssl_server_cert_dn="CN=adb.ap-mumbai-1.oraclecloud.com, OU=Oracle ADB INDIA, O=Oracle Corporation, L=Redwood City, ST=California, C=US") (TOKEN_AUTH=OCI_TOKEN)))
dblab02_low = (description= (retry_count=20)(retry_delay=3)(address=(protocol=tcps)(port=1522)(host=****.ap-mumbai-1.oraclecloud.com))(connect_data=(service_name=g********_dblab02_low.adb.oraclecloud.com))(security=(ssl_server_cert_dn="CN=adb.ap-mumbai-1.oraclecloud.com, OU=Oracle ADB INDIA, O=Oracle Corporation, L=Redwood City, ST=California, C=US") (TOKEN_AUTH=OCI_TOKEN)))

Test connectivity and privileges to the first ADB (DBLAB01):

root@kala:~/.oci/instantclient_21_6#  oci iam db-token get
Private key written at /root/.oci/db-token/oci_db_key.pem
db-token written at: /root/.oci/db-token/token
db-token is valid until 2022-05-09 00:18:38
root@kala:~/.oci/instantclient_21_6# sqlplus /@dblab01_low

SQL*Plus: Release 21.0.0.0.0 - Production on Sun May 8 23:18:44 2022
Version 21.6.0.0.0

Copyright (c) 1982, 2022, Oracle.  All rights reserved.

Last Successful login time: Sun May 08 2022 23:09:04 +05:30

Connected to:
Oracle Database 19c Enterprise Edition Release 19.0.0.0.0 - Production
Version 19.15.0.1.0

SQL> select name from v$pdbs;

NAME
--------------------------------------------------------------------------------
GAD9DCE9730527A_DBLAB01

SQL> SELECT * FROM SESSION_ROLES where role='PDB_DBA';

ROLE
--------------------------------------------------------------------------------
PDB_DBA

SQL> sELECT SYS_CONTEXT('USERENV','IDENTIFICATION_TYPE') FROM DUAL;

SYS_CONTEXT('USERENV','IDENTIFICATION_TYPE')
--------------------------------------------------------------------------------
GLOBAL SHARED

SQL> SELECT SYS_CONTEXT('USERENV','AUTHENTICATION_METHOD') FROM DUAL;

SYS_CONTEXT('USERENV','AUTHENTICATION_METHOD')
--------------------------------------------------------------------------------
TOKEN_GLOBAL

SQL> SELECT SYS_CONTEXT('USERENV','CURRENT_USER') FROM DUAL;

SYS_CONTEXT('USERENV','CURRENT_USER')
--------------------------------------------------------------------------------
SHARED_SCHEMA

SQL> SELECT SYS_CONTEXT('USERENV','AUTHENTICATED_IDENTITY') FROM DUAL;

SYS_CONTEXT('USERENV','AUTHENTICATED_IDENTITY')
--------------------------------------------------------------------------------
akala

 

Similarly, test connectivity and privileges to the second ADB (DBLAB02):

root@kala:~/.oci/instantclient_21_6#  sqlplus /@dblab02_low

SQL*Plus: Release 21.0.0.0.0 - Production on Sun May 8 23:26:57 2022
Version 21.6.0.0.0

Copyright (c) 1982, 2022, Oracle.  All rights reserved.


Connected to:
Oracle Database 19c Enterprise Edition Release 19.0.0.0.0 - Production
Version 19.15.0.1.0

SQL> select name from v$pdbs;

NAME
--------------------------------------------------------------------------------
GAD9DCE9730527A_DBLAB02

SQL> SELECT * FROM SESSION_ROLES where role='PDB_DBA';

ROLE
--------------------------------------------------------------------------------
PDB_DBA

4. Instance Principal/Resource Principal through shared mapping

OCI applications can use OCI resource principal to connect to an ADB Instance. Similar to IAM user-based authentication process, the application using an OCI SDK can retrieve and then forward the retrieved db-token to the ADB Instance for verification and authorization. This enables the application to talk directly with the ADB without separate DB accounts for the applications.

here are a couple of things worth noting

  • When using Instance/Resource Principals, you can only use dynamic groups.
  • Also, Instance/Resource Principals can only be mapped through shared mapping.

Conclusion

In this series of blogs, we have explored how IAM authentication can be leveraged to connect directly to an ADB Instance, eliminating the need for dedicated database credentials to be maintained.

This thus enables the IAM administrators to manage all the ADB users centrally, by adding/removing users to the appropriate IAM groups as required. From a user perspective, the users no longer need to maintain individual passwords for each ADB instance, and from an application perspective, if supported, it can log on directly to an ADB without the need for dedicated credentials.

I hope you found this post helpful. Feel free to share any questions or feedback in the comments, and make sure to sign up for updates so you don’t miss the next post.

 

 

No Comments Yet

Let us know what you think

Subscribe by email