Tag Archives: trivadis

A simple Container based Guacamole Setup

Another food blog post? No, of course not. Guacamole in this case does not refer to the avocado-based dip, but to the Apache client less remote desktop gateway. We use this as an alternative access to the OCI based Trivadis LAB environment. We use an automatically configured Guacamole environment with Nginx reverse proxy and Let’s encrypt SSL certificates. The detailed description of this Guacamole environment is the goal of this blog post.

For the Trivadis LAB and training environment in Oracle Cloud (OCI), we typically use a bastion host to access the various resources. In training courses, it is not always possible for all participants to use SSH clients such as Putty, MobaXterm, SSH command line and so on. This is especially true when training courses are increasingly conducted virtually, as is currently the case. Participants often use their company’s IT devices for this purpose. These devices are often protected accordingly and do not allow SSH access to public IP addresses. An HTTP-based remote access gateway such as Guacamole offers a simple alternative to allow participants to access the training environment.

Structure

Apache itself already provides Guacamole as a container. A simple setup contains two containers. The guacamole container for the remote desktop gateway and the guacd container for the server-side proxy. Guacamole uses a dedicated port and is not specially protected. For the training environment, however, access should be possible via HTTPS. The use of the default ports is also desirable. Guacamole uses Tomcat with a dedicated port and is not specially protected by default. For the training environment, however, access should be possible via HTTPS. The use of the default ports is also desirable. To meet the requirements while using existing Docker images, Guacamole is run behind an Nginx reverse proxy. The SSL certificates are generated using Let’s encrypt. The following graphic shows the schematic structure of the environment.

Guacamole Setup with Nginx Reverse Proxy

A few notes on the containers:

  • nginx configured as reverse proxy. By default this container does bind to HTTP and HTTPS to allow client access.
  • certbot simple container to create the Let’s Encrypt certificates.
  • guacamole the Apache Guacamole container
  • guacd the server-side proxy server for Guacamole
  • mysql database used to store the Guacamole connection information

Quickstart

Make sure you have docker and docker-compose installed on your environment. If not yet done you can get more information in chapter Install Docker Compose in the Docker documentation.

git clone https://github.com/oehrlis/guacamole.git
  • Review and update the .env and docker-compose.yml file. Make sure to define at least the following environment variable either with export , in the .env file or directly change the values in the compose file:
    • EMAIL – Adding a valid address for certificate renewal (default none)
    • HOSTNAME – Define a hostname for the nginx server and certificate name (default: $(hostname))
    • DOMAINNAME – Define a domain name for nginx server and certificate name (default: trivadislabs.com)
    • STAGING_ENABLE – Set STAGING to 1 if you’re testing your setup to avoid hitting request limits is certification
  • Pull the required Docker images
docker pull guacamole/guacamole
docker pull guacamole/guacd
docker pull mysql/mysql-server
docker pull nginx
docker pull certbot/certbot
  • Prepare the MySQL database
cd guacamole
./bin/prepare_initdb.sh
  • Start guacamole containers
docker-compose up -d guacamole mysql guacd
  • Perform the certificate challenge. Where Nginx is first started with a self signed certificate in order to then execute the actual certificate request. Define the variables If not yet updated in the .env file
export HOSTNAME="guacamole"
export DOMAINNAME="example.org"
export EMAIL="info@example.org"
export STAGING_ENABLE=1
./bin/prepare_certs.sh
  • Start all containers
docker-compose up -d

The different passwords for the Guacamole admin, Guacamole database and MySQL root are generated when not explicitly specified. You can find them in the logs respectively in the .env file which is updated by the prepare_initdb.sh script.

As soon as your container are up and running you can access your guacamole remote desktop gateway

Login Dialog Guacamole
Example Guacamole Home Page

Automatisation

There is even a quicker way to setup the Guacamole Docker stack by using the script setup_guacamole.sh. In particular, this method is used to set up the guacamole stack in an OCI bootstrap process. By default it will use the OS user avocado (what else 😉). But the user can be customised by the variable GUACAMOLE_USER.

git clone https://github.com/oehrlis/guacamole.git
cd guacamole
export HOSTNAME="guacamole"
export DOMAINNAME="example.org"
export EMAIL="info@example.org"
export STAGING_ENABLE=1
./bin/setup_guacamole.sh

Customised Configuration

As you could see above, the installation can be customised with a few variables. These include the following variables in particular.

VariableDefault ValueDescription
HOSTNAMEhostnameHostname of the bastion host used to create the certificate request. i.h. this name must be resolvable via DNS
DOMAINNAMEtrivadislabs.comDomain name user for the certificate request
EMAILadmin@DOMAINNAMEA valid e-Mail address used for the certificate challange
GUACAMOLE_USERavocadoGuacamole OS User
GUACAMOLE_BASE/home/${GUACAMOLE_USER}/guacamoleGuacamole base folder
GUACADMIN_USERguacadminGuacamole admin user
GUACADMIN_PASSWORDn/aGuacamole admin password. Will be generated and stored in .env
MYSQL_PASSWORDn/aMySQL database password. Will be generated and stored in .env
Environment Variables

Additionally, it is possible to create the guacamole connections directly when creating the configuration. For this purpose, the SQL script 02_connections.sql in the config/mysql directory has to be adapted. For example, with an SSH connection.

INSERT INTO guacamole_connection (connection_name, protocol) 
    VALUES ('Database Server (db - 10.0.1.6)', 'ssh');
