Wednesday, August 12, 2026

Oracle Wallet file settings

 I have been doing more research on how to set wallet locations for the Oracle database as wallets are becoming more and more important to secure your database.



Oracle Wallet usage
Oracle wallet usage


I have found that there are different types of wallets, and  different ways to set the Wallet location depending on it's usage.


1) WALLET_ROOT

Wallet_root is a Database setting (spfile) that is used by a running database.  Below are the different sub-directories that can be created within wallet root and what they can be used for.

The most commonly used directories are

TDE - The wallet in this directory contains the encryption key(s) for the database and replaces the setting ENCRYPTION_WALLET_LOCATION in the sqlnet.ora.

TLS - The wallet in this directory contains the TLS certificate(s) used by the database to make secure TCPS connections.

SERVER_SEPS - The wallet in this location contains the login credentials for other databases or even the same database. Some examples of when this can be useful are.

  • Sending real-time redo to a ZDLRA
  • Creating Database Links to other databases
  • RMAN channel configurations that connect to different nodes in a RAC cluster.
* Note : It was pointed out to me, that using the wallet in server_seps for RMAN channel connects will replace the usage of the "connect ..." string when allocating RMAN channels.


Subdirectory Component / Purpose Typical File Types Notes & Details
tde Transparent Data Encryption (TDE) ewallet.p12, ewallet_*.p12 Created automatically when establishing TDE keystores. Contains master encryption keys for CDB$ROOT, non-CDBs, or isolated PDBs.
tde_seps TDE Auto-Login / SEPS cwallet.sso Stores the Secure External Password Store (SEPS) auto-login file used for automatic opening of the TDE keystore.
tls Transport Layer Security (TLS/SSL) ewallet.p12, cwallet.sso Stores public key infrastructure (PKI) certificates and private keys used for encrypted network communications.
eus Enterprise User Security (EUS) ewallet.p12, cwallet.sso Contains credentials for centralized directory service authentication (e.g., Oracle Internet Directory / LDAP).
xdb_wallet XML Database (XDB) Security ewallet.p12 Used for securing Oracle XML DB HTTP, HTTPS, and FTP server connections.
server_seps Server-Side Credential Store cwallet.sso, ewallet.p12 Used in newer releases (e.g., Oracle 23ai) for passwordless server-side connections and integrations (such as Recovery Appliance).
mfa Multi-Factor Authentication (MFA) ewallet.p12, cwallet.sso Holds certificates and PKI credentials used for native Multi-Factor Authentication integrations (e.g., OMA or Duo). Introduced in Oracle 19.28+.
bctable Blockchain Tables ewallet.p12, cwallet.sso Stores the PKI private key and certificates of the blockchain table owner. Required for signing and verifying rows using the DBMS_BLOCKCHAIN_TABLE package.
<PDB_GUID> Isolated Pluggable Database Root Subdirectories (e.g., /tde, /tls) A 128-bit GUID folder automatically generated per isolated PDB to isolate keystores from CDB$ROOT and other PDBs.



WALLET_ROOT Directory Structure
WALLET_ROOT/
├── bctable/                    # Blockchain Tables PKI store
│   └── ewallet.p12
├── eus/                        # Enterprise User Security credentials
│   └── ewallet.p12
├── mfa/                        # Multi-Factor Authentication wallet (19.28+)
│   └── ewallet.p12
├── server_seps/                # Server-side credential store
│   └── cwallet.sso
├── tde/                        # Master CDB/non-CDB TDE wallet
│   └── ewallet.p12
├── tde_seps/                   # CDB Auto-login keystore
│   └── cwallet.sso
├── tls/                        # TLS/SSL certificate wallet
│   └── ewallet.p12
├── xdb_wallet/                 # XML DB security wallet
│   └── ewallet.p12
└── <PDB_GUID>/                 # Isolated PDB directory
    ├── bctable/
    │   └── ewallet.p12
    ├── mfa/
    │   └── ewallet.p12
    ├── tde/                    # Isolated PDB TDE wallet
    │   └── ewallet.p12
    ├── tde_seps/
    │   └── cwallet.sso
    └── tls/
        └── cwallet.sso


2) SQLNET.ORA

The sqlnet.ora file is used by the database (during startup) and by client sessions.  Client sessions can override which sqlnet.ora is being used by setting TNS_ADMIN.

There are two locations that can be set in the sqlnet.ora file.

