Showing posts with label Oracle 12c Security. Show all posts
Showing posts with label Oracle 12c Security. Show all posts

Wednesday 6 February 2019

Data redaction

Setup

We need to make sure the test user has access to the DBMS_REDACT package.
CONN sys@pdb1 AS SYSDBA
GRANT EXECUTE ON sys.dbms_redact TO test;
The example code in this article requires the following test table.
CONN test/test@pdb1

DROP TABLE payment_details PURGE;

CREATE TABLE payment_details (
  id          NUMBER       NOT NULL,
  customer_id NUMBER       NOT NULL,
  card_no     NUMBER       NOT NULL,
  card_string VARCHAR2(19) NOT NULL,
  expiry_date DATE         NOT NULL,
  sec_code    NUMBER       NOT NULL,
  valid_date  DATE,
  CONSTRAINT payment_details_pk PRIMARY KEY (id)
);

INSERT INTO payment_details VALUES (1, 4000, 1234123412341234, '1234-1234-1234-1234', TRUNC(ADD_MONTHS(SYSDATE,12)), 123, NULL);
INSERT INTO payment_details VALUES (2, 4001, 2345234523452345, '2345-2345-2345-2345', TRUNC(ADD_MONTHS(SYSDATE,12)), 234, NULL);
INSERT INTO payment_details VALUES (3, 4002, 3456345634563456, '3456-3456-3456-3456', TRUNC(ADD_MONTHS(SYSDATE,12)), 345, NULL);
INSERT INTO payment_details VALUES (4, 4003, 4567456745674567, '4567-4567-4567-4567', TRUNC(ADD_MONTHS(SYSDATE,12)), 456, NULL);
INSERT INTO payment_details VALUES (5, 4004, 5678567856785678, '5678-5678-5678-5678', TRUNC(ADD_MONTHS(SYSDATE,12)), 567, NULL);
COMMIT;

ALTER SESSION SET nls_date_format='DD-MON-YYYY';

COLUMN card_no FORMAT 9999999999999999

SELECT *
FROM   payment_details
ORDER BY id;

        ID CUSTOMER_ID           CARD_NO CARD_STRING         EXPIRY_DATE   SEC_CODE VALID_DATE
---------- ----------- ----------------- ------------------- ----------- ---------- -----------
         1        4000  1234123412341234 1234-1234-1234-1234 28-OCT-2015        123
         2        4001  2345234523452345 2345-2345-2345-2345 28-OCT-2015        234
         3        4002  3456345634563456 3456-3456-3456-3456 28-OCT-2015        345
         4        4003  4567456745674567 4567-4567-4567-4567 28-OCT-2015        456
         5        4004  5678567856785678 5678-5678-5678-5678 28-OCT-2015        567

5 rows selected.

SQL>

Add a new Policy

Creating a new redaction policy is done using the ADD_POLICY procedure in the DBMS_REDACT package. A policy is made up of several distinct sections.
  • Identify the object : The OBJECT_SCHEMA, OBJECT_NAME and COLUMN_NAME parameters identify the column to be redacted.
  • Give it a name : The POLICY_NAME parameter assigns a name to the policy.
  • What should happen? : The FUNCTION_TYPE parameter determines the type of redaction that should take place. The allowable values are listed here. Depending on the type of redaction selected, you may be required to specify the FUNCTION_PARAMETERS or various REGEXP_* parameters.
  • When should it happen? : The EXPRESSION parameter determines when the redaction should take place. For example, an expression of "1=1" means the redaction will always take place. Alternatively, situational expressions can be defined using the SYS_CONTEXT function.
The following example is about as simple as it gets. A full redaction policy is placed on the CARD_NO column with an expression of "1=1".
CONN test/test@pdb1

BEGIN
  DBMS_REDACT.add_policy(
    object_schema => 'test',
    object_name   => 'payment_details',
    column_name   => 'card_no',
    policy_name   => 'redact_card_info',
    function_type => DBMS_REDACT.full,
    expression    => '1=1'
  );
END;
/

ALTER SESSION SET nls_date_format='DD-MON-YYYY';
COLUMN card_no FORMAT 9999999999999999

SELECT *
FROM   payment_details
ORDER BY id;

        ID CUSTOMER_ID           CARD_NO CARD_STRING         EXPIRY_DATE   SEC_CODE VALID_DATE
---------- ----------- ----------------- ------------------- ----------- ---------- -----------
         1        4000                 0 1234-1234-1234-1234 28-OCT-2015        123
         2        4001                 0 2345-2345-2345-2345 28-OCT-2015        234
         3        4002                 0 3456-3456-3456-3456 28-OCT-2015        345
         4        4003                 0 4567-4567-4567-4567 28-OCT-2015        456
         5        4004                 0 5678-5678-5678-5678 28-OCT-2015        567

5 rows selected.

SQL>
We can see the CARD_NO column is now redacted to the number "0". The value displayed by full redaction is based on the data type defaults for the DBMS_REDACT.FULL function type. You can see the default values by querying the REDACTION_VALUES_FOR_TYPE_FULL view, shown by the following example that uses the redaction_columns.sql script.
CONN sys@pdb1 AS SYSDBA

@redaction_value_defaults.sql

NUMBER_VALUE BINARY_FLOAT_VALUE BINARY_DOUBLE_VALUE CHAR_VALUE VARCHAR_VA NCHAR_VALU NVARCHAR_V DATE_VALUE           TIMESTAMP_VALUE             TIMESTAMP_WITH_TIME_ZONE_VALUE   BLOB_VALUE           CLOB_VALUE NCLOB_VALU
------------ ------------------ ------------------- ---------- ---------- ---------- ---------- -------------------- --------------------------- -------------------------------- -------------------- ---------- ----------
           0                  0                   0                                             01-JAN-2001 00:00:00 01-JAN-2001 01:00:00.000000 01-JAN-01 01.00.00.000000 +00:00 5B72656461637465645D [redacted] [redacted]

1 row selected.

SQL>
These default values can be altered using the DBMS_REDACT.UPDATE_FULL_REDACTION_VALUES procedure, but you will need to start the instance for the updates to be visible.
Information about existing policies is displayed using the REDACTION_COLUMNS and REDACTION_POLICIES views, used in the redaction_policies.sql and redaction_columns.sql scripts below.
CONN sys@pdb1 AS SYSDBA

@redaction_policies

OBJECT_OWNER         OBJECT_NAME                    POLICY_NAME                    EXPRESSION                     ENABLE  POLICY_DESCRIPTION
-------------------- ------------------------------ ------------------------------ ------------------------------ ------- --------------------
TEST                 PAYMENT_DETAILS                redact_card_info               1=1                            YES

1 row selected.

SQL>


@redaction_columns