INSERT INTO guacamole_connection_parameter VALUES (2, 'hostname', '10.0.1.6');
INSERT INTO guacamole_connection_parameter VALUES (2, 'port', '22');
INSERT INTO guacamole_connection_parameter VALUES (2, 'username', 'oracle');

Of course you can also enter passwords, SSH keys etc. directly. All SQL scripts in this directory are executed when the MySQL DB is created. So further customisations are possible. More information about the configuration of Guacamole can be found in the documentation.

OCI Bastion Host

How about using this on an OCI bastion host? Nothing simpler than that. You just have to configure you VCN and bastion host in the following manner.

  • Allow incoming traffic for port 80 and 443
  • Install docker on the bastion host
  • Register the public IP of your bastion host in a DNS zone create in OCI
  • Deploy the Guacamole stack manually as explained above.

In one of my next blog posts, I will show you how to automatically deploy your bastion host with guacamole stack by using my Terraform modules module tvdlab-bastion and tvdlab-base.

Conclusion

The container-based setup for Apache Guacamole is relatively simple and adds value to accessing the Trivadis cloud-based training and lab environment. The approach described here has also been successfully used for various test and PoC environments. To make setup in OCI even easier, Terraform module tvdlab-bastion and tvdlab-base use this approach to deploy the Guacamole stack on the Bastion host directly in the bootstrap process. But more about that in an other blog post.

References

How to get an Oracle 21c Database on the Oracle Cloud

A few hours ago Oracle published a blog post about the new version Oracle 21c. See Introducing Oracle Database 21c. It is again an innovation release with a couple of interesting new features and enhancements. The online Oracle Documentation library does provide a few information on this enhancements:

The study of documentation and blog posts is always interesting. But it gets much more exciting when you can do first hands-on with the new release. Thanks to the Oracle Cloud this is easily possible. With a few clicks in OCI you can create a DB system with Oracle 21c. Then nothing else standing in the way to test new features all night long.

Requirements

Unfortunately it is not possible to get Oracle 21c as Always Free Version. At least I did not find a way to do so. My workmate Philipp Salvisberg pointed out to me that it is indeed possible to create an Allways Free 21c ATP DB. You just have to be in the right OCI region. Any way, since I do like to test a few infrastructure feature like DB Nest, Kerberos, EUS etc I any way have to setup a DB System rather than an Oracle Autonomous Database. In order to finally get started, a few prerequisites must be met:.

  • An Oracle Account and active OCI Tenant
  • A few OCI credits
  • Compartment where you plan to deploy your DB system
  • A VCN for you DB System.

VCN

Usually create my VCN’s with Terraform. That means I create my VCNs usually with a bastion host, a public and a private network. For this I use my Terraform OCI modules which are available in the Terraform registry. See tvdlab-base, tvdlab-bastion or tvdlab-vcn. A blog post is still on my todo list 😊. For setting up the Oracle 21c DB system I assume that a corresponding VCN is available.

I’ll use the following information for my setup

  • Compartment DB21C
  • VCN db21c00

DB System

To setup the 21c database go to the main page and select Bare Metal, VM, and Exadata in the menu.

Create a DB System by pressing the corresponding blue button. Do not be surprised. On the following picture you can already see a 21c DB system.

Compared to Oracle 20c preview it does not matter if you choose Bare Metal or Virtual Machine. 21c is available for both environments. This also applies to the storage management software. I do select a Virtual Machine with the Logical Volume Manager.

DB System wizard part 1

As I do only use the DB System for simple feature test and engineering I keep the size to the minimum. As Oracle software I choose the Enterprise Edition. Other editions including Standard Edition are also possible.

DB System wizard part 2

Add you public SSH key(s) to be able to access the DB system later on via SSH. Depending on your OS you can use putty or ssh-keygen for this. Since I do work on a Mac I’ll create the pair of keys with ssh-keygen.

Add SSH public keys

Finalise the system configuration by selecting your VCN and a corresponding subnet. In my case it is the VCN db21c00 and the private subnet db21c00 private.

DB System wizard part 3

After pressing next you come to the second page of the DB System wizard, where we configure the DB itself.

DB System wizard part 4

Choose a fancy name for your DB or like me just TDB21c. By the default you see, that the Database Image 19c is selected. You can change it and select 21c.

DB System wizard part 5

Finish the DB System wizard by selecting Create DB System.

DB System wizard part 6

It will take now a while until you Oracle 21c Database is ready to use. A good moment to crab a cup of coffee or write a blog post 😉. I’ll do this now as well and finish this post in a couple of minutes…

DB System Setup

My 21C DB system is finished in the meantime and can be used.

Since I did create the VM in a private subnet, it is not possible to directly access the DB from the internet. I do have to connect using the bastion host. Either via SSH or for SQL Developer using SSH port forwarding.

Enclosed an example to connect to the new DB system via bastion host using SSH proxy command. In this example I do us the following SSH parameters:

  • -A does enables forwarding of the authentication agent connection
  • -J is used to specify the proxy host used to initiate the connection. In my case the bastion host.
  • db21c is the alias hostname for the public IP of my bastion host
  • deadalus is the hostname for my DB system
  • opc is the user used to connect to the different compute instances. you can also connect directly to the oracle user, if you put the public keys in the .ssh/authorized_keys file of user oracle.