ENCRYPTION_WALLET_LOCATION 

This parameter is being deprecated in Oracle 26ai and it is being replaced with WALLET_ROOT mentioned previously.  WALLET_ROOT allows for easily setting individual wallet locations for each database sharing the same $ORACLE_HOME, along with the ability to set individual wallet locations for each PDB. it is recommended to no longer use this setting and migrate to WALLET_ROOT.

WALLET_LOCATION

Wallet_location is used for a number of wallets entries including SEPS, TLS, and EUS.  Because of this you need to be careful when setting the general wallet_location in the default location ($ORACLE_HOME/network/admin).  With consolidation, many environments today have multiple databases sharing the same $ORACLE_HOME and those databases often require separate, unique wallet files files for each database. 
It is best to create a separate sqlnet.ora directory for each database outside of the $ORACLE_HOME and utilize TNS_ADMIN to set your environment.
This parameter is being deprecated for use by the Oracle Database server (during startup), but not by client connections.

3) TNSNAMES.ORA

The tnsnames.ora file is used to make the connection to the database and it is possible set some wallet locations as part of the connection string.
This setting is done with the the (SECURITY= ...) block of the connect string.

SEPS_WALLET_LOCATION


This setting can be used to set the location of the SEPS wallet for each client connection. This can be useful if you make multiple connects in the same client session and wish to use different SEPS wallets for each connection. 

WALLET_LOCATION

Wallet_location is used for a number of wallets entries including SEPS, TLS, and EUS.  The usage of wallet location in the database connect string is the same as it would be within the sqlnet.ora. Using this setting will allow you to isolate which wallets is used for each connection when using the same client session.


Tuesday, June 23, 2026

Automating Creating Long Term backups from the Autonomous Recovery Service

 When I wrote my last blog on listing the Long Term Backups created by Autonomous Recovery Service, I didn't go through the process of how to dynamically create a new backup.

Below is how you create a long term backup in the console, but most customers want to automate this process.


The oci cli command you would use to create a new backup is "oci db backup create".

In order to create an end-of-month backup with a restore point as of midnight what I recommend customers do is

  1. Ensure you have a nightly backup that runs late at night (about 22:00) and will finish by midnight on a regular basis. 
  2. Schedule the automatic long term backup creation to occur about 00:45 on the next day. This ensures that a log sweep has occurred. For BaseDB you would wait until after the next hour.  If you have enabled the zero data loss feature (real-time redo), you want to make sure that the ARCHIVE_LAG_TARGET is set to 30 minutes or less and forcing a periodic log switch.
This ensures you are creating a long term backup with minimal archive logs to defuzzy the backup.

Command inputs

The easiest way to determine the input for this command is to use the --generate-full-command-json-input option.

oci db backup create --generate-full-command-json-input

What is returned is the JSON example below showing you what parameters need to be filled in to create the backup.

{
  "databaseId": "string",
  "displayName": "string",
  "maxWaitSeconds": 0,
  "retentionDays": 0,
  "retentionYears": 0,
  "waitForState": [
    "CREATING|ACTIVE|DELETING|DELETED|FAILED|RESTORING|UPDATING|CANCELING|CANCELED"
  ],
  "waitIntervalSeconds": 0
}

Source database and backup identifying name

  • databaseID : This is the OCID for the database that you want to create the long term backup for.
  • displayName: This is the name to identify the backup from a listing and would match the name I would put in the GUI.

Wait for state of command (Optional)

  • waitForState: Since the backup can take awhile to run, you can have the command wait to return until a specified state (or any one of a list of states) occurs. When creating a new backup the valid states would be
    • ACTIVE
    • CANCELED
    • CANCELING
    • CREATING
    • FAILED
  • maxWaitSeconds: How long to wait between state checks when waiting for a state to occur.
Example of  wait

oci db backup create --waitForState CREATING --waitForState CANCELED 

Would wait for the backup to start to be created or canceled before returning.

Retention (mandatory for long term backups and must be greater than 90 days and less than 10 years)

You would enter the number of days you want to keep backups for (retentionDays), or you would enter the number of years (retentionYears) , but not both.

Below is an example JSON file that would create a new long term backup named "bsgtest" and keep the backup for 100 days.


{
  "databaseId": "ocid1.database.oc1.phx.anyhqljtbv6267ia2wse63oz7xadpv5lfi2gf233333eomezhadfbdkt2eq",
  "displayName": "bsgtest",
  "maxWaitSeconds": 0,
  "retentionDays": 100
}