OBJECT_OWNER         OBJECT_NAME                    COLUMN_NAME                    FUNCTION_TYPE               FUNCTION_PARAMETERS            REGEXP_PATTERN                 REGEXP_REPLACE_STRING          REGEXP_POSITION REGEXP_OCCURRENCE REGEXP_MAT COLUMN_DESCRIPTION
-------------------- ------------------------------ ------------------------------ --------------------------- ------------------------------ ------------------------------ ------------------------------ --------------- ----------------- ---------- --------------------
TEST                 PAYMENT_DETAILS                CARD_NO                        FULL REDACTION                                                                                                                         0                 0

1 row selected.

SQL>
Other variations on redaction policies are described in the following section. These are equally applicable during redaction policy creation.

Alter an Existing Policy

The ALTER_POLICY procedure allows you to make changes to an existing policy. The type of change being made is controlled using the ACTION parameter. Depending on the action required, the relevant parameters must be specified.
The following example changes the previously created redaction policy so that it uses partial redaction. Notice the FUNCTION_PARAMETERS are now specified to give instructions how the partial redaction should take place. For a numeric data type we specify a comma separated list of three elements (value to redact to, start point, end point), so in this case we want the first 12 characters of the number to always display as "111111111111".
CONN test/test@pdb1

BEGIN
  DBMS_REDACT.alter_policy (
    object_schema       => 'test',
    object_name         => 'payment_details',
    policy_name         => 'redact_card_info',
    action              => DBMS_REDACT.modify_column,
    column_name         => 'card_no',
    function_type       => DBMS_REDACT.partial,
    function_parameters => '1,1,12'
  );
END;
/
   
ALTER SESSION SET nls_date_format='DD-MON-YYYY';
COLUMN card_no FORMAT 9999999999999999

SELECT *
FROM   payment_details
ORDER BY id;

        ID CUSTOMER_ID           CARD_NO CARD_STRING         EXPIRY_DATE   SEC_CODE VALID_DATE
---------- ----------- ----------------- ------------------- ----------- ---------- -----------
         1        4000  1111111111111234 1234-1234-1234-1234 28-OCT-2015        123
         2        4001  1111111111112345 2345-2345-2345-2345 28-OCT-2015        234
         3        4002  1111111111113456 3456-3456-3456-3456 28-OCT-2015        345
         4        4003  1111111111114567 4567-4567-4567-4567 28-OCT-2015        456
         5        4004  1111111111115678 5678-5678-5678-5678 28-OCT-2015        567

5 rows selected.

SQL>
We can add another column to the redaction policy to protect the string representation of the card number.
BEGIN
  DBMS_REDACT.alter_policy (
    object_schema       => 'test',
    object_name         => 'payment_details',
    policy_name         => 'redact_card_info',
    action              => DBMS_REDACT.add_column,
    column_name         => 'card_string',
    function_type       => DBMS_REDACT.partial,
    function_parameters => 'VVVVFVVVVFVVVVFVVVV,VVVV-VVVV-VVVV-VVVV,#,1,12'
  );
END;
/

ALTER SESSION SET nls_date_format='DD-MON-YYYY';
COLUMN card_no FORMAT 9999999999999999

SELECT *
FROM   payment_details
ORDER BY id;

        ID CUSTOMER_ID           CARD_NO CARD_STRING         EXPIRY_DATE   SEC_CODE VALID_DATE
---------- ----------- ----------------- ------------------- ----------- ---------- -----------
         1        4000  1111111111111234 ####-####-####-1234 28-OCT-2015        123
         2        4001  1111111111112345 ####-####-####-2345 28-OCT-2015        234
         3        4002  1111111111113456 ####-####-####-3456 28-OCT-2015        345
         4        4003  1111111111114567 ####-####-####-4567 28-OCT-2015        456
         5        4004  1111111111115678 ####-####-####-5678 28-OCT-2015        567

5 rows selected.

SQL>
The following example redacts the expiry date using partial redaction, converting the day and month values to 1st of January.
BEGIN
  DBMS_REDACT.alter_policy (
    object_schema       => 'test',
    object_name         => 'payment_details',
    policy_name         => 'redact_card_info',
    action              => DBMS_REDACT.add_column,
    column_name         => 'expiry_Date',
    function_type       => DBMS_REDACT.partial,
    function_parameters => 'm1d1Y'
  );
END;
/

ALTER SESSION SET nls_date_format='DD-MON-YYYY';
COLUMN card_no FORMAT 9999999999999999

SELECT *
FROM   payment_details
ORDER BY id;

        ID CUSTOMER_ID           CARD_NO CARD_STRING         EXPIRY_DATE   SEC_CODE VALID_DATE
---------- ----------- ----------------- ------------------- ----------- ---------- -----------
         1        4000  1111111111111234 ####-####-####-1234 01-JAN-2015        123
         2        4001  1111111111112345 ####-####-####-2345 01-JAN-2015        234
         3        4002  1111111111113456 ####-####-####-3456 01-JAN-2015        345
         4        4003  1111111111114567 ####-####-####-4567 01-JAN-2015        456
         5        4004  1111111111115678 ####-####-####-5678 01-JAN-2015        567

5 rows selected.

SQL>
We can also amend the policy so it does not affect the schema owner. The following example uses the SYS_CONTEXT function in the EXPRESSION parameter to determine the current user, making the application of the redaction policy conditional.
CONN test/test@pdb1

BEGIN
  DBMS_REDACT.alter_policy (
    object_schema       => 'test',
    object_name         => 'payment_details',
    policy_name         => 'redact_card_info',
    action              => DBMS_REDACT.modify_expression,
    column_name         => 'card_no',
    expression          => 'SYS_CONTEXT(''USERENV'',''SESSION_USER'') != ''TEST'''
  );
END;
/

-- Test on current user.
ALTER SESSION SET nls_date_format='DD-MON-YYYY';
COLUMN card_no FORMAT 9999999999999999

SELECT *
FROM payment_details
ORDER BY id;

        ID CUSTOMER_ID           CARD_NO CARD_STRING         EXPIRY_DATE   SEC_CODE VALID_DATE
---------- ----------- ----------------- ------------------- ----------- ---------- -----------
         1        4000  1234123412341234 1234-1234-1234-1234 28-OCT-2015        123
         2        4001  2345234523452345 2345-2345-2345-2345 28-OCT-2015        234
         3        4002  3456345634563456 3456-3456-3456-3456 28-OCT-2015        345
         4        4003  4567456745674567 4567-4567-4567-4567 28-OCT-2015        456
         5        4004  5678567856785678 5678-5678-5678-5678 28-OCT-2015        567

5 rows selected.

SQL>


-- Connect to another user and test.
GRANT SELECT ON test.payment_details TO test2;