soe@gaia:~/ [ic19300] ssh -A -J opc@db21 opc@deadalus
Last login: Wed Dec  9 05:35:20 2020 from 10.0.0.2
[opc@deadalus ~]$ sudo su - oracle
Last login: Wed Dec  9 05:36:22 UTC 2020 from 10.0.0.2 on pts/0
[oracle@deadalus ~]$ sqlplus / as sysdba

SQL*Plus: Release 21.0.0.0.0 - Production on Wed Dec 9 05:42:38 2020
Version 21.1.0.0.0

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


Connected to:
Oracle Database 21c Enterprise Edition Release 21.0.0.0.0 - Production
Version 21.1.0.0.0

SQL> 

Alternatively, you can do SSH port forwarding for port 1521 and connect directly to the database with SQL Developer.

soe@gaia:~/ [ic19300] ssh -A opc@db21 -L 1521:deadalus:1521
Last login: Wed Dec  9 05:33:00 2020 from yyy.yyy.yyy.yyy
--------------------------------------------------------------------
-
- Welcome to the bastion / jump host for the OCI environment
- hostname          :   db21c
- Public IP         :   xxx.xxx.xxx.xxx
- Guacamole Console :   http://secret
- Guacamole Admin   :   <USER>
- Guacamole Password:   <PASSWORD>

[opc@db21c-bastion00 ~]$ 
SQL Developer connection setting
SQL Developer SQL Worksheet

If you don’t want to deal with command line and SSH commands, then with newer versions of SQL Developer you can set up a connection directly via SSH port forwarding. Select SSH from the View menu and create a new SSH connection. The following details must be added:

  • Name: Name of your SSH connection
  • Host: Public IP of your bastion host
  • Username: Usually just opc
  • Key File: The private key file matching the public key used above
  • Name: Name of you SSH port forwarding rule
  • Host: Private IP address of the DB system
  • Port: The TCP Port configured on the DB system usually just 1521
  • Local Port: Use an automatically assigned local port, then you do not have to bother if it is already in use
New SSH Host Dialog

The SSH host can now be used to configure the DB connection. You only have to select the connection type SSH.

SQL Developer Connection using SSH

Conclusion

In OCI you can create a new engineering system for Oracle 21c relatively quickly. With the Bastion host I have chosen a more complex but secure method. The separation of the subnets into private and public network does offer me the flexibility to test a few Features which requires additional infrastructure components. e.g. Centrally Managed Users CMU or Enterprise User Security EUS, which both require additional services such as Oracle Unified Directory or MS Active Directory. Running everything via public IP is rather a bad idea. Any way, following this approach you now have Oracle 21c Database. I wish you happy engineering.

References

Security Best Practice: Oracle passwords, but secure!

Beach view in Brighton at the UKOUG Techfest 2019

Today I held my presentation about Oracle security best practice “Oracle passwords, but secure!” at the virtual UKOUG event. Unfortunately, this year the beautiful view of Brighton beach and the active exchange with colleagues was missing. Ok, on the other hand I was able to enjoy the first snow in Switzerland with my children. 😊

The following blog post is a summary of my presentation with some examples, notes, references and slides.

Oracle Password Hashes

The different Oracle Database releases do provide various password verifiers. Although the older password verifiers are no longer state of the art, they are still used relatively frequently. It is therefore essential to take the appropriate measures to make password-based authentication secure. Oracle currently offers the following password hash functions:

  • Oracle 10g Hash Function based on DES and an Oracle specific algorithm. It is case insensitive and does use a weak password salt i.e. the username is used as salt.
  • MD5 based Hash Function used for digest authentication in XDB
  • Oracle 11g Hash Function based on the SHA1 hash algorithm. But since 2005 SHA1 is no longer considered as safe. The hash function does supports case sensitive and multibyte character passwords.
  • Oracle 12c Hash Function based on a de-optimised algorithm involving PBKDF2 and SHA-512. It supports case sensitive and multibyte character passwords.

The different password verifiers can be controlled by SQLNET.ALLOWED_LOGON_VERSION_SERVER respectively SQLNET.ALLOWED_LOGON_VERSION_CLIENT or by setting the passwords explicitly using ALTER USER ... IDENTIFIED BY VALUES.

Create different users with different password verifiers

CREATE USER test_10g IDENTIFIED BY VALUES 'AF310E4D20D06950';
CREATE USER test_11g IDENTIFIED BY VALUES 'S:6702B83E88D277BFC378AD6B22DD1AE01895A254470F8124A9D3C5347056';
CREATE USER test_12c IDENTIFIED BY VALUES 'T:45738A7B75C9E31ED0C533BCF4931084658A143FD7CF826B980A88EA6C4F0BE66C28DA7085BCAE386723029BA967DC4F45E9C146F6FA7C22E44BA2C1BD2F56F8C22291D417E26D4B810003F3F055EDFF';
CREATE USER test_all IDENTIFIED BY Welcome1;

In DBA_USERS you will see the different password versions

SET LINESIZE 160 PAGESIZE 200
COL username FOR a10
COL password_versions FOR a20
SELECT username, password_versions 
FROM dba_users WHERE username LIKE 'TEST_%';

USERNAME    PASSWORD_VERSIONS
----------- --------------------
TEST_10G    10G
TEST_11G    11G
TEST_ALL    10G 11G 12C
TEST_12C    12C

Or in USER$ you can find the corresponding hashes:

SET LINESIZE 160 PAGESIZE 200
COL name FOR a10
COL password FOR a16
COL spare4 FOR a64
SELECT name,password,spare4 
FROM user$ WHERE name LIKE 'TEST_%' ORDER BY 1;

NAME       PASSWORD         SPARE4
---------- ---------------- ----------------------------------------------------------------
TEST_10G   AF310E4D20D06950
TEST_11G                    S:6702B83E88D277BFC378AD6B22DD1AE01895A254470F8124A9D3C5347056
TEST_12C                    T:45738A7B75C9E31ED0C533BCF4931084658A143FD7CF826B980A88EA6C4F0B
                            E66C28DA7085BCAE386723029BA967DC4F45E9C146F6FA7C22E44BA2C1BD2F56
                            F8C22291D417E26D4B810003F3F055EDFF

TEST_ALL   4932A1B4C59EC3D0 S:ABF25107166264C8EAFE72BF02152DE17000F359CB5BAF21A6AF41477633;T
                            :62FEE108652A56D940813F54EC72D1494ACAD99F2BBDD0A578BF1F97FAB4A7E
                            B468A98B6B553E460DE21E57F6C35A930DEE027D20B33ED13D56EA0ECACB1CEA
                            94EEC8AC389561346052BB0BFF2C06647

Manually create a Oracle 10g password verifier:

SQL> @create_password_hash.sql system ieShae0

Username : system
Password : ieShae0
Hash	 : 0AD56CF5F1CB8D2A
SQL	 : alter user system identified by values '0AD56CF5F1CB8D2A';

PL/SQL procedure successfully completed.

Testing the Password Verifier

There are a couple of possibilities and tools to “verify” password hashes. Among the best known are the tools Hashcat and John the Ripper. These tools doe support a wide range of hashes as well attack methods. Below you find an example of a brute force attack for the Oracle hash we created above.

  • --increment will start to brute force with shorter length e.g 4 characters
  • -custom-charset1 to define numbers and characters
  • -hash-type Oracle 7+ respectively password verifier 10g
  • --show show the password
echo "0AD56CF5F1CB8D2A" >demo.hash
hashcat --attack-mode 3 --increment --increment-min 4 \
--custom-charset1 ?l?d --hash-type 3100 ./demo.hash ?1?1?1?1?1?1?1
hashcat --hash-type 3100 ./demo.hash --show

Good Practice

Here are a few good practices on Oracle passwords.

  • Keep your Oracle Clients and Server up to date. Stay updated by following Critical Patch Updates, Security Alerts and Bulletins. Install security fixes in a reasonable time frame
  • Consider using strong Authentication like Kerberos and SSL based authentication.
  • Don’t use legacy password verifier
    • Use Oracle password file version 12.2
    • Explicitly configure ALLOWED_LOGON_VERSION_SERVER to 12a and exclusively use 12c hash values
    • Start using PBKDF2 SHA-512 for directory-based password authentication with EUS and CMU
  • Revise your password policies
    • NIST, CIS, STIG and other standards are continuously adjusted.
    • Does the complexity rule still make sense or does it just reduce the amount of possibilities.
  • User awareness training. Make sure your user know the principle of good and bad Use of phase phrase rather than password

Slides of the UKOUG Presentation

UKOUG Presentation Security Best Practice: Oracle passwords, but secure!

References

Links and references related to this blog post

Audit Trail cleanup in Oracle Multitenant environments

A crucial aspect of any database audit concept is the management and maintenance of audit trails. Depending on the defined audit policies and the database activity, an audit trail can grow relatively quickly. Oracle Multitenant environments increase the operational effort because the root container and each PDB uses their own audit trail. Ok, for a simple CDB with 2-3 PDB this effort is manageable, but what about CDB’s with 40 or more PDB’s?

Let’s look into the different possibilities.

Common Purge Job for all PDB’s

Oracle allow’s to initiate an audit trail clean up for all PDB’s using dbms_audit_mgmt.clean_audit_trail procedure by specifying dbms_audit_mgmt.container_all. The following example initiate a clean up in the root container for all PDB’s without considering the last archive timestamp.

ALTER SESSION SET CONTAINER=cdb$root;
BEGIN
   dbms_audit_mgmt.clean_audit_trail(
      audit_trail_type => dbms_audit_mgmt.audit_trail_unified,
      container => dbms_audit_mgmt.container_all,
      use_last_arch_timestamp => false);
END;
/

The problem with this method are the closed PDB’s. First let’s check how much audit records we do have per PDB.

COLUMN con_id FORMAT 999999
COLUMN count FORMAT 99999
COLUMN name FORMAT a8
SELECT
   v.con_id, v.name, v.open_mode, COUNT(u.event_timestamp) count
FROM
   cdb_unified_audit_trail u
FULL OUTER JOIN v$containers v ON u.con_id = v.con_id
GROUP BY
   v.con_id, v.name, v.open_mode
ORDER BY
   v.con_id;

CON_ID NAME     OPEN_MODE   COUNT
====== ======== =========== =====
     1 CDB$ROOT READ WRITE    644
     2 PDB$SEED READ ONLY       0
     3 PDB1     MOUNTED         0
     4 PDB2     READ WRITE     36
     5 PDB3     MOUNTED         0
     6 PDBSEC   READ WRITE     27