That's all you need to know about creating a long term backup dynamically.


Thursday, May 21, 2026

Autonomous Recovery Service - Listing backups

Autonomous Recovery Service - Listing backups

One of the unique features of the Autonomous Recovery Service (RCV) is the ability to create Long Term Backups by using existing backups that are currently stored in RCV.

NOTE: Long term backups, also known as "Keep" backups are self contained backups that provide the ability to restore to a small predetermined point-in-time window. These long term backups are often stored for months, or even years and are typically used for auditing purposes.

These backups are created dynamically outside of the database itself and the DB host is not used.
Because the DB host is bypassed, the normal backup listings on the DB host using the DBAASCLI tool do not see long term backups.


Viewing backups with OCI

All of the backups can be viewed in both the OCI Console and by using the OCI CLI tool.
In this blog, I will describe how you can use the OCI Cli tool to view all of the backups.
The command I am utilizing to display backups is

oci db backup list


Unfortunately, the output from this command is JSON objects which can be difficult to read if you want to produce a report.  

In this blog, I show examples leveraging JMESPath queries via the --query flag.



The Foundation: Listing Database Backups

The baseline command to list backups for a specific database requires the --database-id (OCID). By default, we want to output this as a table, grab all records across pages using the --all flag, and project key fields like Shape and Type:

oci db backup list \
  --database-id {DB OCID} \
  --output table \
  --query "data[?\"lifecycle-state\" == 'ACTIVE'] | sort_by(@, &\"time-started\")[].{Backup_Name: \"display-name\", Time_Started: \"time-started\", Status: \"lifecycle-state\", Version: \"version\", OCID: \"id\", Database_size_GBs: \"database-size-in-gbs\",Shape: \"shape\",Type: \"type\"}"

Running this execution in your environment outputs a perfectly structured text report directly in your shell stream:

+------------------+-------------------+-------------------------------------------------------------------------------------+-------------+--------+----------------------------------+-------------+-------------+
| Backup_Name      | Database_size_GBs | OCID                                                                                | Shape       | Status | Time_Started                     | Type        | Version     |
+------------------+-------------------+-------------------------------------------------------------------------------------+-------------+--------+----------------------------------+-------------+-------------+
| Automatic Backup | 24.01171875       | ocid1.dbbackup.oc1.phx.anyhqljtbv6267iafzxovfcfwpr3pcact3e3vu2exz..........         | Exadata.X8M | ACTIVE | 2026-03-30T12:04:06.553000+00:00 | INCREMENTAL | 19.26.0.0.0 |
| Automatic Backup | 24.01171875       | ocid1.dbbackup.oc1.phx.anyhqljtbv6267iat6czxrwvfnhrgl4voypnunsf2qmfc......          | Exadata.X8M | ACTIVE | 2026-03-31T12:05:41.932000+00:00 | INCREMENTAL | 19.26.0.0.0 |
| Automatic Backup | 24.01171875       | ocid1.dbbackup.oc1.phx.anyhqljtbv6267iapdhn7ekp7ax2y74pbbk32yi4c5zr.......          | Exadata.X8M | ACTIVE | 2026-04-01T12:05:13.350000+00:00 | INCREMENTAL | 19.26.0.0.0 |
| Automatic Backup | 24.01171875       | ocid1.dbbackup.oc1.phx.anyhqljtbv6267iakasw46kzqpk74g335esjwehihmkfzuj............. | Exadata.X8M | ACTIVE | 2026-04-02T12:04:54.891000+00:00 | INCREMENTAL | 19.26.0.0.0 |
| Automatic Backup | 24.01171875       | ocid1.dbbackup.oc1.phx.anyhqljtbv6267iagzx75s2s6zravvpjoem2rkvtm7ue54d............. | Exadata.X8M | ACTIVE | 2026-04-03T12:05:40.559000+00:00 | INCREMENTAL | 19.26.0.0.0 |
| Automatic Backup | 24.01171875       | ocid1.dbbackup.oc1.phx.anyhqljtbv6267ia2j7s7r464swgvrfc34dqh7b635hupho............. | Exadata.X8M | ACTIVE | 2026-04-04T12:03:59.219000+00:00 | INCREMENTAL | 19.26.0.0.0 |
| Automatic Backup | 24.01171875       | ocid1.dbbackup.oc1.phx.anyhqljtbv6267iawkwrmemheourosyriczq3v7lecgmrcj............. | Exadata.X8M | ACTIVE | 2026-04-05T07:24:00.238000+00:00 | INCREMENTAL | 19.26.0.0.0 |
| Automatic Backup | 24.01171875       | ocid1.dbbackup.oc1.phx.anyhqljtbv6267ia2j25fk53uf5fmfkivkoa6ijcbn3fdg7c............ | Exadata.X8M | ACTIVE | 2026-04-06T12:04:22.389000+00:00 | INCREMENTAL | 19.26.0.0.0 |
| Automatic Backup | 24.01171875       | ocid1.dbbackup.oc1.phx.anyhqljtbv6267iass2o5w5bryallijsjjpk2nso2654jr2............. | Exadata.X8M | ACTIVE | 2026-04-07T12:03:56.898000+00:00 | INCREMENTAL | 19.26.0.0.0 |
| Automatic Backup | 24.01171875       | ocid1.dbbackup.oc1.phx.anyhqljtbv62