CONN test2/test2@pdb1

ALTER SESSION SET nls_date_format='DD-MON-YYYY';
COLUMN card_no FORMAT 9999999999999999

SELECT *
FROM   test.payment_details
ORDER BY id;

        ID CUSTOMER_ID           CARD_NO CARD_STRING         EXPIRY_DATE   SEC_CODE VALID_DATE
---------- ----------- ----------------- ------------------- ----------- ---------- -----------
         1        4000  1111111111111234 ####-####-####-1234 01-JAN-2015        123
         2        4001  1111111111112345 ####-####-####-2345 01-JAN-2015        234
         3        4002  1111111111113456 ####-####-####-3456 01-JAN-2015        345
         4        4003  1111111111114567 ####-####-####-4567 01-JAN-2015        456
         5        4004  1111111111115678 ####-####-####-5678 01-JAN-2015        567

5 rows selected.

SQL>
As expected, the redaction policy no longer applies to the TEST user.
Details of the FUNCTION_PARAMETERS formats is available here. There are also predefined Partial Fixed Character Redaction Formats listed here.

Drop an Existing Policy

The DROP_POLICY procedure is used to remove an existing redaction policy. The following example drops the redaction policy and queries the data, showing the redaction is no longer taking place.
CONN test/test@pdb1

BEGIN
  DBMS_REDACT.drop_policy (
    object_schema => 'test',
    object_name   => 'payment_details',
    policy_name   => 'redact_card_info'
  );
END;
/

ALTER SESSION SET nls_date_format='DD-MON-YYYY';
COLUMN card_no FORMAT 9999999999999999

SELECT *
FROM   payment_details
ORDER BY id;

        ID CUSTOMER_ID           CARD_NO EXPIRY_DATE   SEC_CODE VALID_DATE
---------- ----------- ----------------- ----------- ---------- -----------
         1        4000  1234123412341234 27-OCT-2015        123
         2        4001  2345234523452345 27-OCT-2015        234
         3        4002  3456345634563456 27-OCT-2015        345
         4        4003  4567456745674567 27-OCT-2015        456
         5        4004  5678567856785678 27-OCT-2015        567

5 rows selected.

SQL>

Views

As mentioned previously, you can get information about redaction policies using the following views.
You can see examples scripts using these views here (redaction_policies.sql, redaction_columns.sql, redaction_value_defaults.sql).

Additional Information

  • Redaction will not take place if the user has the EXEMPT REDACTION POLICY system privilege.
  • If you try to CREATE TABLE ... AS SELECT (CTAS) against a redacted table you get the following error message.
    ORA-28081: Insufficient privileges - the command references a redacted object.
  • The DATAPUMP_EXP_FULL_DATABASE role includes the EXEMPT REDACTION POLICY system privilege. As this role is granted to the DBA role, DBAs are excluded from redaction policies.
  • Redaction does not apply to the WHERE clause, so inference of the value is still possible for those with SQL access.
  • Enterprise Manager allows you to create and manage custom partial redaction formats, allowing you to build a library of your favourites. This is not part of the core functionality. This functionality is described here.
  • There have been several high profile bugs related to security holes in redaction. Make sure you are patched.

Oracle 12c Security - Overview

Securing enterprise business-critical data is as important for DBAs as database tuning and data protection. Oracle provides comprehensive and powerful security controls/solutions to ensure data privacy and data security which will help with meeting regulatory compliance. Oracle supports the following security controls:
  • Data Masking
  • Advance Security (TDE, Data Redaction)
  • Label security
  • Virtual Private Database (VPD)
  • Fine Grained Auditing (FGA)
  • Data Vault
  • Database auditing
  • Audit Vault
  • Storage/Network authentication
The purpose of this two part article series is to briefly explore some of the most important, and useful Oracle security tools/options/utilities, and the new security features introduced in Oracle Database 12c.

Masking sensitive data

Let me brief you here the need for data masking and how it is achieved in an Oracle database. It is a very common practice to clone production database to a non-production environment for any sort of testing or a new application deployment. If you are working for a financial sector or a high-profile company as an Oracle DBA, it is essential and a common practice to protect the sensitive data using Oracle security solutions or any third party data scrambling solution. Using the Oracle data masking solution, the sensitive data can be secured by replacing it with some fictitious values. This way, an organization can achieve regulatory compliance and avoid data leak or threats.
To implement data masking, you will have to follow the 4-step Oracle data masking pack approach, Find, Assess, Security and Test (F.A.S.T).
  • The first phase (find) involves identifying the sensitive data, for example, credit/debit card information columns, in a table.
  • In the second phase (assess), determine a format of data  masking algorithm to apply in conjunction with IT risk team.
  • The third phase (secure): apply the masking scripts on the sensitive database before handing over the environment.
  • The final phase (test) involves certifying the data masking where the business users validate whether the data has been masked appropriately or requires any further tweaking.
The data can be masked either through an Oracle Enterprise Manager Cloud Control or with Data Pumps. Keep in mind that the OEM Data Masking packs are licensed separately.

Oracle Database Vault

With traditional database auditing control, a DBA can audit/log application user activities. However, the challenging part is to audit and control the privileged user activities in order to restrict and distribute the duties to the individual privileged (sys) users. With Oracle database vault solution you can control administrative users’ data access and can separate/restrict their duties to specific tasks. For example, if an organization has a group of DBAs, you can restrict individual administrative/privileged users and apply the rules individually. For example, you could have one user just to control user management in the database, another user to handle patch & tuning tasks, another user to monitor, backup duties, etc. Also, you can prevent and apply rules to restrict the viewing of sensitive data by the super-users.
With Oracle 12c, the Oracle Database Vault is pre-installed, but doesn’t enabled. To enable the option, either you use Database Configuration Assistant (DBCA) or through SQL command prompt. For more information how to implement this feature, refer to Oracle security documents like Oracle Database Vault Administrator Guide.

Advanced Security

Oracle provides advanced security options to protect enterprise data protection problems. With Oracle Advanced Security solutions in 12c, you can encrypt the data in the database using the Transparent Data Encryption (TDE) option and also on-the-fly data redaction.

Data encryption

Oracle TDE solution provides industry standard encryption capability for an Oracle databases, with which you can ensure only authorized users can read the sensitive data in a database. TDE can be applied at column level or at the entire tablespace level; it is transparent and requires no application modifications. Follow the below steps to configure TDE:
Specify the wallet location and other details in the sqlnet.ora file, as show below:
ENCRYPTION_WALLET_LOCATION =
    (SOURCE = (METHOD = FILE)
      (METHOD_DATA =
       (DIRECTORY = /oracle/DB_WALLET/<db_name>)
      )
    )