Running the clean up on this container database will end with an ORA-46273: DBMS_AUDIT_MGMT operation failed in one of the PDB.

BEGIN
   dbms_audit_mgmt.clean_audit_trail(
      audit_trail_type => dbms_audit_mgmt.audit_trail_unified,
      container => dbms_audit_mgmt.container_all,
      use_last_arch_timestamp => false);
END;
/

BEGIN
*
ERROR at line 1:
ORA-46273: DBMS_AUDIT_MGMT operation failed in one of the PDB
ORA-06512: at "AUDSYS.DBMS_AUDIT_MGMT", line 204
ORA-06512: at "AUDSYS.DBMS_AUDIT_MGMT", line 2137
ORA-06512: at "AUDSYS.DBMS_AUDIT_MGMT", line 1409
ORA-06512: at line 2

The error ORA-46273 is confusing. When we check the audit records, we see that the entries have been effectively be deleted. Here it would be more understandable if Oracle simply issue a warning rather than an error.

COLUMN con_id FORMAT 999999
COLUMN count FORMAT 99999
COLUMN name FORMAT a8
SELECT
   v.con_id, v.name, v.open_mode, COUNT(u.event_timestamp) count
FROM
   cdb_unified_audit_trail u
FULL OUTER JOIN v$containers v ON u.con_id = v.con_id
GROUP BY
   v.con_id, v.name, v.open_mode
ORDER BY
   v.con_id;

CON_ID NAME     OPEN_MODE   COUNT
====== ======== =========== =====
     1 CDB$ROOT READ WRITE    5
     2 PDB$SEED READ ONLY     0
     3 PDB1     MOUNTED       0
     4 PDB2     READ WRITE    1
     5 PDB3     MOUNTED       0
     6 PDBSEC   READ WRITE    1

The same does apply when we run the clean up task as a job. The job will always fail if one PDB is in MOUNT stat. This is annoying when monitoring scheduler jobs.

SQL> BEGIN
2 DBMS_SCHEDULER.RUN_JOB(job_name => '"AUDSYS"."TVD_TEST"');
3 END;
4 /
BEGIN
*
ERROR at line 1:
ORA-46273: DBMS_AUDIT_MGMT operation failed in one of the PDB
ORA-06512: at "AUDSYS.DBMS_AUDIT_MGMT", line 204
ORA-06512: at "AUDSYS.DBMS_AUDIT_MGMT", line 2137
ORA-06512: at "AUDSYS.DBMS_AUDIT_MGMT", line 1409
ORA-06512: at line 1
ORA-06512: at "SYS.DBMS_ISCHED", line 242
ORA-06512: at "SYS.DBMS_SCHEDULER", line 566
ORA-06512: at line 2

There is an other issue related to dbms_audit_mgmt.clean_audit_trail in Oracle 12.1 to 18c. The procedure does create a wrong scheduler job. The container_all is not set for the scheduler job, which results in the job running only in the root container. The issue is addressed in Oracle bug 27527173 – ISSUE WITH CREATE PURGE JOB FOR UNIFIED_AUDIT_TRAIL WITH CONTAINER_ALL. A bugfix is available for Oracle 12.1.0.2, 12.2.0.1 and 18.0.0.0. Alternatively you can workaround this issue by manually create a scheduler job to purge the audit trail rather than using dbms_audit_mgmt.clean_audit_trail. The issue is permanently fixed in Oracle 19.0.0.0.

dbms_audit_mgmt or Scheduler Job

Considering the above problems, it seems better to directly create a regular scheduler job for deleting audit trails. All right, this does work as expected, but these kind of jobs will never be visible in cdb_audit_mgmt_cleanup_jobs view. Technically this is not a problem, but it is good practice when audit-related clean up jobs are visible where they should.

The following example creates a regular scheduler job.

BEGIN
   dbms_scheduler.create_job(
      job_name => 'TVD_AUDIT_PURGE_JOB',
      job_type => 'PLSQL_BLOCK',
      job_action => 'BEGIN dbms_audit_mgmt.clean_audit_trail(
         audit_trail_type => dbms_audit_mgmt.audit_trail_unified,
         container => dbms_audit_mgmt.container_current,
         use_last_arch_timestamp => false); END;',
      start_date => trunc(sysdate)+(2/24),
      repeat_interval => 'FREQ=HOURLY;INTERVAL=12',
      enabled => true,
      comments => 'Create an audit purge job for unified audit');
END;
/

Insights when creating audit purge job via dbms_scheduler:

  • Job is not visible in cdb_audit_mgmt_cleanup_jobs
  • Start date can be defined when the job is created
  • Job can be created in any schema, which has the appropriate rights.

The following example does create an audit trail clean up job for unified audit trail using dbms_audit_mgmt and adjusting the start time to 01:00 with dbms_scheduler.

BEGIN
   -- Create regular purge job
   dbms_audit_mgmt.create_purge_job(
      audit_trail_type => dbms_audit_mgmt.audit_trail_unified,
      audit_trail_purge_interval => 12,
      audit_trail_purge_name=> 'tvd_unified_audit_purge_job',
      container => dbms_audit_mgmt.container_current,
      use_last_arch_timestamp => true);
   -- Adapt start date of dbms_audit_mgmt purge job
   dbms_scheduler.set_attribute (
      name => 'tvd_unified_audit_purge_job',
      attribute => 'start_date',
      value => trunc(sysdate) + ( 1 / 24 ) );
