Wednesday, May 28, 2025

TLS for Oracle Real Application Cluster (RAC)

In recent months, I've helped many customers understand Oracle's two new cloud native architectures for centralizing authentication including multi-factor, authorization, and user life cycle management of Oracle database users.  These two new architectures enable integration with identity providers Oracle Cloud Infrastructure Identity and Access Management (OCI IAM) and Microsoft's Entra ID.

The interactive SAML flow of this architecture outsources authentication to the identity provider by popping up a browser to the identity provider.  Once the authentication browser with the identity provider is complete, an authorization code is returned to the database client. The client then securely sends the access token to the database server over a TLS encrypted connection between the database client and database server.  Finally, the database confirms the validity of the access token from the public key that it retrieves from the identity provider.  The following diagram illustrates this interactive flow with Entra ID.


The configuration options for the TLS configuration for a standalone database is covered in the following previous blog posts:


Oracle Real Application Cluster (RAC) database system is quite a bit more sophisticated and has unique needs where TLS is concerned compared to a standalone database instance. The RAC cluster is composed of 2 or more hosts (nodes) configured for high availability including built in load distribution through the Single Client Access Name (SCAN) listener.  




When a database client connects to the RAC cluster through SCAN listener, the SCAN listener re-directs the client to the local listener specified by LOCAL_LISTENER of the RAC node to which he database client is then connected.  The LOCAL_LISTENER is managed by RAC to take into consideration fail-overs and fall-backs which is most easily accomplished by using IP addresses rather than host names.

Given that the client connects via TLS to both the SCAN listener hostname and then to the IP address of the RAC node, the certificate(s) will need to either use a single host cert for all of the RAC nodes and SCAN listener, or a Subject Alternative Name (SAN) certificate that includes the SCAN listener name and all possible RAC node names and the RAC node IP addresses or use a wildcard certificate.

Most customers avoid wildcard certificates like the plague because it of the security risk that it represents by not having unique certificates per host.  Therefore, we will distill the RAC certificate options down to the following three options.

Option 1: Single Host Certificate
This option is possible because the database client can validate the certificate by the SSL_SERVER_CERT_DN alone rather than matching the host value to the CN value of the certificate subject or one of the certificate Subject Alternative Name (SAN) entries.  Let's consider the following TNS entry:

Let's start with looking up the certificate subject from database server with orapki:

$ orapki wallet display -complete  -wallet $WALLET_ROOT/tls  -pwd Oracle123|egrep "Certificates:|Subject:"
Requested Certificates: 
User Certificates:
Subject:        C=US,ST=Texas,L=Austin,O=MyCo,CN=scan.myco.com
Trusted Certificates: 
Subject:        CN=Certificate Authority,O=Company,L=Austin,ST=Texas,C=US


Alternatively, you can retrieve the certificate subject with openssl form a UNIX/Linux host:

echo | openssl s_client -connect scan.myco.com:2484 2>&1 | openssl x509 -noout -text | egrep "DNS:|IP:|Subject:"
        Subject: C=US,ST=Texas,L=Austin,O=MyCo,CN=scan.myco.com

The client TNS entry would look like the following where key TLS properties are highlighted in blue and the SSL_SERVER_CERT_DN is set to the exact subject DN of the certificate.