Generate a master key:
SQL> alter system set encryption key identified by “welcome”;
This will create a wallet in location specifiied in the DIRECTORY above with the password welcome.
To verify wallet details, run the following SQL query:
 SQL> select * from v$encryption_wallet;
The following demonstrates how to encrypt the data at the column and tablespace level:
SQL> create table card_payment (card_no varchar2(30) encrypt SALT|NOSALT, 
       pdate date, amount number(10,2))

SQL> alter table card_payment modify(card_no encrypt using ‘AES256’ SALT);

SQL> create tablespace data_ts datafile size 100m 
       encryption using ‘AES256’ DEFAULT STORAGE (ENCRYPT);
The following demonstrates how to stop/start/enable/disable the wallet:
SQL> ALTER SYSTEM SET ENCRYTPION WALLET CLOSE;
SQL> ALTER SYSTEM SET ENCRYPTION WALLET OPEN IDENTIFIED BY “welcome”;
syedpic2
Image copyright: Oracle

Data Redaction

With the Data Redaction feature in Oracle 12c, you can now have selective, on-the-fly redaction of important/sensitive data before the SQL result displaying to the end user. Unlike TDE, the data redaction doesn’t change the actual data, it redacts data on-the-fly, i.e, before the SQL query displays the sensitive data to the application user. You can redact data via different methods: full redaction, partial redaction, Random and regular expression.
To configure data redaction, the user must have EXECUTE privileges on the new DBMS_REDACT package.
syedpic2
Image copyright: Oracle


First line of defense – Oracle Database firewall

The Oracle database firewall option prevents database attacks from internal and external accesses by acting as the first line of database defense. It sits on the network layer, transporting data to the application and database layers without any application modification needed.
With its highly accurate SQL-based monitoring ability, all unauthorized and suspicious network traffic to the databases is blocked. When the SQL-based policies are configured and defined, the SQL statements will be analyzed before they’re sent to the database and appropriate action is taken. With the white, black and exception lists support, you can define a set of SQL statements that the firewall can see, this can include users, schemas and SQL statements that you need to prevent attacks from reaching the database.
The following image depicts the overall Audit Vault and Database firewall architecture and its functionality:
whatsnewin12c
Image courtesy: Oracle documentation

Oracle Secure Backups (OSB)

Although several third-party vendor-supported Tape-Based backup solutions exist, Oracle Secure Backups (OSB) provides backup encryption, protection and centralized backup solutions. The OSB has built-in support to Recovery Manager (RMAN), protection to the file system on UNIX, WINDOWS and Linux hosts, centralized backup management and its cloud module supports backup on the cloud.  The following are the key benefits of OSB:
  • Centralized tape backup management
  • Backups over the cloud
  • Supports Exadata backups
  • Encrypts backups and secure backup data
  • Provides enterprise data protection

Network encryption and storage authentication

In my previous article, I explained how to mask sensitive data, data redaction, controlling super sys privileges, data encryption etc. This segment will cover how to apply security controls in network and storage layers.
As part of storage authentication, Oracle provides the following industry standard authentication methods:
  • Kerberos: enables single sign-on and centralized authentication capabilities to the Oracle users.
  • RAIDUS: provides remote authentication and access with a client/server protocol in a client/server network environment using the smart cards and token cards mechanism.
  • Secure Socket Layer (SSL): an industry standard protocol which supports authentication, data integrity and data encryption. Oracle uses the SSL protocol for secure client/server communication, SSL can also be configured to provide server only, client only or both authentication.
To prevent unauthorized users from viewing the plain text data that’s been sent over the network, you will have to apply encryption to network data. This protects against Data modification and Replay attach attacks.
Oracle Net Manager offers network encryption configuration options on the client and server. You can choose one of the four (REJECTED, ACCEPTED, REQUESTED and REQUIRED) listed options from the Checksum Level list. Also, the sqlnet.ora file must contain following entries:

Oracle database 12c new security features

It’s time to review a few selective Oracle database 12c enhancements and additions. Here is the list of new features:
  • With Oracle 12c, a new schema, AUDSYS, is solely used to store the unified audit trail records in the table.  Typically, audit records are first kept in the SGA queue and are then periodically written to the AUDSYS schema audit table in the SYSAUX tablespace. This prevents writing the records immediately to the table and improves overall audit trail process. However, you have the ability to overwrite or define the rules on how the audit records should be written, immediately or queued in the SGA.
  • RESOURCE role no longer grants UNLIMITED TABLESPACE privilege
  • SELECT ANY DICTIONARY no longer provides access to the SYS and DICTIONARY tables
  • Unified Audit trail for all individual components: SYS.ADU$, fine-grained auditing, Oracle Database vault, Oracle Label Security etc
  • Separate duties of Audit administration
  • Enhanced password verification functionality

Common database security practices

It is not a good idea to   comprise on data security, at the very least businesses should apply the basic level of database security compliance. According to Verizon’s security survey, 97% security breaches are preventable with a very basic level of security controls. The following are a few security guidelines, in no particular order, which are common basic security practices you should consider adopting in your production environments:
  • Apply regular PSU patches
  • Enable basic level and common database auditing parameters:  AUDIT_TRAIL, AUDIT_SYS_OPERATIONS, AUDIT_FILE_DEST
  • Limit or grant only required privileges to the database users
  • Contain super users and revoke all unnecessary privileges from the PUBLIC role
  • Lock down and change the default passwords to the pre-defined, non-administrative database users
  • Avoid using the default 1521 port
  • Enforce password management profiles, such as password reuse max, life time, password life time etc
  • Secure batch jobs
  • Encrypt sensitive data
  • Control data access
  • Maintain SYS.AUD$ table
  • Audit and track all important database changes

ORA-01031: insufficient privileges DB Vault