END;
/

Insights when creating audit purge job via dbms_audit_mgmt:

  • Job is visible in cdb_audit_mgmt_cleanup_jobs
  • Start date can not be defined when the job is created with dbms_audit_mgmt. The start date has to be changed later using dbms_scheduler.set_attribute. This also applies to other adjustments to the job.
  • For Oracle 18c and 19c the job will be created in the AUDSYS schema. In Oracle 12c and earlier it will be created in the SYS schema.

Audit Window

In the above examples I did set use_last_arch_timestamp=>true. This means that only audit trails older than the archive timestamp will be deleted. The archive timestamp is usually set by the Oracle audit vault agent, when it reads the audit records. But what happens a third party tool like splunk collects the audit data? These tools will generally just read the data without setting a corresponding archive timestamp. Oracle will then never delete old audit records. Therefor it is crucial, that the archive timestamp is set by the tool as soon as the data as been collected. Additionally to this, it is good practice to define an audit window. This is nothing else than set up a job which regularly set an archive timestamp e.g. set the timestamp to sysdate-30. This way all audit records older than 30 days will be removed. The database is thus always nicely tidied up. :-The following example creates such an archive timestamp job. Every 12 hours the archive timestamp is set to sysdate-30.

BEGIN
   dbms_scheduler.create_job(
   job_name =>'tvd_unified_audit_timestamp_job',
   job_type => 'PLSQL_BLOCK',
   job_action => 'BEGIN dbms_audit_mgmt.set_last_archive_timestamp(
      audit_trail_type => dbms_audit_mgmt.audit_trail_unified,
      container => dbms_audit_mgmt.container_current,
      last_archive_time => sysdate - 30); END;',
   start_date => trunc(sysdate)+(2/24),
   repeat_interval => 'FREQ=HOURLY;INTERVAL=12',
   enabled => true,
   comments => 'Create an regularly archive timestamp for unified audit');
END;
/

Conclusion

The administration of audit records works well in Oracle Multitenant environments as well. dbms_audit_mgmt helps with the automatic and manual management of audit trails. Nevertheless, there are a few issues and best practices to consider:

  • Audit data should always be stored in a separate tablespace. However, depending on the Oracle version, there may be issues related to the relocation of the audi trail. For example, not all partitions are moved correctly, LOB and index partitions will continue to be created in the old tablespace. See also bug 27576342dbms_audit_mgmt.set_audit_trail_location does not move lob and index partitions or MOS note 2428624.1 Dbms_Audit_Mgmt.Set_Audit_Trail_Location Does Not Move Lob And Index Partitions
  • Adjusting the partition size or the interval when a new audit partition has to be created, has be done according to the audit quantity and database activity..
  • The different jobs for the clean up as well as the setting of the archive timestamp should run in the same scheme. This increases the transparency. As of Oracle 18c < dbms_audit_mgmt creates the jobs under the user AUDSYS. Older versions usually use the SYS user
  • In Oracle Multitenant environments a central clean up job is the easiest, but makes no sense, depending on the state of the PDB’s it always finishes with an error. Here it is recommended to define one job for each CDB / PDB. In this way, the frequency of the deletion can be individually adapted to the database activity and compliance requirements of the particular PDB.
  • So far we just discussed unified audit. If the database does run in pure unified mode there is no need to define a housekeeping for the legacy audit trails (AUD$, FGA$ etc). Although it is a good practice to define a minimal housekeeping for the legacy audit trail.
  • To define a time window in which audit records are keep in the database is usually a easy method to hold a certain level of audit information in the database. Third party tools like splunk do have enough time to collect the relevant information.
  • For successful database audit concept it is crucial to define the different users and roles who can access or maintain audit information.

References

Some links related to this blog post:

  • Oracle® Database PL/SQL Packages and Types Reference 19c DBMS_AUDIT_MGMT
  • Master Note For Oracle Database Auditing [1299033.1]
  • Dbms_Audit_Mgmt.Set_Audit_Trail_Location Does Not Move Lob And Index Partitions [2428624.1]
  • Bug 27576342 – dbms_audit_mgmt.set_audit_trail_location does not move lob and index partitions
  • Bug 22859443 – CONTAINER_ALL IS IGNORED IN CREATE_PURGE_JOB
  • Patch 27527173 – ISSUE WITH CREATE PURGE JOB FOR UNIFIED_AUDIT_TRAIL WITH CONTAINER_ALL (Patch)

Conferences, Workshops and Events 2019

I am looking forward to a busy second half of 2019. I will be represented with my lectures at various conferences and events. Enclosed a short overview, at which events I will participate:

The comprehensive list is listed under public appearances. I’ll update the events as soon as more information is available. Slides of the presentation will usually be posted on this side.

Oracle CPU / PSU Advisory July 2019

Recently, just in the middle of the summer holidays, Oracle has released the third Critical Patch Advisory for its products. It seems there’s a lot of work going on in Redwood Shore. Oracle has fixed about 319 security vulnerabilities across their products. The Oracle database is relatively prominently represented with 9 security vulnerabilities and a maximal CVSS rating of 9.8. The problem CVE-2018-11058 with such a high CVSS rating is related to Core RDBMS and affects all Oracle releases on various platforms. In addition this vulnerability can also be exploited remotely over the network. 3 of the security bug fixes are for client-only installations. So you have to patch your database servers as well the clients.