PDB1 = 
  (DESCRIPTION=
    (ADDRESS_LIST=
      (ADDRESS=(PROTOCOL=
TCPS)(HOST=scan.myco.com)(PORT=2484))
    )
    (SECURITY=
      (SSL_SERVER_DN_MATCH=TRUE)
      (SSL_SERVER_CERT_DN="C=US,ST=Texas,L=Austin,O=MyCo,CN=scan.myco.com")
      (WALLET_LOCATION=SYSTEM)

      (TOKEN_AUTH=AZURE_INTERACTIVE)
      (TENANT_ID=7f4c6e3e-a1e0-43fe-14c5-c2f051a0a3a1)
      (CLIENT_ID=e5124a85-ac3e-14a4-f2ca-1ad635cf781a)
      (AZURE_DB_APP_ID_URI=https://dbauthdemo.com/16736175-ca41-8f33-af0d-4616ade17621)
    )
    (CONNECT_DATA=
      (SERVICE_NAME=pdb1)
    )
  )



Option 2: Single SAN Certificate
The single Subject Alternative Name (SAN) certificate is slightly more secure because you incorporate all of the possible names and IP address of the RAC cluster into the SAN entries of a single certificate where the subject of the certificate includes the SCAN listener host name for it's canonical name (CN) value.

Let's start with looking up the certificate subject from database server with orapki:

$ orapki wallet display -complete  -wallet $WALLET_ROOT/tls  -pwd Oracle123|egrep "Certificates:|Subject:"
Requested Certificates: 
User Certificates:
Subject:        C=US,ST=Texas,L=Austin,O=MyCo,CN=scan.myco.com
Trusted Certificates: 
Subject:        CN=Certificate Authority,O=Company,L=Austin,ST=Texas,C=US


Alternatively, you can retrieve the certificate subject and SAN entries with openssl form a UNIX/Linux host:

echo | openssl s_client -connect scan.myco.com:2484 2>&1 | openssl x509 -noout -text | egrep "DNS:|IP:|Alternative|Subject:"
        Subject: C=US,ST=Texas,L=Austin,O=MyCo,CN=scan.myco.com
            X509v3 Subject Alternative Name: 
                DNS:node1.myco.com, DNS:node2.myco.com, DNS: node1, DNS: node2 IP: 10.0.0.10, IP 10.0.0.20

Note in the above openssl output, that the DNS and IP SAN entries are listed as well and that they include the fully qualified host names, unqualified host names and IP addresses of the RAC nodes.  This is important because clients can sometimes connect directly to a RAC node rather than through the SCAN listener. In this case, you wan the certificate to find a match in the SAN entries to complete the TLS connection.

The client TNS entry would look like the following where key TLS properties are highlighted in blue and the SSL_SERVER_CERT_DN is not present because the DN matching is just looking to find a match of ADDRESS HOST value with the CN value of the certificate subject name or any of the SAN entries.

PDB1 = 
  (DESCRIPTION=
    (ADDRESS_LIST=
      (ADDRESS=(PROTOCOL=
TCPS)(HOST=scan.myco.com)(PORT=2484))
    )
    (SECURITY=
      (SSL_SERVER_DN_MATCH=TRUE)
      (WALLET_LOCATION=SYSTEM)
      (TOKEN_AUTH=AZURE_INTERACTIVE)
      (TENANT_ID=7f4c6e3e-a1e0-43fe-14c5-c2f051a0a3a1)
      (CLIENT_ID=e5124a85-ac3e-14a4-f2ca-1ad635cf781a)
      (AZURE_DB_APP_ID_URI=https://dbauthdemo.com/16736175-ca41-8f33-af0d-4616ade17621)
    )
    (CONNECT_DATA=
      (SERVICE_NAME=pdb1)
    )
  )




Option 3: Individual SAN Certificates Per RAC Node
The individual SAN certificate is again more secure because you specify a host-specific set of SAN entries for that host's names and IP address.

Let's start with looking up the certificate subject and SAN entries from the first RAC node with openssl from a UNIX/Linux host:

echo | openssl s_client -connect node1.myco.com:2484 2>&1 | openssl x509 -noout -text | egrep "DNS:|IP:|Alternative|Subject:"
        Subject: C=US,ST=Texas,L=Austin,O=MyCo,CN=scan.myco.com
            X509v3 Subject Alternative Name: 
                DNS:node1.myco.com, DNS: node1, IP: 10.0.0.10

Next, lets lookup the certificate subject and SAN entries from the second RAC node with openssl from a UNIX/Linux host:

echo | openssl s_client -connect node1.myco.com:2484 2>&1 | openssl x509 -noout -text | egrep "DNS:|IP:|Alternative|Subject:"
        Subject: C=US,ST=Texas,L=Austin,O=MyCo,CN=scan.myco.com
            X509v3 Subject Alternative Name: 
                DNS:node2.myco.com, DNS: node2, IP: 10.0.0.20

Note in the above openssl output, that the DNS and IP SAN entries are listed as well and that they include the fully qualified host names, unqualified host names and IP addresses of the just the local RAC node rather than all RAC nodes.

A similar RAC node specific certificate would be created and installed on each respective RAC node and respective listener.

The client TNS entry would be the same as the Option 2 because the difference in the two options is the contents of the certificate.

If you encounter issues with any of these configurations or EntraID integration, check out my blog posts on troubleshooting these areas:

Those are the three certificate options for RAC clusters.

I hope you found this information useful.

Blessings!

Brad

Oracle Net Service Name Resolution Options

Oracle database name resolution is provided by Oracle Net Services.  Oracle Net Services connect string (a.k.a. connect descriptor) resolution is to Oracle database clients what Domain Name Services (DNS) is to TCP/IP clients for host name to IP address resolution. For example, with DNS a TCP/IP client would resolve a hostname like hrdb.dbauthdemo.com to an IP address like 10.10.0.1.  In the same way, an Oracle database client would resolve through Oracle Net services a service name alias like pdb1 to a connect string like the following:

(DESCRIPTION=(ADDRESS=(PROTOCOL=TCP)(HOST=hrdb.dbauthdemo.com)(PORT=1521))(CONNECT_DATA=(SERVICE_NAME=pdb1)))

In the above sample connect string, the pdb1 service name resolves to a connect string for enabling a database client to connect to the pdb1 service name via TCP to host hrdb.dbauthdemo.com on port 1521.

As customers expand their Oracle database estate and transition Oracle databases from on premises to one or more  clouds and strengthen their security posture through enabling TLS encryption or enabling multi-factor authentication, the number and complexity of connect strings will increase dramatically over time.  Therefore, it is important to ensure accurate and up-to-date name resolution through centralizing Oracle database server name resolution.

Net Service Name Resolution Options

The most common net service naming resolution configuration approaches include the following.

1. Independent Client Configs

Every database client independently specifies a connect string or maintains name service entry it's own  local tnsnames.ora file.  Using previous example, here is a sample connect string for the service name alias pdb1:

(DESCRIPTION=(ADDRESS=(PROTOCOL=TCP)(HOST=hrdb.dbauthdemo.com)(PORT=1521))(CONNECT_DATA=(SERVICE_NAME=pdb1))) 

Here is an equivalent net service connect descriptor entry from a tnsnames.ora file: 

PDB1 = 
  (DESCRIPTION=
    (ADDRESS=(PROTOCOL=TCP)(HOST=
hrdb.dbauthdemo.com)(PORT=1521))
    (CONNECT_DATA=
      (SERVICE_NAME=
 pdb1)
    )
  )



2. Unified tnsnames.ora File

With this option, the database administrative team creates and maintains a single tnsnames.ora file that is either published for internal reference or distributed to all database clients.  This method is better than independently managed connect strings and tnsnames.ora files but is also fraught with possible data inconsistency over time because the clients don't necessarily have to refresh their tnsnames.ora files with the most current version. There can also be security concerns with method used to propagate the tnsnames.ora file to database clients.



3. Centralized Directory Naming

This is one of the most common options employed by customers with a large number of database servers and clients that need to be kept up-to-date.  In this solution, you setup one or more LDAP-based directory service instances according to your high availability requirements and load the directory service with your TNS entries using either dbca tool that comes with the Oracle database or create your own custom TNS entries.

The main directory service products employed for this architecture include Oracle Unified Directory (OUD) and Oracle Internet Directory (OID) though others could be used as well.  One important note on directory server product selection is that Active Directory (AD) can technically be used for this purpose but Microsoft strongly discourages extending AD schema or loading non-Microsoft data in AD because it can put AD upgrades at risk.  I've worked with hundreds of customers on this use case and I've yet to meet a single large customer that allows this data to be loaded into their production AD service.

 Regarding high availability, the recommended maximum high availability architecture includes use local and geographic load balancers that support proper LDAP service tests.  From a security perspective, note that exclusive use of encrypted LDAPS connections is accomplished by not including non-encrypted port in the DIRECTORY_SERVERS ldap.ora.  Further, authenticated lookups is available as well using additional properties for basic authentication are supported for LDAP-based name resolution as well.

An example configuration using OUD 12cPS4 is covered at the following blog post:https://www.braddiggs.com/2023/10/oud-12cps4-use-case-oracle-database.html


The equivalent net service connect descriptor entry for the pdb1 alias from a directory services looks like the following: 

dn: cn=pdb1,cn=OracleContext,dc=hrdb.dbauthdemo,dc=com
objectclass: orclApplicationEntity
objectclass: orclDBServer_92
objectclass: orclService
objectclass: orclDBServer
objectclass: top
orclNetDescString: (DESCRIPTION=(ADDRESS=(PROTOCOL=TCP)(HOST=hrdb.dbauthdemo.com)(PORT=1521))(CONNECT_DATA=(SERVICE_NAME=pdb1))

 

4. Centralized Configuration Provider [New with 23ai] 

This is a new option was introduced with Oracle database version 23ai that enables connect descriptors to be loaded into HTTPS based object storage in JSON format. 

 There are several restrictions namely that it only works with 23ai and newer version clients and that the WALLET_LOCATION only supports SYSTEM.  Only supporting SYSTEM for the WALLET_LOCATION means that all certificates must be signed by a public certificate authority or your private certificate authority chain must be loaded into the host trust store where the database client is run.  This new feature along with the full set of restrictions is covered at the following link: https://docs.oracle.com/en/database/oracle/oracle-database/23/netrf/centralized-configuration-provider-naming-parameters.html 


The equivalent net service connect descriptor entry of the pdb1 alias in JSON format for centralized configuration provider looks like the following: 

{
 "connect_descriptor": "(DESCRIPTION=
                           (ADDRESS=
                              (PROTOCOL=TCP)
                              (HOST=hrdb.dbauthdemo.com)
                              (PORT=1521))
                           (CONNECT_DATA=
                              (SERVICE_NAME=pdb1))
                        )"
}

A JDBC reference to the above entry might look like:

jdbc:oracle:thin:@config-https://objectstorage.us-phoenix-1.oraclecloud.com/n/orasenatdpltintegration03/b/azure/o/pdb1.json


A more robust list of examples of the available configuration providers are available at the following blog post: https://blogs.oracle.com/developers/post/jdbc-config-providers

I hope you find this information helpful.

Blessings!

Braed

Wednesday, May 7, 2025

Entra ID Integration for TOAD

Shout out to Jason Gay for figuring out and sharing the TOAD configuration for adding an Entra ID enabled Oracle database.

The Tools for Oracle Database Administration and Development (TOAD) application is a frequently used SQL tool used by developers and database administrators for browsing and managing Oracle database data.  TOAD appears to leverage the Oracle Call Interface (OCI) libraries included with the Oracle full and instant database clients.  These are the same libraries leveraged by the very popular SQL*Plus command line tool that is includes with the Oracle database client.

To add an Entra ID integration enabled Oracle database to TOAD, us the following configuration parameters:

User: EXTERNAL
TNS: Select database alias from pull-down
Connect as: Normal
Connect using Oracle Client: <ODB 23.5+ full or instant client>
Check: Use this client by default

Here is a screen shot of what it looks like filled out except the selection of the database alias from the tnsnames.ora file.



I hope you found this post helpful and informative.

Blessings!

Brad