SQL> alter system set max_dump_file_size=10000 scope=spfile;
alter system set max_dump_file_size=10000 scope=spfile
*
ERROR at line 1:
ORA-01031: insufficient privileges
In  Database Vault enabled databases, SYS user is not able to change certain  parameters using and ALTER SYSTEM command.
The commands are failing :
Database Vault prohibits the dynamic change of certain parameters. The dynamic change of the following parameters is blocked intentionally:
dump datafile
DB_CREATE_FILE_DEST
DB_CREATE_ONLINE_LOG_DEST_1
db_recovery_file_dest
LOG_ARCHIVE_DEST_%
log_archive_dest_state_%
background_dump_dest
core_dump_dest
user_dump_dest
audit_file_dest
db_recovery_file_dest
DB_RECOVERY_FILE_DEST_SIZE
standby_archive_dest
recyclebin=on
control_files
optimizer_secure_view_merging = true
utl_file_dir
plsql_debug=true
audit_sys_operations = false
audit_trail
remote_os_roles
os_roles
job_queue_processes
sql92_security
So there are two ways you can solve it
Workaround I:
Disable the  ALTER SYSTEM command rule.
Login to the Database Vault Console -> select command rule -> select ALTER SYSTEM command -> Edit and set it disable.
select * from dvsys.DBA_DV_COMMAND_RULE;
COMMAND                        RULE_SET_NAME                                                                              OBJECT_OWNER    OBJECT_NAME                         E PRIVILEGE_SCOPE
—————————— —————————————————————————————— ————— ———————————– – —————
CREATE USER                    Can Maintain Accounts/Profiles                                                             %               %                                   Y
DROP USER                      Can Maintain Accounts/Profiles                                                             %               %                                   Y
CREATE PROFILE                 Can Maintain Accounts/Profiles                                                             %               %                                   Y
ALTER PROFILE                  Can Maintain Accounts/Profiles                                                             %               %                                   Y
DROP PROFILE                   Can Maintain Accounts/Profiles                                                             %               %                                   Y
ALTER USER                     Can Maintain Own Account                                                                   %               %                                   Y
CHANGE PASSWORD                Can Maintain Own Account                                                                   %               %                                   Y
ALTER SYSTEM                   Allow Fine Grained Control of System Parameters                                            %               %                                   Y
begin  DVSYS.DBMS_MACADM.UPDATE_COMMAND_RULE
(command=> ‘ALTER SYSTEM’,
rule_set_name   => ‘Allow Fine Grained Control of System Parameters’,
object_owner    => ‘%’,
object_name     => ‘%’,
enabled         => ‘N’);
end;
/
Change the parameter
alter system set max_dump_file_size=10000 scope=spfile;
begin  DVSYS.DBMS_MACADM.UPDATE_COMMAND_RULE
(command=> ‘ALTER SYSTEM’,
rule_set_name   => ‘Allow Fine Grained Control of System Parameters’,
object_owner    => ‘%’,
object_name     => ‘%’,
enabled         => ‘Y’);
end;
/
select * from dvsys.DBA_DV_COMMAND_RULE;
Workaround II:
Manually edit init.ora and change the parameters. And restart the database with this init.ora file with the command STARTUP PFILE=<path/name of the pfile>

Oracle Database Vault

Oracle Database Vault provides powerful security controls to help protect application data from unauthorized access and comply with privacy and regulatory requirements.  Recently, we had a customer purchase the Database Vault option for their environment and was looking for a demonstration of the product to help them get started.  This blog entry is a brief introduction on Database Vault that demonstrates how to protect sensitive data from abuse by privileged users like the DBA.
Database Vault protects sensitive data by using Realms. A database Realm is created and contains one or more objects (Tables, Indexes,…) from one or more schemas.  Users are authorized directly by the DV_OWNER and the schema owner by granting access.  Mandatory Realms only allow users who are directly authorized by DV_OWNER to access the protected objects (not schema owners or anyone granted access by the schema owner).  Administrative users can not access objects unless specifically authorized.
database_vault-1
(Courtesy Oracle America)
In this post, I will demonstrate how to configure Database Vault and demonstrate protecting data from the SYSDBA user.  For this post, I’m using Enterprise Edition Database 12c (12.1.0.2) with Oracle Multi-tenancy on a Windows machine.

Oracle Database Vault Configuration

Database Vault is installed when you perform a default installation of Oracle Database. After the database is installed, you must register Oracle Database Vault and then enable the Oracle Database Vault Account Manager user account. If Oracle Label Security is not enabled, then the registration process enables it as well as Database Vault.
Register Database Vault:
  • Log in as SYS user with SYSDBA privileges
  • Check if Oracle Database Vault has already been enabled. The PARAMETER column is case sensitive.SELECT value FROM V$OPTION WHERE parameter = ‘Oracle Database Vault’; If TRUE, then Database Vault is registered.  If FALSE, then Database Vault registration is required as follow.
Register Database Vault with a common user to manage the CDB Root Container Database:
Create accounts for the Database Vault Owner and Account Manager (DV_OWNER and DV_ACCTMGR Roles)
sys@ORCL> grant create session, set container to c##dbv_owner_root identified by oracle_4U container=all;
Grant succeeded.
sys@ORCL> grant create session, set container to c##dbv_acctmgr_root identified by oracle_4U container=all;
Grant succeeded.
Configure Database Vault user accounts
sys@ORCL> begin
   2  dvsys.configure_dv (
   3    dvowner_uname => 'c##dbv_owner_root',
   4    dvacctmgr_uname => 'c##dbv_acctmgr_root');
   5  end;
   6  /