Oracle Unified Directory itself is not mentioned in the Oracle Critical Patch Update Advisory. But the MOS note 2385785.1 Information And Bug Listing of Oracle Unified Directory Bundle Patches: 12.2.1.3.x (12cR2PS3) Version does provide information on the latest bundle patch for OUD. Beside this patch, There are updates for Oracle WebLogic and Oracle Java as well (see links below).

The highest CVSS Base Score of vulnerabilities affecting Oracle Database Server is 9.8. The following components are affected:

  • Oracle 11.2 Core RDBMS, Java VM, Oracle Text
  • Oracle 12.1 Core RDBMS, Java VM, Oracle Text
  • Oracle 12.2 Core RDBMS, Java VM, Oracle Text, Spatial
  • Oracle 18c Core RDBMS, Java VM, Oracle Text, Spatial
  • Oracle 19c Core RDBMS, Java VM

Oracle Java VM is not installed by default. It is therefore recommended that you check your database environment to see if it is necessary to apply this critical patch update.

For Oracle Fusion Middleware the situation looks somehow different. The Critical Patch Update includes not less than 33 fixes for vulnerabilities. Several of the vulnerabilities may be remotely exploitable without authentication and are rated with the highest CVSS rating of 9.8.

By the way, I’ve just update my Docker build scripts for Oracle Databases as well Oracle Unified Directory on GitHub to use the latest release updates. Ok, I still haven’t improved the documentation, but at least the build scripts are up to date. 🙂

A few links related to this Critical Patch Update.

SOUG Day 2019 – Oracle Database in Docker

Today I did have the opportunity to give a presentation on Oracle Database in Docker at the SOUG day in Olten. It was a great opportunity to discuss how Oracle database engineering can be simplified using Docker.

Besides the demo the following topics were discussed:

  • Docker images, container and volumes
  • Requirements to setup Oracle database image
  • Build an Oracle database image
  • Discuss the Dockerfile and build scripts
  • Create database containers
  • Use cases for Oracle database in Docker
  • Demo setup Oracle database with Enterprise User Security and Oracle Unified Directory

Combining docker-compose and custom initialisation scripts allow a various number of use cases for Oracle database in Docker. Rapid deployment of Oracle databases for engineering and testing. But is it also suitable for production environments?

The presentation and information related to event:

Some references and links related to this blog post and the presentation:

Oracle Security at Trivadis TechEvent Fall 2018

A few days ago the semi-annual Trivadis TechEvent took place. As always, it was a great IT event where Trivadis employees and customers had the opportunity to exchange and discuss a variety of topics. I had the pleasure to give one lecture about Oracle 18c New Security Features as well one on Oracle Enterprise User Security, Kerberos and Oracle Unified directory. In the meantime, both presentations have been published via SlideShare.

Oracle 18c new Security Features

Abstract: The aim of the presentation is to discuss the various security enhancements which has been introduced with Oracle Release 18c. But which features are worth a closer look at? In what context do the new features and option do make sense? How can security be improved in general with Oracle database 18c? Where does it make sense to invest in additional database options? The aim of this lecture is to answer these and other questions around Oracle Database 18c security.

The demos for this presentation is rather small but also available as GitHub Gist oehrlis/EUS_demos.md.

Oracle EUS, Kerberos, SSL and OUD a guideline

Abstract: The configuration of a central user administration for Oracle DB is basically simple. The challenge is to integrate the different technologies in a meaningful and stable IT environment. Oracle EUS together with OUD, Kerberos or SSL can be implemented autonomously or in combination with existing directory services or an IAM solution. In addition to the technical challenges, other aspects such as users, roles and the security concept in general also play an important role. Within the scope of this lecture, the measures are discussed in order to establish a central user administration for Oracle.

The demos for this presentation is available as GitHub Gist oehrlis/EUS_demos.md.

Oracle Unified Directory Access Log Parsing System ALPS

For one of my customers I had to analyse the log files of Oracle Unified Directory from time to time. In particular the access log file. During my research I came across the MOS note 2042620.1 and the Access Log Parsing System or short ALPS. ALPS is a small and handy tool to analyse OUD and OUDSEE access logs. Written in Java it does run an a couple of different environments. The requirements to run it are rather simple. Just make sure you still have Java 8. 🙂

A few features:

  • Graphical dashboard providing an overview of LDAP operations, connections, operations per seconds and elapsed times.
  • Information on connection with longest etimes
  • Analysis of LDAP operationen e.g. operations over time, most frequent search base, filters, attributes and more.
  • Connections and client adresses.
  • Overview of the result codes that occurred.
  • Log reader to browse through the logfiles.
  • Log replay
  • Load of individual log files, zip archives or entire log directories. Loading multiple access log files allows to simultaneous analysis of access logs from replicated OUD instances. Although this is some kind of a workaround.

The following print screen does show an ALPS dashboard. The access log has been taken from my OUD EUS AD proxy instance, which I did used during my TechEvent presentation on OUD and EUS. Not really a heavily loaded OUD instance.

An other view of the LDAP operations around 09:30. The time I’ve rund the demo and created the instance 🙂

In the context of OUD 12c there are currently some limitations. Oracle changed the default log publisher to the Oracle Loggers using the ODL format. ALPS can not yet handle the new format. If you plan to analyse OUD access or admin logs you still have to use the legacy log publishers. Beside this, a small info message can cause, that your log’s are not recognised by ALPS. OUD 12c add’s the following info to the header of new log files.