Finding the most recent backup

In this example, I am limiting the command to extract only daily backups (no long term backups), sort by the execution time, and return only the first record.

This command can be also be used in any scripting to ensure you are cloning from the most recent backup.

oci db backup list \
  --database-id {DB OCID} \
--output table \ --query "data[?\"retention-period-in-days\" == \`null\` && \"retention-period-in-years\" == \`null\` && \"lifecycle-state\" == 'ACTIVE'] | sort_by(@, &\"time-started\")[-1].{Backup_Name: \"display-name\", Time_Started: \"time-started\", Status: \"lifecycle-state\", Version: \"version\", OCID: \"id\", Database_size_GBs: \"database-size-in-gbs\",Shape: \"shape\",Type: \"type\"}"

Executing this slice pattern evaluates down to a single, isolated record representing your absolute most recent backup:

+------------------+-------------------+-------------------------------------------------------------------------------------+-------------+--------+----------------------------------+-------------+-------------+
| Backup_Name      | Database_size_GBs | OCID                                                                                | Shape       | Status | Time_Started                     | Type        | Version     |
+------------------+-------------------+-------------------------------------------------------------------------------------+-------------+--------+----------------------------------+-------------+-------------+
| Automatic Backup | 24.01171875       | ocid1.dbbackup.oc1.phx.anyhqljtbv6267iaufuy74ggl2bvf66czd75x3v4366qrwc............. | Exadata.X8M | ACTIVE | 2026-05-19T12:04:12.917000+00:00 | INCREMENTAL | 19.26.0.0.0 |
+------------------+-------------------+-------------------------------------------------------------------------------------+-------------+--------+----------------------------------+-------------+-------------+

Finding all of the long term backups

This command will display only backups that were creating with a future expiration date. This can be used to view all of the long term backups that were created for this database.

 oci db backup list \
>   --database-id {Database OCID} \
>   --output table \
>   --query "data[?\"time-expiry-scheduled\" != \`null\` && \"lifecycle-state\" == 'ACTIVE'] | sort_by(@, &\"time-started\")[].{Backup_Name: \"display-name\", Time_Bacdkup_Started: \"time-started\", Status: \"lifecycle-state\", Version: \"version\", Time_Backup_Expires: \"time-expiry-scheduled\", OCID: \"id\", Database_size_GBs: \"database-size-in-gbs\",Shape: \"shape\"}"


+------------------+-------------------+-------------------------------------------------------------------------------------+-------------+--------+----------------------------------+----------------------------------+-------------+
| Backup_Name      | Database_size_GBs | OCID                                                                                | Shape       | Status | Time_Bacdkup_Started             | Time_Backup_Expires              | Version     |
+------------------+-------------------+-------------------------------------------------------------------------------------+-------------+--------+----------------------------------+----------------------------------+-------------+
| Long_term_backup | 21.0              | ocid1.dbbackup.oc1.phx.anyhqljtbv6267iaskl3otjhgovkhvefzcjzckdg3v5sfwfybglhrl2mqz7a | Exadata.X8M | ACTIVE | 2026-05-14T14:39:17.539000+00:00 | 2027-05-14T14:39:18.871000+00:00 | 19.26.0.0.0 |
+------------------+-------------------+-------------------------------------------------------------------------------------+-------------+--------+----------------------------------+----------------------------------+-------------+