PL/SQL procedure successfully completed.
Recompile Invalid Database Objects
sys@ORCL> @?/rdbms/admin/utlrp.sql
--
-- Cut for brevity
--
PL/SQL procedure successfully completed.
sys@ORCL>
Just a note – Oracle recommends creating Backup Accounts for the DV Owner and Account Manager Roles. (e.g. c##dbv_owner_root_bkup and c##dbv_acctmgr_root_bkup)
Connect to Root Container as Database Vault Owner and Enable Database Vault
sys@ORCL> connect c##dbv_owner_root/oracle_4U
Connected.
c##dbv_owner_root@ORCL> exec dbms_macadm.enable_dv;
PL/SQL procedure successfully completed.
c##dbv_owner_root@ORCL>
Connect to Root Container as SYSDBA and Bounce the Database.
c##dbv_owner_root@ORCL> connect / as sysdba
Connected.
ys@ORCL> shutdown immediate;
Database closed.
Database dismounted.
ORACLE instance shut down.

sys@ORCL> startup
ORACLE instance started.
Total System Global Area 2550136832 bytes
Fixed Size                  3048872 bytes
Variable Size             671091288 bytes
Database Buffers         1862270976 bytes
Redo Buffers               13725696 bytes
Database mounted.
Database opened.
sys@ORCL>
Register Database Vault common user to manage specific PDBs
Grant Privileges for Database Vault Owner and Account Manager in the Pluggable Database (PDB1)
sys@ORCL> connect sys/oracle_4U@//localhost:1521/pdb1.us.oracle.com as sysdba
Connected.
sys@PDB1> grant create session, set container to c##dbv_owner_root container = current;
Grant succeeded.
sys@PDB1> grant create session, set container to c##dbv_acctmgr_root container = current;
Grant succeeded.
Configure Database Vault user accounts for PDB
sys@PDB1> begin
  2  dvsys.configure_dv (
  3     dvowner_uname => 'c##dbv_owner_root',
  4     dvacctmgr_uname => 'c##dbv_acctmgr_root');
  5  end;
  6  /
PL/SQL procedure successfully completed.
Recompile Invalid Database Objects in PDB
sys@PDB1> @?/rdbms/admin/utlrp.sql
--
-- Cut for brevity
--
PL/SQL procedure successfully completed.
Note:  In a multitenant environment, you must register Oracle Database Vault in the root first, then in the PDBs.  If you try to register in a PDB first, then an ORA-47503: Database Vault is not enabled on CDB$ROOT error appears.
Connect to PDB Container as Database Vault Owner and Enable Database Vault
sys@PDB1> connect c##dbv_owner_root/oracle_4U@//localhost:1521/pdb1.us.oracle.com
Connected.
c##dbv_owner_root@PDB1> exec dbms_macadm.enable_dv;
PL/SQL procedure successfully completed.
Connect to Root Container as SYSDBA and Bounce the Pluggable Database
c##dbv_owner_root@PDB1> connect / as sysdba
Connected.
sys@ORCL> alter pluggable database pdb1 close immediate;
Pluggable database altered.
sys@ORCL> alter pluggable database pdb1 open;
Pluggable database altered.
sys@ORCL>

Verify Database Vault is Configured and Enabled

The V$OPTION view and the DVSYS.DBA_DV_STATUS and DBA_OLS_STATUS data dictionary views verify if Oracle Database Vault is configured and enable.
Query the V$OPTION view to verify Database Vault and Label Security are configured
sys@ORCL> connect sys/oracle_4U@//localhost:1521/pdb1.us.oracle.com as sysdba
Connected.
sys@PDB1> select value from v$option where parameter = 'Oracle Database Vault';
VALUE
----------------------------------------------------------------
TRUE
sys@PDB1> select value from v$option where parameter = 'Oracle Label Security';
VALUE
----------------------------------------------------------------
TRUE
Query the DVSYS.DBA_DV_STATUS view to verify Database Vault status
sys@PDB1> select * from dvsys.dba_dv_status;
NAME                STATUS
------------------- ---------------------------------
DV_CONFIGURE_STATUS TRUE
DV_ENABLE_STATUS    TRUE

Database Vault Demonstration:

The V$OPTION view and the DVSYS.DBA_DV_STATUS and DBA_OLS_STATUS data dictionary views verify if Oracle Database Vault is configured and enabled.
Enable the Scott account and grant access to the Order Entry Customer’s table
idle> connect sys/oracle_4U@//localhost:1521/pdb1.us.oracle.com as sysdba
Connected.
sys@PDB1> alter user scott identified by oracle_4U account unlock;
User altered.
sys@PDB1> alter user oe identified by oracle_4U account unlock;
User altered.
sys@PDB1> connect oe/oracle_4U@//localhost:1521/pdb1.us.oracle.com
Connected.
oe@PDB1> grant select on customers to scott;
Grant succeeded.
Query the OE.CUSTOMERS table as SYS and SCOTT
At this stage, both SYS and SCOTT have select privileges on the CUSTOMERS table because SYS has Administrative privileges and SCOTT has a direct grant.
oe@PDB1> connect sys/oracle_4U@//localhost:1521/pdb1.us.oracle.com as sysdba
Connected.
sys@PDB1> select count(*) from oe.customers;
  COUNT(*)
----------
       319
sys@PDB1> connect scott/oracle_4U@//localhost:1521/pdb1.us.oracle.com
Connected.
scott@PDB1> select count(*) from oe.customers;
  COUNT(*)
----------
       319
Create a Realm to Protect the OE.CUSTOMERS Table
I’m sorry – We have to do this the hard way, I don’t have Enterprise Manager Cloud Control on my Laptop
scott@PDB1> connect c##dbv_owner_root/oracle_4U@//localhost:1521/pdb1.us.oracle.com

Connected.

c##dbv_owner_root@PDB1> begin
  2  DBMS_MACADM.CREATE_REALM (
  3     realm_name => 'OE Protections',
  4     description => 'Realm to protect OE schema',
  5     enabled => DBMS_MACUTL.G_YES,
  6     audit_options => DBMS_MACUTL.G_REALM_AUDIT_FAIL,
  7     realm_type => 1);
  8  end;
  9  /
PL/SQL procedure successfully completed.
Add OE tables to Realm for protection
c##dbv_owner_root@PDB1> begin
  2  DBMS_MACADM.ADD_OBJECT_TO_REALM(
  3     realm_name => 'OE Protections',
  4     object_owner => 'OE',
  5     object_name => '%',
  6     object_type => 'TABLE');
  7  end;
  8  /
PL/SQL procedure successfully completed.
c##dbv_owner_root@PDB1>
Create Realm Authorizations for OE and Scott
c##dbv_owner_root@PDB1> begin
  2  DBMS_MACADM.ADD_AUTH_TO_REALM(
  3     realm_name => 'OE Protections',
  4     grantee => 'OE',
  5     auth_options => DBMS_MACUTL.G_REALM_AUTH_OWNER);
  6  end;
  7  /

c##dbv_owner_root@PDB1> begin
  2  dbms_macadm.add_auth_to_realm(
  3     realm_name => 'OE Protections',
  4     grantee => 'SCOTT',
  5     auth_options => DBMS_MACUTL.G_REALM_AUTH_PARTICIPANT);
  6  end;
  7  /
PL/SQL procedure successfully completed.
Test our Database Vault protections for the OE Tables
scott@PDB1> connect oe/oracle_4U@//localhost:1521/pdb1.us.oracle.com
Connected.
oe@PDB1> select table_name from user_tables;
TABLE_NAME
----------------------------------------------------------------------------------------------------
CUSTOMERS
WAREHOUSES
ORDER_ITEMS
ORDERS
INVENTORIES
PRODUCT_INFORMATION
PRODUCT_DESCRIPTIONS
PROMOTIONS
PRODUCT_REF_LIST_NESTEDTAB
SUBCATEGORY_REF_LIST_NESTEDTAB
10 rows selected.

oe@PDB1> select count(*) from customers;
  COUNT(*)
----------
       319

oe@PDB1> select count(*) from warehouses;
  COUNT(*)
----------
         9
This just shows that the Owner of the Realm has access to their tables.
idle> connect scott/oracle_4U@//localhost:1521/pdb1.us.oracle.com
Connected.
scott@PDB1> select count(*) from oe.customers;
  COUNT(*)
----------
       319

scott@PDB1> select count(*) from oe.warehouses;
select count(*) from oe.warehouses
                        *
ERROR at line 1:
ORA-00942: table or view does not exist
This shows that Scott has access to the customers table in the Realm but not the warehouses table.  While the Realm we configured contains all of OE’s tables, any user in the Realm like Scott still needs to have appropriate privileges to the objects in the Realm.
scott@PDB1> connect sys/oracle_4U@//localhost:1521/pdb1.us.oracle.com as sysdba
Connected.
sys@PDB1> select count(*) from oe.customers;
select count(*) from oe.customers
                        *
ERROR at line 1:
ORA-01031: insufficient privileges

sys@PDB1> select count(*) from oe.warehouses;
select count(*) from oe.warehouses
                        *
ERROR at line 1:
ORA-01031: insufficient privileges
Finally, this shows that SYS with SYSDBA privileges does not have authority to view data that is in the Realm!  As you can see, using Database Vault helps prevent the “insider attack”.

References:

Database Vault Administrator’s Guide – https://docs.oracle.com/database/121/DVADM/toc.htm
Database 2 Day + Security Guide – https://docs.oracle.com/database/121/TDPSG/toc.htm
Oracle Sample Schemas on GitHub – https://github.com/oracle/db-sample-schemas

Introduction to Oracle Label Security 12c

In the previous post, we looked at how to support fine-grained access control of tables using Oracle VPD technology. In this post, we are going to have a quick look at another technology with similar purpose called OLS (Oracle Label Security) which is built on top of VPD.

A commonly raised question is that if both VPD and OLS serve the same purpose, why do we need OLS? While VPD is a generic solution, OLS addresses a very specific and common use case in many government and corporate environment - allow access to data based on the need to know basis. Unlike VPD which requires administrator to write PL/SQL code for the policy function, OLS requires no programming. You can think of OLS as a out-of-the-box VPD with built-in policies.

What exact does OLS address?
Many government and business organizations, label their data using different sensitivity levels, such as top secret (TS), secret (S), confidential (C), unclassified (UC), depending on the perceived risk levels so that they can selectively protect most valuable assets of the organization. Users are assigned different clearance levels based on their job functions and seniority. Each user is allowed to access only those data records with the sensitivity level no more than the clearance level of the user. For example, if user tom is assigned the clearance level C, he can access data records with the sensitive levels C or UC only. He is not allowed to access data records with sensitivity levels greater than C, that is, TS or S.

How is OLS enforced?
OLS is a security in depth feature, meaning that users must first have the DAC table privileges necessary to access the OLS protected rows. On top that, there could be VPD policies that may be enforced as well. The following diagram shows the order of enforcement. (Not shown in the diagram: a database vault policy may be enforced on the table as well.)

Figure: OLS Enforcement

How does OLS work?
The following diagram shows the example that we will walk through later in this post. The table flight has data of different sensitivity level and based users' clearance levels they see different set of records even though they issue the same query. Row level access control is enforced transparent to end users.

Figure: OLS Example

How are row sensitivity labels assigned?
When a new record is inserted to an OLS protected table, there are three ways to assign sensitivity label to each row:
- Explicit specify a label (which should be between the maximum and minimum clearance of the user)
- Select 'LABEL_DEFAULT' option when creating the policy and the sessions ROW_LABEL value will be used automatically when inserting records
- Create a labeling function and specify when applying the policy on the table. This will automatically call your labeling function when inserting records

How are user clearance levels decided?
If it is a database user, SA_USER_ADMIN.SET_LEVELS procedure assigns a default level to each user. At the time of login user will have this clearance level. In a session, user can change the clearance level to a level less than the maximum level granted using SA_SESSION.SET_LABEL procedure.

If it is an application user who does not have a database user, SA_SESSION.SET_ACCESS_PROFILE procedure allows to set an existing database user's profile to be the profile of the application user.

A working example:
SQL> -- First do the test setup
SQL> conn sys/password@cdb1_pdb1 as sysdba
Connected.
SQL> create user gov identified by gov;
User created.

SQL> create user bob identified by bob;
User created.

SQL> create user tim identified by tim;
User created.

SQL> grant create session to gov, bob, tim;
Grant succeeded.

SQL> grant create table, unlimited tablespace to gov;
Grant succeeded.

SQL> conn gov/gov@cdb1_pdb1
Connected.
SQL> create table flight(flight# number, destination varchar2(100), payload varchar2(100));
Table created.

SQL> grant select, insert on flight to bob, tim, scott;
Grant succeeded.

SQL> -- insert test data
SQL> insert into flight values (505, 'Iraq', 'Weapon');
1 row created.
SQL> insert into flight values (506, 'Canada', 'Charcoal');
1 row created.
SQL> insert into flight values (706, 'Japan', 'Battery');
1 row created.
SQL> insert into flight values (501, 'Syria', 'Weapon');
1 row created.
SQL> insert into flight values (508, 'Israel', 'Jets');
1 row created.
SQL> insert into flight values (509, 'India', 'Aid');
1 row created.

SQL> 
SQL> conn lbacsys/password@cdb1_pdb1
Connected.
SQL> BEGIN
  2  -- Create OLS Policy
  3  -- Notice that the default_options is set to no_control to disable the policy
  4  -- in order add labels to the existing data items
  5  SA_SYSDBA.CREATE_POLICY(
  6    policy_name => 'ols_pol1',
  7    column_name => 'lb_col',
  8    default_options => 'no_control'
  9  );
 10  
 11  -- Create label component levels
 12  -- TOP_SECRET has the highest level of access
 13  SA_COMPONENTS.CREATE_LEVEL(
 14    policy_name => 'ols_pol1',
 15    level_num   => 4,
 16    short_name => 'TS',
 17    long_name   => 'top_secret'
 18  );
 19  
 20  
 21  SA_COMPONENTS.CREATE_LEVEL(
 22    policy_name => 'ols_pol1',
 23    level_num   => 3,
 24    short_name => 'S',
 25    long_name   => 'secret'
 26  );
 27  
 28  SA_COMPONENTS.CREATE_LEVEL(
 29    policy_name => 'ols_pol1',
 30    level_num   => 2,
 31    short_name => 'C',
 32    long_name   => 'confidential'
 33  );
 34  
 35  SA_COMPONENTS.CREATE_LEVEL(
 36    policy_name => 'ols_pol1',
 37    level_num   => 1,
 38    short_name => 'UC',
 39    long_name   => 'unclassified'
 40  );
 41  
 42  -- Create data labels
 43  SA_LABEL_ADMIN.CREATE_LABEL(
 44    policy_name => 'ols_pol1',
 45    label_tag   => 40,
 46    label_value => 'TS',
 47    data_label  => TRUE
 48  );
 49  
 50  SA_LABEL_ADMIN.CREATE_LABEL(
 51    policy_name => 'ols_pol1',
 52    label_tag   => 30,
 53    label_value => 'S',
 54    data_label  => TRUE
 55  );
 56  
 57  SA_LABEL_ADMIN.CREATE_LABEL(
 58    policy_name => 'ols_pol1',
 59    label_tag   => 20,
 60    label_value => 'C',
 61    data_label  => TRUE
 62  );
 63  
 64  SA_LABEL_ADMIN.CREATE_LABEL(
 65    policy_name => 'ols_pol1',
 66    label_tag   => 10,
 67    label_value => 'UC',
 68    data_label  => TRUE
 69  );
 70  
 71  -- Apply access_pol policy on table gov.flight
 72  SA_POLICY_ADMIN.APPLY_TABLE_POLICY(
 73    policy_name       => 'ols_pol1',
 74    schema_name       => 'gov',
 75    table_name        => 'flight',
 76    table_options  => null,
 77    label_function => null,
 78    predicate         => null
 79  );
 80  
 81  -- Add user authorizations (i.e. clearance levels)
 82  SA_USER_ADMIN.SET_LEVELS(
 83    policy_name => 'ols_pol1',
 84    user_name   => 'bob',
 85    max_level   => 'S',
 86    min_level   => 'UC',
 87    def_level   => 'S',
 88    row_level   => 'S'
 89  );
 90  
 91  SA_USER_ADMIN.SET_LEVELS(
 92    policy_name => 'ols_pol1',
 93    user_name   => 'tim',
 94    max_level   => 'UC',
 95    min_level   => 'UC',
 96    def_level   => 'UC',
 97    row_level   => 'UC'
 98  );
 99  END;
100  /
PL/SQL procedure successfully completed.

SQL> 
SQL> conn system/password@cdb1_pdb1
Connected.
SQL> -- Add labels to rows
SQL> update gov.flight set lb_col = char_to_label('ols_pol1', 'TS') where payload in ('Weapon');
2 rows updated.

SQL> update gov.flight set lb_col = char_to_label('ols_pol1', 'S') where payload in ('Jets');
1 row updated.

SQL> update gov.flight set lb_col = char_to_label('ols_pol1', 'C') where payload in ('Battery');
1 row updated.

SQL> update gov.flight set lb_col = char_to_label('ols_pol1', 'UC') where payload in ('Charcoal', 'Aid');
2 rows updated.

SQL> 
SQL> conn lbacsys/password@cdb1_pdb1
Connected.
SQL> BEGIN
  2  -- Now we change the policy to enfoce on read by first altering the policy
  3  -- and then removing and applying the policy again
  4  SA_SYSDBA.ALTER_POLICY(
  5    policy_name => 'ols_pol1',
  6    default_options => 'read_control, label_default'
  7  );
  8  
  9  SA_POLICY_ADMIN.REMOVE_TABLE_POLICY(
 10    policy_name => 'ols_pol1',
 11    schema_name => 'gov',
 12    table_name  => 'flight',
 13    drop_column => false
 14  );
 15  
 16  SA_POLICY_ADMIN.APPLY_TABLE_POLICY(
 17    policy_name => 'ols_pol1',
 18    schema_name => 'gov',
 19    table_name  => 'flight'
 20  );
 21  END;
 22  /

PL/SQL procedure successfully completed.

SQL> -- This is to demonstrate OLS can be bypassed with
SQL> -- special privileges. Here, scott is granted to read
SQL> -- the OLS protected table without any specific 
SQL> -- clearance level  
SQL> BEGIN
  2  SA_USER_ADMIN.SET_USER_PRIVS(
  3    policy_name  => 'ols_pol1',
  4    user_name    => 'scott',
  5    privileges   => 'READ'
  6  );
  7  END;
  8  /
PL/SQL procedure successfully completed.

SQL> column flight# format 9999;
SQL> column destination format a15;
SQL> column payload format a15;
SQL> 
SQL> 
SQL> conn bob/bob@cdb1_pdb1
Connected.
SQL> -- The following demonstrates how to change the row label
SQL> -- of the current session so that that label is used
SQL> -- when bob is inserting new records to gov.flight. 
SQL> select SA_SESSION.ROW_LABEL('ols_pol1') from DUAL;

SA_SESSION.ROW_LABEL('OLS_POL1')
--------------------------------
S

SQL> select SA_SESSION.LABEL('ols_pol1') from DUAL;

SA_SESSION.LABEL('OLS_POL1')
----------------------------
S

SQL> 
SQL> BEGIN
  2  SA_SESSION.SET_ROW_LABEL(
  3    policy_name  => 'ols_pol1',
  4    label        => 'UC'
  5  );
  6  END;
  7  /
PL/SQL procedure successfully completed.

SQL> -- The label of this row is automatically assigned as UC
SQL> insert into gov.flight (flight#, destination, payload) values (599, 'Peru', 'Medicine');
1 row created.

SQL> select flight#, destination, payload from gov.flight;

FLIGHT# DESTINATION     PAYLOAD
------- --------------- ---------------
    506 Canada          Charcoal
    706 Japan           Battery
    508 Israel          Jets
    509 India           Aid
    599 Peru            Medicine

SQL> 
SQL> conn tim/tim@cdb1_pdb1
Connected.
SQL> select flight#, destination, payload from gov.flight;

FLIGHT# DESTINATION     PAYLOAD
------- --------------- ---------------
    506 Canada          Charcoal
    509 India           Aid
    599 Peru            Medicine

SQL> 
SQL> conn scott/tiger@cdb1_pdb1
Connected.
SQL> select * from gov.flight;

FLIGHT# DESTINATION     PAYLOAD             LB_COL
------- --------------- --------------- ----------
    505 Iraq            Weapon                  40
    506 Canada          Charcoal                10
    706 Japan           Battery                 20
    501 Syria           Weapon                  40
    508 Israel          Jets                    30
    509 India           Aid                     10
    599 Peru            Medicine                10

7 rows selected.
SQL> -- Now we do the clean up
SQL> conn lbacsys/password@cdb1_pdb1
Connected.
SQL> BEGIN
  2  SA_SYSDBA.DROP_POLICY(
  3    policy_name => 'ols_pol1'
  4  );
  5  END;
  6  /
PL/SQL procedure successfully completed.

SQL> 
SQL> conn sys/password@cdb1_pdb1 as sysdba
Connected.
SQL> drop user gov cascade;
User dropped.
SQL> drop user bob cascade;
User dropped.
SQL> drop user tim cascade;
User dropped.
There is more to OLS:
I only scratched the surface of OLS. A data label is actually consists of three components:

1. Sensitivity level - has an ordering relationship
2. Compartment (optional) - used to segregate data within a level
3. Group (optional) - used to organizationally segregate data within a level - has a hierarchical relationship

In order for a user to able to access a labeled record, the following conditions must be satisfied:
a. User's clearance level should be at least as high as the the data record's sensitivity level
b. User has all the compartments associated with the data record
c. User belongs to one of the groups associated with the data record or a parent group of one of the associated groups

With the quick understanding of the OLS technology, I encourage you to look the Oracle documentation to learn more about OLS and its new powerful features.