This logger has been deprecated. Recommended to use Oracle Loggers
[14/Sep/2018:09:28:23 +0000] CONNECT CONN_POOL conn=0 protocol=LDAP extension=proxy1 from=te2018_oud.postgasse.org/172.17.0.4 to=mneme.postgasse.org/192.168.56.70 s_conn=0
...

Just remove the line starting with This logger has been deprecated... and ALPS is fine again. Beside fixing this issue, I do have a couple of more wishes for the next release of ALPS.

  • Officially support for new ODL format log files.
  • Support for log files from different sources. e.g. from multiple OUD instance in an replicated environment. The current version of ALPS allows to load multiple files, but there is no possibility to distinct the log file source.

Using ALPS to analysis OUD or ODSEE access logs will help to reduce you’re workload, so you have time to enjoy the real alps.

Oracle Unified Directory SSLHandshakeException with Java 1.8.0_181

A couple of days ago I did update my Oracle Unified Directory Docker images with the latest bundle patch for OUD as well the latest java version. With the new Docker images I was about to reproduce a use case from a customer. Everything actually worked at first glance, but after a while I did realise, that my OUD Docker remains in status “unhealthy”. It seems that my status script is not able to get a clear status of the OUD instance. In particular the command “status” does fail.

oracle@oud3:~/ [oud_docker] status --trustall \
-D "cn=Directory Manager" -j $PWD_FILE

Error reading configuration. Details:
javax.naming.CommunicationException: 0.0.0.0:4444 [Root exception is 
javax.net.ssl.SSLHandshakeException: java.security.cert.CertificateException: 
No subject alternative names present]

I’ve tried to drill down the root cause of this issue, but haven’t been successfully. After a hint from a workmate, I took a look into the release notes of Java 1.8.0 update 181. It looks like the latest java 1.8.0 update includes security improvements for LDAP support.

Changes
core-libs/javax.naming
➜ Improve LDAP support
Endpoint identification has been enabled on LDAPS connections.

To improve the robustness of LDAPS (secure LDAP over TLS ) connections, endpoint identification algorithms have been enabled by default.

Note that there may be situations where some applications that were previously able to successfully connect to an LDAPS server may no longer be able to do so. Such applications may, if they deem appropriate, disable endpoint identification using a new system property: com.sun.jndi.ldap.object.disableEndpointIdentification.

Define this system property (or set it to true) to disable endpoint identification algorithms.

JDK-8200666 (not public)

My first intention was to adjust the java.properties and disable endpoint identification just for status. But I was not successful. As a workaround I’ve set the java arguments -Dcom.sun.jndi.ldap.object.disableEndpointIdentification=true with the environment variable OPENDS_JAVA_ARGS. This seems to work as expected.

oracle@oud3:~/ [oud_docker] export OPENDS_JAVA_ARGS=-Dcom.sun.jndi.ldap.object.disableEndpointIdentification=true
oracle@oud3:~/ [oud_docker] status --trustall \
  -D "cn=Directory Manager" -j $PWD_FILE

--- Server Status ---
Server Run Status:        Started
Open Connections:         1

--- Server Details ---
Host Name:                oud3
Administrative Users:     cn=Directory Manager
Installation Path:        /u00/app/oracle/product/fmw12.2.1.3.0/oud
Instance Path:            /u01/instances/oud_docker/OUD
Version:                  Oracle Unified Directory 12.2.1.3.180626
Java Version:             1.8.0_181
Administration Connector: Port 4444 (LDAPS)

--- Connection Handlers ---
Address:Port : Protocol               : State
-------------:------------------------:---------
--           : LDIF                   : Disabled
0.0.0.0:161  : SNMP                   : Disabled
0.0.0.0:1389 : LDAP (allows StartTLS) : Enabled
0.0.0.0:1636 : LDAPS                  : Enabled
0.0.0.0:1689 : JMX                    : Disabled

--- Data Sources ---
Base DN:     cn=OracleContext
Backend ID:  OIDCompatibility
Entries:     34
Replication: Disabled

Base DN:     cn=OracleContext,dc=example,dc=com
Backend ID:  OracleContext0
Entries:     17
Replication: Disabled

Base DN:     cn=OracleSchemaVersion
Backend ID:  OIDCompatibility
Entries:     3
Replication: Disabled

Base DN:     cn=virtual acis
Backend ID:  virtualAcis
Entries:     0
Replication: Disabled

Base DN:     dc=example,dc=com
Backend ID:  userRoot
Entries:     1
Replication: Disabled

This workaround temporarily disable the endpoint identification, although the correct method would be to fix and use it. For now there is a MOS bug related to this issue. This enhance the chance that this will be fixed in a future release. Till then you can easily workaround setting the environment variable.

A few links related to this short blog post:

  • Blog post on Oracle Unified Directory on Docker
  • MOS Bug 28525374 SSLHANDSHAKEEXCEPTION WHEN CREATING OUD INSTANCE WITH JAVA 1.8.0_181
  • MOS Note OUD – How To Configure the Default JVM and Java Arguments with Environment Variables or by Modification of the java.properties File 2220584.1
  • My genuine Docker build scripts for Oracle Unified Directory on GitHub (oehrlis/docker)
  • Oracle Docker build scripts for Oracle Unified Directory on GitHub (oracle/docker-images) yep from me too 🙂