In banking, a security breach doesn't just cost money — it costs trust. And trust, once lost, takes a decade to rebuild.
In This Chapter
- Learning Objectives
- Opening: The Cost of a Breach
- 19.1 DB2 Security Architecture Overview
- 19.2 [z/OS] Authentication with RACF, ACF2, and Top Secret
- 19.3 [LUW] Authentication
- 19.4 Privileges — The Granular Permission Model
- 19.5 Roles — Simplifying Privilege Management
- 19.6 Administrative Authorities
- 19.7 Row and Column Access Control (RCAC)
- 19.8 Trusted Contexts and Secure Connections
- 19.9 Audit Policies
- 19.10 Encryption — Data at Rest and In Transit
- 19.11 Compliance Patterns
- 19.12 The Meridian National Bank Security Model
- Spaced Review: Chapters 4, 12, and 17
- Summary
Chapter 19: Security and Authorization — Authentication, Privileges, Roles, Row-Level Security, and Audit
Learning Objectives
By the end of this chapter, you will be able to:
- Explain DB2's authentication and authorization architecture, including the boundary between external authentication and internal authorization
- Grant and revoke privileges at the database, schema, table, and column levels using precise SQL syntax
- Implement role-based access control to simplify privilege management across large user populations
- Configure row-level and column-level security using DB2's Row and Column Access Control (RCAC) features
- Set up audit policies that satisfy PCI-DSS, HIPAA, SOX, and GDPR compliance requirements
- Design the complete Meridian National Bank security model — from authentication through audit
Opening: The Cost of a Breach
In banking, a security breach doesn't just cost money — it costs trust. And trust, once lost, takes a decade to rebuild.
Consider what happened in 2019 when a major financial institution disclosed that a misconfigured access control rule exposed over 100 million customer records. The direct costs — regulatory fines, legal settlements, remediation — exceeded $300 million. But the indirect costs were worse: customer attrition, reputational damage, and an erosion of confidence that persisted for years. The root cause was not some exotic zero-day exploit. It was a privilege escalation through a misconfigured role, the kind of mistake that a disciplined security model would have caught before it reached production.
DB2 provides one of the most granular, auditable, and mature security frameworks of any database platform. On z/OS, it integrates with RACF — the same external security manager that protects the most sensitive government and financial systems on earth. On LUW, it supports operating system authentication, LDAP, Kerberos, and a flexible plugin architecture. Both platforms offer row-level security, column masking, trusted contexts, encryption, and audit policies that map directly to regulatory requirements.
But these features mean nothing if you do not understand them. A DB2 system with default security is a locked vault with the combination taped to the door. This chapter will teach you to design, implement, and verify a security model worthy of the data it protects.
We will build this understanding layer by layer — authentication first, then privileges, then roles, then fine-grained access control, then encryption, then audit — because security is not a feature you bolt on. It is an architecture you build from the ground up.
Let us begin at the outermost layer: proving who you are.
19.1 DB2 Security Architecture Overview
The Two Fundamental Questions
Every security system answers two questions:
- Authentication: Who are you? (Identity verification)
- Authorization: What are you allowed to do? (Permission enforcement)
DB2 separates these concerns cleanly. Authentication is handled outside of DB2 — by the operating system, an LDAP directory, a Kerberos realm, or an external security manager like RACF. Authorization is handled inside DB2 — through a layered system of privileges, authorities, roles, and fine-grained access controls stored in the DB2 catalog.
This separation is deliberate and important. It means DB2 never stores passwords. It never implements its own authentication protocol. It delegates identity verification to systems that specialize in it, and then makes authorization decisions based on the verified identity. This principle — "authenticate externally, authorize internally" — is one of the reasons DB2 has maintained its security reputation across four decades.
The Security Layers
Think of DB2 security as a series of concentric walls, each providing a different type of protection:
┌──────────────────────────────────────────────────┐
│ Layer 1: Network Security (SSL/TLS, firewalls) │
│ ┌──────────────────────────────────────────────┐│
│ │ Layer 2: Authentication (RACF, OS, LDAP) ││
│ │ ┌──────────────────────────────────────────┐││
│ │ │ Layer 3: Administrative Authorities │││
│ │ │ ┌──────────────────────────────────────┐│││
│ │ │ │ Layer 4: Database/Schema Privileges ││││
│ │ │ │ ┌──────────────────────────────────┐││││
│ │ │ │ │ Layer 5: Object Privileges │││││
│ │ │ │ │ ┌──────────────────────────────┐│││││
│ │ │ │ │ │ Layer 6: RCAC (Row/Column) ││││││
│ │ │ │ │ │ ┌────────────────────────┐ ││││││
│ │ │ │ │ │ │ Layer 7: Encryption │ ││││││
│ │ │ │ │ │ └────────────────────────┘ ││││││
│ │ │ │ │ └──────────────────────────────┘│││││
│ │ │ │ └──────────────────────────────────┘││││
│ │ │ └──────────────────────────────────────┘│││
│ │ └──────────────────────────────────────────┘││
│ └──────────────────────────────────────────────┘│
└──────────────────────────────────────────────────┘
A request must pass through every layer to access data. Even if a user is authenticated (Layer 2) and has table-level SELECT privilege (Layer 5), a row permission (Layer 6) can still filter out rows they should not see, and column masking can redact sensitive values. This defense-in-depth approach means that a misconfiguration at one layer does not automatically compromise the entire system.
The DB2 Catalog as Security Registry
All authorization information in DB2 is stored in the system catalog tables. The most important ones for security include:
| Catalog Table (LUW) | z/OS Equivalent | What It Stores |
|---|---|---|
| SYSCAT.DBAUTH | SYSIBM.SYSUSERAUTH | Database-level privileges |
| SYSCAT.TABAUTH | SYSIBM.SYSTABAUTH | Table and view privileges |
| SYSCAT.COLAUTH | SYSIBM.SYSCOLAUTH | Column-level privileges |
| SYSCAT.SCHEMAAUTH | SYSIBM.SYSSCHEMAAUTH | Schema-level privileges |
| SYSCAT.ROUTINEAUTH | SYSIBM.SYSROUTINEAUTH | Routine (procedure/function) privileges |
| SYSCAT.ROLEAUTH | SYSIBM.SYSROLES | Role memberships |
| SYSCAT.CONTROLS | SYSIBM.SYSCONTROLS | RCAC permissions and masks |
When DB2 receives a SQL statement, it checks these catalog tables to determine whether the requesting authorization ID has the necessary privileges. This check happens at both compile time (for static SQL) and execution time (for dynamic SQL), with caching for performance.
Key Concept: Authorization ID
Every connection to DB2 carries an authorization ID (auth ID) — a string that identifies the user or application. On z/OS, this is typically the RACF user ID (up to 8 characters). On LUW, it is the operating system user name (or LDAP/Kerberos principal). All privilege checks in DB2 are performed against this auth ID. Understanding what auth ID is in effect at any given moment is fundamental to understanding DB2 security.
19.2 [z/OS] Authentication with RACF, ACF2, and Top Secret
The External Security Manager Model
DB2 for z/OS does not authenticate users itself. Instead, it delegates authentication entirely to an External Security Manager (ESM). The three ESMs supported on z/OS are:
- RACF (Resource Access Control Facility) — IBM's own ESM, by far the most common in DB2 environments
- ACF2 (Access Control Facility) — from Broadcom (formerly CA Technologies)
- Top Secret — also from Broadcom
Of these, RACF is dominant in banking and government. We will focus our examples on RACF, but the concepts apply to all three ESMs.
How RACF Authentication Works for DB2
When a user connects to DB2 for z/OS, the authentication flow is:
- User presents credentials — A TSO user ID and password, a CICS sign-on, or a DRDA connection with user ID and password.
- z/OS passes credentials to RACF — The operating system calls RACF's authentication service (RACROUTE macro).
- RACF validates identity — Against its own database of user profiles, group memberships, and password policies.
- RACF returns a verified identity — A RACF user ID that becomes the DB2 authorization ID.
- DB2 uses the auth ID for all privilege checks — DB2 never sees the password; it only sees the verified identity.
This means that DB2 security on z/OS is only as strong as the RACF configuration. A poorly configured RACF environment undermines everything DB2 does internally.
RACF Profiles for DB2
RACF protects DB2 resources through profiles in specific classes. The key RACF classes for DB2 are:
DSNR — Controls who can connect to DB2 (plan authorization)
DSNADM — Controls administrative functions
MDSNSM — Controls DB2 subsystem-level operations
A RACF profile for DB2 plan execution looks like this:
RDEFINE DSNR DB2P.EXECUTE.PLANNAME UACC(NONE)
PERMIT DB2P.EXECUTE.PLANNAME CLASS(DSNR) ID(USRGRP1) ACCESS(READ)
SETROPTS RACLIST(DSNR) REFRESH
This defines a profile in the DSNR class that controls who can execute a specific DB2 plan. The UACC(NONE) sets the universal default to "no access," and the PERMIT command grants READ access (which allows execution) to a specific RACF group.
Connection Trust Levels
DB2 for z/OS recognizes different levels of trust depending on how the connection was established:
| Connection Type | Trust Level | Typical Auth ID Source |
|---|---|---|
| TSO (foreground) | High | TSO user ID = RACF ID = DB2 auth ID |
| Batch (JCL) | High | JOB card USER parameter, verified by RACF |
| CICS | Medium | CICS sign-on user, propagated via attachment facility |
| IMS | Medium | IMS sign-on or /SIGN ON user |
| DRDA (remote) | Variable | Depends on AUTHENTICATION setting (see below) |
For DRDA (Distributed Relational Database Architecture) connections — the protocol used for remote access, including JDBC and ODBC — DB2 for z/OS supports multiple authentication modes configured at the DDF (Distributed Data Facility) level:
- SERVER — Client sends user ID and password; DB2 (via RACF) authenticates
- CLIENT — DB2 trusts the client's authentication (dangerous — use only in fully trusted networks)
- SERVER_ENCRYPT — Like SERVER, but credentials are encrypted in transit
- KERBEROS — Kerberos ticket-based authentication (requires z/OS Integrated Security Services)
Meridian Bank z/OS Standard: All DRDA connections use SERVER_ENCRYPT at minimum. CLIENT authentication is prohibited by policy. Kerberos is used for application server connections within the trusted data center network.
RACF Group Structures for DB2
In practice, RACF groups map to DB2 access patterns. A well-designed RACF group structure for a banking environment might look like:
MERIDIAN (top-level group)
├── MER-DBA (database administrators)
│ ├── MER-DBA-PROD (production DBAs)
│ └── MER-DBA-DEV (development DBAs)
├── MER-APP (application IDs)
│ ├── MER-APP-ONLINE (online transaction processing)
│ └── MER-APP-BATCH (batch processing)
├── MER-OPS (operations staff)
└── MER-AUDIT (auditors — read-only)
Each group receives DB2 privileges through GRANT statements targeting the group name. When a new DBA joins the team, the security administrator adds their RACF ID to the MER-DBA-PROD group, and they inherit all associated DB2 privileges. No individual GRANT statements needed.
19.3 [LUW] Authentication
Authentication Types
DB2 for LUW supports several authentication types, configured at the instance level using the AUTHENTICATION database manager configuration parameter:
| Auth Type | Description | When to Use |
|---|---|---|
| SERVER | Server validates user ID and password against OS | Default; suitable for simple environments |
| SERVER_ENCRYPT | Same as SERVER, but credentials encrypted in transit | Minimum for production |
| CLIENT | Server trusts client's authentication | Development only; never in production |
| KERBEROS | Kerberos ticket-based authentication | Enterprise single sign-on environments |
| GSSPLUGIN | Generic Security Services plugin | Custom authentication (LDAP, certificates, etc.) |
| DATA_ENCRYPT | Like SERVER_ENCRYPT, plus encrypts all data in transit | High-security requirements |
| DATA_ENCRYPT_CMP | DATA_ENCRYPT with fallback to SERVER_ENCRYPT | Migration scenarios |
To view the current authentication type:
-- LUW: Check authentication configuration
db2 get dbm cfg | grep -i authentication
To change it:
-- LUW: Set authentication to SERVER_ENCRYPT
db2 update dbm cfg using AUTHENTICATION SERVER_ENCRYPT
db2stop
db2start
Note that changing the authentication type requires a database manager restart.
LDAP Authentication
For enterprise environments, LDAP authentication is typically configured through a GSS-API plugin. DB2 for LUW ships with an LDAP security plugin that can authenticate users against an LDAP directory (IBM Tivoli Directory Server, Microsoft Active Directory, OpenLDAP, etc.).
Configuration steps:
-- Step 1: Configure the LDAP plugin in db2 registry
db2set DB2AUTH=OSAUTHDB (optional: OS auth for local + LDAP for remote)
db2set DB2_GRP_LOOKUP=LDAP (groups come from LDAP, not OS)
-- Step 2: Configure LDAP server details in the plugin config
-- File: $INSTHOME/sqllib/cfg/IBMLDAPSecurity.ini
[LDAP]
LDAP_HOST = ldap.meridianbank.com
LDAP_PORT = 636
ENABLE_SSL = TRUE
USER_BASEDN = ou=employees,dc=meridianbank,dc=com
GROUP_BASEDN = ou=groups,dc=meridianbank,dc=com
USER_OBJECTCLASS = inetOrgPerson
USERID_ATTRIBUTE = uid
Kerberos Authentication
For environments with an existing Kerberos infrastructure (common in enterprises with Active Directory), DB2 for LUW can participate in Kerberos single sign-on:
-- LUW: Enable Kerberos authentication
db2 update dbm cfg using AUTHENTICATION KERBEROS
db2 update dbm cfg using SRVCON_GSSPLUGIN_LIST IBMkrb5
db2stop
db2start
With Kerberos, users authenticate once to the Kerberos Key Distribution Center (KDC) and receive a ticket-granting ticket. Subsequent DB2 connections use service tickets derived from this initial authentication — no password retransmission required.
Operating System Authentication
In the default SERVER or SERVER_ENCRYPT mode, DB2 for LUW validates credentials against the operating system:
- Linux/UNIX: User must exist in
/etc/passwd(or NIS/LDAP via NSS), and the password is validated by PAM or shadow password file - Windows: User must exist in the local Security Accounts Manager (SAM) or Active Directory, validated through Windows authentication APIs
This means that user management for DB2 on LUW starts at the OS level. Creating a DB2 user means creating an OS user first:
# Linux: Create an OS user for DB2 access
useradd -m -s /bin/bash meridian_teller01
passwd meridian_teller01
# The user can now connect to DB2 (after being granted CONNECT privilege)
db2 connect to MERIDIAN user meridian_teller01 using <password>
Important Distinction: On LUW, creating an OS user does not automatically grant any DB2 privileges. The user can attempt to authenticate, but until they receive at least CONNECT privilege on a database, they cannot do anything useful. On z/OS, the situation is analogous — a RACF user ID exists for authentication, but DB2 privileges must be explicitly granted.
19.4 Privileges — The Granular Permission Model
The Principle of Least Privilege
Before we discuss syntax, we must establish the principle that governs all security design: least privilege. Every user, application, and process should have exactly the privileges it needs to perform its function — no more, no less.
In banking, this is not optional. Regulators examine privilege assignments during audits. "We gave everyone DBADM because it was easier" is a finding that can result in fines, mandatory remediation, and consent orders. The granularity of DB2's privilege system exists precisely so that you can implement least privilege rigorously.
GRANT and REVOKE — The Fundamental Verbs
All privilege management in DB2 uses two SQL statements:
- GRANT — Gives a privilege to a user, group, or role
- REVOKE — Removes a privilege from a user, group, or role
The general syntax is:
GRANT <privilege-list> ON <object> TO <grantee> [WITH GRANT OPTION];
REVOKE <privilege-list> ON <object> FROM <grantee>;
Database-Level Privileges
Database-level privileges control broad operations within a database:
-- Grant CONNECT privilege (required for any database access)
GRANT CONNECT ON DATABASE TO USER meridian_app;
-- Grant ability to create tables (CREATETAB)
GRANT CREATETAB ON DATABASE TO ROLE app_developer;
-- Grant ability to create schemas (IMPLICIT_SCHEMA is usually default)
GRANT IMPLICIT_SCHEMA ON DATABASE TO USER dev_lead;
-- Grant ability to bind packages (important for static SQL)
GRANT BINDADD ON DATABASE TO ROLE app_deployer;
-- Grant ability to create external routines
GRANT CREATE_EXTERNAL_ROUTINE ON DATABASE TO ROLE sys_developer;
-- LUW: Grant LOAD authority (required for LOAD utility)
GRANT LOAD ON DATABASE TO ROLE etl_operator;
The full list of database-level privileges on LUW includes: CONNECT, CREATETAB, BINDADD, CREATE_NOT_FENCED_ROUTINE, CREATE_EXTERNAL_ROUTINE, IMPLICIT_SCHEMA, LOAD, QUIESCE_CONNECT, and EXTERNALROUTINE.
Schema-Level Privileges
Schemas provide a namespace for database objects. Schema-level privileges control who can create, alter, or drop objects within a schema:
-- Grant all schema privileges
GRANT ALTERIN, CREATEIN, DROPIN ON SCHEMA meridian TO ROLE app_developer;
-- Grant only the ability to create objects in the schema
GRANT CREATEIN ON SCHEMA meridian TO ROLE app_deployer;
-- Revoke DROP privilege (developers can create but not drop in production)
REVOKE DROPIN ON SCHEMA meridian FROM ROLE app_developer;
Table-Level Privileges
Table-level privileges are the most commonly used and provide fine-grained control over data access:
-- Grant SELECT (read) access
GRANT SELECT ON TABLE meridian.accounts TO ROLE teller;
-- Grant INSERT and UPDATE (write) access
GRANT INSERT, UPDATE ON TABLE meridian.transactions TO ROLE teller;
-- Grant DELETE access (rarely granted to application roles)
GRANT DELETE ON TABLE meridian.temp_staging TO ROLE etl_operator;
-- Grant ALL privileges (use sparingly)
GRANT ALL ON TABLE meridian.accounts TO ROLE branch_manager;
-- Grant with the ability to pass the privilege to others
GRANT SELECT ON TABLE meridian.accounts TO USER senior_dba WITH GRANT OPTION;
-- Grant REFERENCES (needed to create foreign keys referencing this table)
GRANT REFERENCES ON TABLE meridian.accounts TO ROLE app_developer;
-- Grant ALTER (needed to add columns, create indexes, etc.)
GRANT ALTER ON TABLE meridian.accounts TO ROLE app_developer;
-- Grant INDEX (needed to create indexes on the table)
GRANT INDEX ON TABLE meridian.accounts TO ROLE app_developer;
The table-level privileges in DB2 are: SELECT, INSERT, UPDATE, DELETE, ALTER, INDEX, REFERENCES, and CONTROL (which implies all the others plus the ability to grant them).
Column-Level Privileges
When table-level privileges are too broad, DB2 supports column-level UPDATE and REFERENCES privileges:
-- Allow tellers to update only the balance and status columns
GRANT UPDATE (balance, account_status)
ON TABLE meridian.accounts
TO ROLE teller;
-- Allow foreign key references only to the account_id column
GRANT REFERENCES (account_id)
ON TABLE meridian.accounts
TO ROLE app_developer;
Column-level SELECT is not directly supported through GRANT (use views or column masking for that), but column-level UPDATE is essential for least-privilege enforcement. A teller who can update an account balance should not be able to update the account holder's Social Security number.
View-Based Security
Before RCAC was introduced, views were the primary mechanism for restricting which rows and columns a user could see:
-- Create a view that shows only the teller's assigned branch
CREATE VIEW meridian.v_branch_accounts AS
SELECT account_id, customer_name, account_type, balance
FROM meridian.accounts
WHERE branch_id = SESSION_USER_BRANCH()
WITH CHECK OPTION;
-- Grant SELECT on the view, not the base table
GRANT SELECT ON meridian.v_branch_accounts TO ROLE teller;
Views still serve an important security role, but RCAC (Section 19.7) provides a more robust mechanism that cannot be bypassed through direct table access.
WITH GRANT OPTION
The WITH GRANT OPTION clause allows a grantee to pass the privilege to others:
GRANT SELECT ON TABLE meridian.accounts
TO USER dba_lead WITH GRANT OPTION;
-- dba_lead can now grant SELECT on this table to others
Use this sparingly. Every WITH GRANT OPTION creates a privilege chain that is harder to audit and harder to revoke cleanly. When you revoke a privilege that was granted with WITH GRANT OPTION, DB2's behavior depends on the platform:
- LUW: Revoking from the grantor also revokes from anyone they granted to (cascading revoke)
- z/OS: Similar cascading behavior, but
REVOKE ... BY ALLmay be needed for completeness
REVOKE — Removing Privileges
-- Revoke specific privilege
REVOKE INSERT ON TABLE meridian.accounts FROM ROLE teller;
-- Revoke all privileges on a table
REVOKE ALL ON TABLE meridian.accounts FROM USER former_employee;
-- Revoke database-level privilege
REVOKE CONNECT ON DATABASE FROM USER former_employee;
Warning
: On DB2 for LUW, revoking a privilege that was used to create views or packages can cascade — invalidating dependent objects. Always check dependencies before revoking privileges in production. Use SYSCAT.TABDEP and SYSCAT.PACKAGEDEP to identify dependent objects.
19.5 Roles — Simplifying Privilege Management
The Problem Roles Solve
Without roles, privilege management in a large organization becomes a nightmare. Consider Meridian National Bank with 500 tellers, 50 branch managers, and 20 DBAs. Without roles, granting access to a new table requires 570 individual GRANT statements. When a teller is promoted to branch manager, you must revoke dozens of teller privileges and grant dozens of manager privileges. This does not scale.
Roles solve this by creating named collections of privileges:
ROLE: teller
├── SELECT ON meridian.accounts
├── SELECT ON meridian.customers
├── INSERT ON meridian.transactions
├── UPDATE (balance, account_status) ON meridian.accounts
└── EXECUTE ON meridian.process_deposit
ROLE: branch_manager
├── (all teller privileges via role membership)
├── SELECT ON meridian.branch_performance
├── UPDATE ON meridian.branch_config
└── EXECUTE ON meridian.approve_loan
When a new teller joins, one statement handles it: GRANT ROLE teller TO USER new_teller. When they are promoted, two statements: REVOKE ROLE teller FROM USER promoted_user; GRANT ROLE branch_manager TO USER promoted_user;
Creating and Managing Roles
-- Create roles
CREATE ROLE teller;
CREATE ROLE branch_manager;
CREATE ROLE auditor;
CREATE ROLE dba_operations;
-- Grant privileges to roles
GRANT SELECT ON TABLE meridian.accounts TO ROLE teller;
GRANT INSERT ON TABLE meridian.transactions TO ROLE teller;
GRANT EXECUTE ON PROCEDURE meridian.process_deposit TO ROLE teller;
-- Grant a role to a user
GRANT ROLE teller TO USER john_smith;
-- Grant a role to another role (role hierarchy)
GRANT ROLE teller TO ROLE branch_manager;
-- branch_manager now inherits all teller privileges
-- Grant a role to a group (LUW)
GRANT ROLE teller TO GROUP teller_group;
-- Check who holds a role
SELECT GRANTEE, GRANTEETYPE, ADMIN
FROM SYSCAT.ROLEAUTH
WHERE ROLENAME = 'TELLER';
Role Hierarchies
Roles can be granted to other roles, creating hierarchies:
-- Base roles
CREATE ROLE bank_employee;
CREATE ROLE teller;
CREATE ROLE senior_teller;
CREATE ROLE branch_manager;
CREATE ROLE regional_manager;
-- Build hierarchy
GRANT ROLE bank_employee TO ROLE teller;
GRANT ROLE teller TO ROLE senior_teller;
GRANT ROLE senior_teller TO ROLE branch_manager;
GRANT ROLE branch_manager TO ROLE regional_manager;
-- Privileges at each level accumulate upward
GRANT CONNECT ON DATABASE TO ROLE bank_employee;
GRANT SELECT ON TABLE meridian.customers TO ROLE bank_employee;
GRANT INSERT ON TABLE meridian.transactions TO ROLE teller;
GRANT EXECUTE ON PROCEDURE meridian.override_limit TO ROLE senior_teller;
GRANT SELECT ON TABLE meridian.branch_performance TO ROLE branch_manager;
GRANT SELECT ON TABLE meridian.region_performance TO ROLE regional_manager;
A regional_manager now inherits privileges from all levels below: bank_employee, teller, senior_teller, and branch_manager.
DBADM vs. SECADM vs. SQLADM
DB2 defines several built-in administrative authorities that function like super-roles. Understanding their differences is critical:
| Authority | Can Manage Data? | Can Manage Privileges? | Can Manage Security? | Typical Holder |
|---|---|---|---|---|
| DBADM | Yes — full DML on all objects | Yes — can GRANT/REVOKE | No — cannot manage SECADM features | Senior DBA |
| SECADM | No — cannot SELECT/INSERT/UPDATE/DELETE | Yes — can GRANT/REVOKE | Yes — manages RCAC, audit, LBAC, roles | Security Admin |
| SQLADM | No — cannot modify data | No — limited | No | SQL tuning specialist |
| ACCESSCTRL | No | Yes — can GRANT/REVOKE | No | Privilege administrator |
| DATAACCESS | Yes — full DML | No | No | Data steward |
The separation of DBADM and SECADM is a deliberate separation of duties. A DBA can manage database objects and data but cannot modify security policies. A SECADM can manage security policies but cannot access the data those policies protect. This prevents any single individual from both controlling access and accessing data — a fundamental principle of financial regulation.
-- LUW: Grant SECADM authority
GRANT SECADM ON DATABASE TO USER security_admin;
-- LUW: Grant DBADM authority
GRANT DBADM ON DATABASE TO USER senior_dba;
-- z/OS: Administrative authorities are granted through RACF
-- or through the GRANT statement with installation SYSADM authority
GRANT DBADM ON DATABASE TO auth_id;
Meridian Bank Policy: No single individual holds both DBADM and SECADM. Production DBADM is held by the operations DBA team via role membership. SECADM is held by the information security officer. This separation is audited quarterly.
19.6 Administrative Authorities
The Authority Hierarchy
DB2 defines a hierarchy of administrative authorities that provide system-wide powers beyond what individual privileges offer. The hierarchy differs between z/OS and LUW, but the principle is the same: higher authorities encompass the capabilities of lower ones.
z/OS Authority Hierarchy
Installation SYSADM (highest — set in DSNZPARM)
└── Installation SYSOPR
└── SYSADM (database level)
└── DBADM
└── DBCTRL
└── DBMAINT
On z/OS, the installation SYSADM is defined by the SYSTEM ADMIN 1 and SYSTEM ADMIN 2 fields in the DSNZPARM (subsystem parameter module). This auth ID has unrestricted access to everything in the DB2 subsystem. It is typically set to a RACF group ID that is tightly controlled:
-- z/OS: DSNZPARM settings (set during installation)
SYSTEM ADMIN 1 = MERIDBA1
SYSTEM ADMIN 2 = MERIDBA2
SYSTEM OPERATOR 1 = MERIOPR1
SYSTEM OPERATOR 2 = MERIOPR2
LUW Authority Hierarchy
SYSADM (highest — instance owner's group)
├── SYSCTRL (can create/drop databases, no data access)
├── SYSMAINT (can backup/restore, no data access)
└── SYSMON (monitoring only)
Within a database:
SECADM (security administration — independent authority)
DBADM (full database administration and data access)
SQLADM (SQL tuning — EXPLAIN, but no data modification)
WLMADM (workload management)
ACCESSCTRL (privilege management)
DATAACCESS (data access)
On LUW, SYSADM authority is granted implicitly to members of the operating system group specified by the SYSADM_GROUP database manager configuration parameter:
-- LUW: Check current SYSADM group
db2 get dbm cfg | grep SYSADM_GROUP
-- LUW: Change SYSADM group
db2 update dbm cfg using SYSADM_GROUP db2adm
Understanding SYSADM vs. SECADM
This distinction deserves emphasis because it confuses many administrators:
SYSADM (LUW) or Installation SYSADM (z/OS): - Can do almost anything in the instance/subsystem - Cannot manage RCAC, audit policies, LBAC, or trusted contexts on LUW (these require SECADM) - On z/OS, installation SYSADM historically had unrestricted authority, but modern versions have added SECADM for separation of duties
SECADM: - Specifically designed for security-focused tasks - Can CREATE/ALTER/DROP security objects (roles, trusted contexts, audit policies, RCAC permissions and masks, LBAC components) - Cannot access data directly — cannot SELECT from tables, cannot INSERT/UPDATE/DELETE - Represents the security administrator function in a separation-of-duties model
This separation means that even an all-powerful SYSADM cannot silently modify row-level security policies or disable audit logging. Only SECADM can do that, and that person is typically in a different reporting chain (information security, not IT operations).
19.7 Row and Column Access Control (RCAC)
Why RCAC Exists
Traditional privilege-based security (GRANT/REVOKE) operates at the object level: you can access a table or you cannot. But in many real-world scenarios, you need finer granularity:
- A teller should see accounts only for their assigned branch
- A customer service representative should see the last four digits of a Social Security number but not the full number
- An auditor should see all transactions but not the names associated with accounts under investigation
Views can address some of these requirements, but they have limitations: if a user has direct table access (for application reasons), a view-based restriction can be bypassed. RCAC solves this by enforcing access control rules directly on the base table, regardless of how it is accessed.
RCAC has two components:
- Row Permissions — Control which rows a user can see (row-level security)
- Column Masks — Control what values a user sees in specific columns (column-level masking)
Row Permissions
A row permission is a boolean condition that filters rows for specific users. Only rows satisfying the condition are visible to (or modifiable by) the user.
-- Step 1: Create a row permission
-- Tellers see only accounts from their assigned branch
CREATE PERMISSION meridian.perm_branch_accounts
ON meridian.accounts
FOR ROWS WHERE
branch_id = (
SELECT branch_id
FROM meridian.employee_assignments
WHERE employee_id = SESSION_USER
)
OR
VERIFY_ROLE_FOR_USER(SESSION_USER, 'AUDITOR') = 1
OR
VERIFY_ROLE_FOR_USER(SESSION_USER, 'DBA_OPERATIONS') = 1
ENFORCED FOR ALL ACCESS
ENABLE;
-- Step 2: Activate RCAC on the table
ALTER TABLE meridian.accounts ACTIVATE ROW ACCESS CONTROL;
Once activated, every query against meridian.accounts — whether SELECT, UPDATE, DELETE, or even INSERT — passes through this permission filter. A teller at Branch 101 literally cannot see, modify, or even learn of the existence of accounts at Branch 102.
The ENFORCED FOR ALL ACCESS clause means the permission applies to all types of data access. The ENABLE clause activates the permission immediately.
Critical Detail: When you activate row access control on a table, DB2 implicitly denies all access to all rows unless at least one permission grants access. If you activate RCAC without creating any permissions, nobody can see any data — including DBADM. Only SECADM can create and manage RCAC permissions.
Column Masks
Column masks transform the values of specific columns based on who is querying. Unlike row permissions (which filter rows), column masks return every row but redact specific values:
-- Mask Social Security numbers: show only last 4 digits to tellers
CREATE MASK meridian.mask_ssn
ON meridian.customers
FOR COLUMN ssn
RETURN
CASE
WHEN VERIFY_ROLE_FOR_USER(SESSION_USER, 'AUDITOR') = 1
THEN ssn
WHEN VERIFY_ROLE_FOR_USER(SESSION_USER, 'BRANCH_MANAGER') = 1
THEN 'XXX-XX-' || RIGHT(ssn, 4)
ELSE 'XXX-XX-XXXX'
END
ENABLE;
-- Mask account balances: exact balances only for authorized roles
CREATE MASK meridian.mask_balance
ON meridian.accounts
FOR COLUMN balance
RETURN
CASE
WHEN VERIFY_ROLE_FOR_USER(SESSION_USER, 'TELLER') = 1
THEN balance
WHEN VERIFY_ROLE_FOR_USER(SESSION_USER, 'AUDITOR') = 1
THEN balance
WHEN VERIFY_ROLE_FOR_USER(SESSION_USER, 'BRANCH_MANAGER') = 1
THEN balance
ELSE DECIMAL(0.00, 15, 2)
END
ENABLE;
-- Activate column access control on the table
ALTER TABLE meridian.customers ACTIVATE COLUMN ACCESS CONTROL;
ALTER TABLE meridian.accounts ACTIVATE COLUMN ACCESS CONTROL;
Column masks are evaluated after row permissions. So a teller first sees only their branch's accounts (row permission), and then within those accounts, SSNs are masked (column mask). The layering is:
- Row permissions filter which rows are visible
- Column masks transform values in visible rows
- The result is what the user sees
Label-Based Access Control (LBAC) — z/OS
DB2 for z/OS also supports Label-Based Access Control, a more formal security model based on security labels. LBAC is modeled after military-grade classification systems (CONFIDENTIAL, SECRET, TOP SECRET) and is available on both z/OS and LUW, though it is most commonly used on z/OS:
-- Create a security label component
CREATE SECURITY LABEL COMPONENT classification
ARRAY ['TOP_SECRET', 'SECRET', 'CONFIDENTIAL', 'UNCLASSIFIED'];
-- Create a security policy
CREATE SECURITY POLICY bank_data_policy
COMPONENTS classification
WITH DB2LBACRULES;
-- Apply the policy to a table
ALTER TABLE meridian.sensitive_reports
ADD SECURITY POLICY bank_data_policy;
-- Add a security label column to the table
ALTER TABLE meridian.sensitive_reports
ADD COLUMN sec_label DB2SECURITYLABEL;
-- Grant a security label to a user
CREATE SECURITY LABEL bank_data_policy.secret_level
COMPONENT classification 'SECRET';
GRANT SECURITY LABEL bank_data_policy.secret_level
TO USER intelligence_analyst FOR ALL ACCESS;
With LBAC, a user with SECRET clearance can see rows labeled CONFIDENTIAL and UNCLASSIFIED but not rows labeled TOP_SECRET. The enforcement is automatic and cannot be bypassed.
RCAC Best Practices
-
Always create at least one permissive rule before activating RCAC. Activating row access control with no permissions locks everyone out.
-
Include administrative escape hatches. Your permissions should allow SECADM or designated administrative roles to access all data for maintenance purposes.
-
Test exhaustively before production deployment. RCAC errors can silently filter data, making queries return incorrect results without raising errors.
-
Document every permission and mask. RCAC rules are stored in the catalog (
SYSCAT.CONTROLSon LUW,SYSIBM.SYSCONTROLSon z/OS), but human-readable documentation is essential for audit. -
Use
VERIFY_ROLE_FOR_USERorVERIFY_GROUP_FOR_USERfunctions rather than hardcoding auth IDs. This keeps RCAC rules role-based, not user-based.
19.8 Trusted Contexts and Secure Connections
The Three-Tier Security Challenge
Modern applications typically use a three-tier architecture: client, application server, database. The application server connects to DB2 using a service account (e.g., meridian_app), but the actual end user is a teller, branch manager, or customer using a web interface.
Without trusted contexts, DB2 sees every request as coming from meridian_app. This means:
- RCAC rules cannot distinguish between tellers and managers
- Audit logs show
meridian_appfor every operation, making individual accountability impossible - The service account must have all privileges needed by every end user — violating least privilege
Trusted contexts solve this by allowing the application server to switch the DB2 authorization ID to match the actual end user, without re-authenticating.
Creating a Trusted Context
-- Create a trusted context for the application server
CREATE TRUSTED CONTEXT meridian_online_app
BASED UPON CONNECTION USING SYSTEM AUTHID meridian_app
ATTRIBUTES (ADDRESS '10.0.1.50', -- app server IP
ENCRYPTION 'HIGH') -- require encryption
DEFAULT ROLE teller
ENABLE;
-- Allow specific users to switch into the trusted context
ALTER TRUSTED CONTEXT meridian_online_app
ADD USE FOR john_smith ROLE teller,
ADD USE FOR jane_doe ROLE branch_manager,
ADD USE FOR PUBLIC ROLE bank_employee WITHOUT AUTHENTICATION;
When the application server connects from IP 10.0.1.50 using the meridian_app auth ID, DB2 recognizes it as a trusted context. The application can then switch the auth ID to john_smith without re-authenticating, and DB2 applies john_smith's privileges and the teller role.
How Role Switching Works
Within a trusted context, the application uses the SET SESSION AUTHORIZATION statement (or the sqleseti API) to switch users:
-- Application switches DB2 session to the actual end user
SET SESSION AUTHORIZATION = 'JOHN_SMITH';
-- Now all SQL executes as JOHN_SMITH with the teller role
SELECT * FROM meridian.accounts;
-- RCAC filters to John's branch, column masks apply for teller role
-- Switch to a different user
SET SESSION AUTHORIZATION = 'JANE_DOE';
-- Now operating as JANE_DOE with branch_manager role
The audit trail now shows the actual end-user auth ID, RCAC rules apply per user, and the application service account's privileges are not used for data access.
Trusted Context Security Attributes
Trusted contexts can enforce multiple security attributes:
CREATE TRUSTED CONTEXT meridian_batch
BASED UPON CONNECTION USING SYSTEM AUTHID meridian_batch_svc
ATTRIBUTES (
ADDRESS '10.0.2.0/24', -- subnet range
ENCRYPTION 'HIGH', -- require encryption
SERVERNAME 'BATCH_SERVER_01' -- specific server identity
)
WITH USE FOR
batch_operator_1 ROLE etl_operator,
batch_operator_2 ROLE etl_operator
NO DEFAULT ROLE
ENABLE;
If any attribute does not match — wrong IP address, insufficient encryption, unrecognized server — the trusted context is not activated, and the connection proceeds as a normal (untrusted) connection with only the service account's base privileges.
Meridian Bank Standard: All three-tier applications must use trusted contexts. Direct database connections from application servers without trusted context are flagged as security violations.
19.9 Audit Policies
Why Audit Matters
Privilege management tells DB2 what to allow. Audit tells DB2 what to record. In regulated industries, audit is not optional — it is the evidence trail that proves to regulators, auditors, and courts that security controls are in place and functioning.
DB2 provides comprehensive audit capabilities that can record:
- Who accessed what data, when, and from where
- Which SQL statements were executed, by whom
- Authentication successes and failures
- Privilege grants and revokes
- Administrative actions
- Security policy changes
Audit Categories
DB2 defines several audit categories (events to capture):
| Category | What It Records | Compliance Relevance |
|---|---|---|
| AUDIT | Changes to audit configuration itself | SOX (tamper detection) |
| CHECKING | Authorization checking (success and failure) | PCI-DSS, SOX |
| CONTEXT | Operation context (statement text, connection info) | HIPAA, GDPR |
| EXECUTE | SQL statement execution (with or without data values) | PCI-DSS, HIPAA |
| OBJMAINT | Object creation, alteration, and dropping | SOX |
| SECMAINT | Security-related operations (GRANT, REVOKE, etc.) | All frameworks |
| SYSADMIN | Administrative operations (backup, restore, etc.) | SOX |
| VALIDATE | Authentication attempts (success and failure) | PCI-DSS, SOX |
Creating Audit Policies (LUW)
-- Create an audit policy for sensitive tables
CREATE AUDIT POLICY sensitive_data_policy
CATEGORIES
EXECUTE STATUS BOTH, -- log all executions, success and failure
CHECKING STATUS BOTH, -- log all authorization checks
CONTEXT STATUS BOTH -- log connection context
ERROR TYPE AUDIT; -- fail the operation if audit write fails
-- Apply the policy to specific tables
AUDIT TABLE meridian.accounts USING POLICY sensitive_data_policy;
AUDIT TABLE meridian.customers USING POLICY sensitive_data_policy;
AUDIT TABLE meridian.transactions USING POLICY sensitive_data_policy;
-- Create a policy for security events across the database
CREATE AUDIT POLICY security_events_policy
CATEGORIES
VALIDATE STATUS BOTH, -- all authentication attempts
SECMAINT STATUS BOTH, -- all GRANT/REVOKE operations
SYSADMIN STATUS BOTH, -- all admin operations
AUDIT STATUS BOTH -- changes to audit config itself
ERROR TYPE AUDIT;
-- Apply at the database level
AUDIT DATABASE USING POLICY security_events_policy;
-- Create a policy for a specific user (high-privilege user monitoring)
CREATE AUDIT POLICY dba_monitoring_policy
CATEGORIES
EXECUTE WITH DATA STATUS BOTH, -- capture actual data values accessed
CONTEXT STATUS BOTH
ERROR TYPE AUDIT;
AUDIT ROLE dba_operations USING POLICY dba_monitoring_policy;
The ERROR TYPE AUDIT clause is critical for compliance: it means that if DB2 cannot write the audit record (disk full, I/O error, etc.), the operation itself fails. This guarantees that no unaudited access occurs — a requirement under several compliance frameworks.
Extracting and Archiving Audit Data (LUW)
On LUW, audit data is written to audit log files and must be extracted using the db2audit tool:
# Configure audit at the instance level
db2audit configure datapath /db2audit/data archivepath /db2audit/archive
# Start auditing
db2audit start
# Extract audit data to delimited files for analysis
db2audit extract delasc delimiter ! to /db2audit/reports
# Archive audit logs
db2audit archive database MERIDIAN
# Extract from archive
db2audit extract delasc from files /db2audit/archive/db2audit.db.MERIDIAN.log.*
The extracted files can be loaded into analysis tables for reporting:
-- Create a table to hold extracted audit records
CREATE TABLE meridian_audit.execute_log (
timestamp TIMESTAMP,
category CHAR(8),
authid VARCHAR(128),
application_id VARCHAR(128),
statement_text CLOB(1M),
status INTEGER,
object_schema VARCHAR(128),
object_name VARCHAR(128)
);
-- Load extracted audit data
LOAD FROM /db2audit/reports/execute.del OF DEL
INSERT INTO meridian_audit.execute_log;
z/OS: SMF Records for Audit
On z/OS, DB2 audit data is written to SMF (System Management Facility) records — the standard z/OS auditing infrastructure. DB2 uses several SMF record types:
| SMF Type | Subtype | What It Records |
|---|---|---|
| SMF 101 | — | SQL statement execution (accounting) |
| SMF 102 | — | Performance and statistics |
| SMF 142 | 1 | Authorization failures |
| SMF 142 | 2 | GRANT/REVOKE operations |
| SMF 142 | 3 | Audit trace records |
To enable DB2 audit tracing on z/OS:
-START TRACE(AUDIT) CLASS(1,2,3) DEST(SMF)
SMF records are typically processed by enterprise audit tools (IBM Guardium, BMC Audit for DB2, or custom DFSORT/ICETOOL extracts). The advantage of SMF integration is that DB2 audit records flow into the same infrastructure used for all z/OS auditing — providing a unified view across the entire mainframe environment.
//* z/OS JCL to extract DB2 audit records from SMF
//EXTRACT EXEC PGM=IFASMFDP
//SYSPRINT DD SYSOUT=*
//DUMPIN DD DSN=SYS1.MAN1,DISP=SHR
//DUMPOUT DD DSN=DB2.AUDIT.EXTRACT,DISP=(NEW,CATLG),
// SPACE=(CYL,(50,10),RLSE)
//SYSIN DD *
INDD(DUMPIN,OPTIONS(DUMP))
OUTDD(DUMPOUT,TYPE(142))
/*
Audit Policy Best Practices
-
Audit all authentication attempts (VALIDATE) — both success and failure. Failed logins may indicate an attack.
-
Audit all privilege changes (SECMAINT) — every GRANT and REVOKE should be recorded permanently.
-
Audit sensitive table access with EXECUTE — for tables containing PII, PHI, or financial data, record who accessed what.
-
Use EXECUTE WITH DATA cautiously — capturing actual data values in audit logs creates a second copy of sensitive data. Ensure audit logs are protected with the same rigor as the database itself.
-
Use ERROR TYPE AUDIT for compliance-critical policies — this guarantees no unaudited access.
-
Archive and protect audit logs — audit logs must be immutable and retained per regulatory requirements (typically 7 years for financial data, 6 years for HIPAA).
-
Monitor audit log volume — EXECUTE-level auditing generates enormous volumes. Size your audit infrastructure accordingly.
19.10 Encryption — Data at Rest and In Transit
The Three States of Data
Data exists in three states, each requiring different encryption approaches:
- In transit — Moving between client and server over the network
- At rest — Stored on disk (database files, backup files, log files)
- In use — Being processed in memory
DB2 addresses the first two comprehensively.
Encryption In Transit: SSL/TLS
Both DB2 for z/OS and DB2 for LUW support SSL/TLS encryption for network communications:
LUW SSL Configuration
# Step 1: Create a key database (using GSKit)
gsk8capicmd_64 -keydb -create \
-db /home/db2inst1/sqllib/security/keystore/db2server.kdb \
-pw "strong_password" \
-type cms -stash
# Step 2: Import or create a server certificate
gsk8capicmd_64 -cert -create \
-db /home/db2inst1/sqllib/security/keystore/db2server.kdb \
-stashed \
-label "db2server_cert" \
-dn "CN=db2server.meridianbank.com,O=Meridian Bank,C=US" \
-size 2048
# Step 3: Configure DB2 to use SSL
db2 update dbm cfg using SSL_SVR_KEYDB /home/db2inst1/sqllib/security/keystore/db2server.kdb
db2 update dbm cfg using SSL_SVR_STASH /home/db2inst1/sqllib/security/keystore/db2server.sth
db2 update dbm cfg using SSL_SVR_LABEL db2server_cert
db2 update dbm cfg using SSL_SVCENAME 50001
# Step 4: Restart DB2
db2stop
db2start
z/OS SSL Configuration
On z/OS, SSL/TLS is configured through AT-TLS (Application Transparent Transport Layer Security), which provides encryption at the TCP/IP stack level without application changes:
/* z/OS Policy Agent AT-TLS configuration */
TTLSRule DB2_DDF_Secure
{
LocalPortRange 446
Direction Inbound
TTLSGroupAction DB2_DDF_Group
{
TTLSEnabled On
Trace 2
}
TTLSEnvironmentAction DB2_DDF_Env
{
HandshakeRole Server
TTLSKeyringParmsRef DB2_Keyring
{
Keyring MERIDIAN/DB2RING
}
TTLSCipherParmsRef DB2_Ciphers
{
V3CipherSuites TLS_RSA_WITH_AES_256_CBC_SHA256
V3CipherSuites TLS_RSA_WITH_AES_128_CBC_SHA256
}
}
}
Encryption At Rest
LUW: Native Encryption (Db2 11.1+)
DB2 for LUW supports native encryption at the database level, which encrypts all data, indexes, LOBs, logs, and temporary files:
-- Create an encrypted database
CREATE DATABASE MERIDIAN
ENCRYPT;
-- Or encrypt an existing database (requires backup/restore cycle)
-- Step 1: Backup
BACKUP DATABASE MERIDIAN TO /backups
-- Step 2: Restore with encryption
RESTORE DATABASE MERIDIAN FROM /backups
ENCRYPT;
The encryption key is stored in a keystore file protected by a master key. For enterprise key management, DB2 integrates with:
- IBM Security Guardium Key Lifecycle Manager (GKLM)
- PKCS#11 hardware security modules (HSMs)
- Third-party key management systems via KMIP
-- LUW: Configure centralized key management
db2 update dbm cfg using KEYSTORE_TYPE PKCS12
db2 update dbm cfg using KEYSTORE_LOCATION /opt/ibm/db2keystore/db2keys.p12
z/OS: Encryption with Hardware Crypto
DB2 for z/OS leverages the mainframe's hardware cryptographic processors (Crypto Express adapters) for encryption with minimal performance impact:
-- z/OS: Create an encrypted tablespace
CREATE TABLESPACE ACCTDATA
IN MERIDIAN
USING STOGROUP MERSG01
ERASE YES
COMPRESS YES
DSSIZE 16G
SEGSIZE 64
BUFFERPOOL BP32K1;
-- Apply z/OS DFSMS data set encryption
-- (Configured via RACF CSFKEYS class and SMS data class)
z/OS data set encryption is managed through RACF and SMS (Storage Management Subsystem), providing transparent encryption at the storage level. DB2 data sets, including table spaces, index spaces, and log data sets, can be encrypted without any application changes.
Column-Level Encryption
For encrypting individual columns (e.g., Social Security numbers, credit card numbers), DB2 provides encryption functions:
-- Encrypt a value before storing
INSERT INTO meridian.customers (customer_id, ssn_encrypted)
VALUES (1001, ENCRYPT('123-45-6789', 'encryption_password'));
-- Decrypt when retrieving
SELECT customer_id, DECRYPT_CHAR(ssn_encrypted, 'encryption_password')
FROM meridian.customers
WHERE customer_id = 1001;
However, column-level encryption using SQL functions has significant drawbacks: the encryption password must be managed by the application, encrypted columns cannot be indexed for searching, and key management is manual. For most use cases, native database encryption (at-rest encryption) combined with RCAC column masking provides better security with less complexity.
Meridian Bank Standard: All production databases use native at-rest encryption. SSL/TLS is required for all connections. Column-level encryption is used only for specific PCI-DSS requirements where cardholder data must be encrypted at the column level independent of database-level encryption.
19.11 Compliance Patterns
PCI-DSS: Payment Card Industry Data Security Standard
PCI-DSS defines requirements for protecting cardholder data. Here is how DB2 features map to key PCI-DSS requirements:
| PCI-DSS Requirement | DB2 Implementation |
|---|---|
| Req 3.4: Render PAN unreadable anywhere it is stored | Native encryption + column masking for PAN display |
| Req 7.1: Limit access to cardholder data to need-to-know | RCAC row permissions + column masks |
| Req 7.2: Establish access control system based on job function | Role-based access control (RBAC) |
| Req 8.1: Assign unique identification to each person | Individual auth IDs via RACF/OS/LDAP |
| Req 8.5: Do not use group, shared, or generic accounts | Trusted contexts for three-tier apps (individual accountability) |
| Req 10.1: Link all access to individual users | Audit policies with EXECUTE and CONTEXT categories |
| Req 10.2: Implement audit trails for access to cardholder data | Audit policies on PCI-scoped tables |
| Req 10.5: Secure audit trails so they cannot be altered | ERROR TYPE AUDIT + immutable audit archives |
| Req 10.7: Retain audit trail for at least one year | Audit archive with retention policy |
Implementation pattern:
-- PCI-DSS: Create a role for payment processing
CREATE ROLE pci_payment_processor;
GRANT SELECT ON TABLE meridian.card_transactions TO ROLE pci_payment_processor;
GRANT INSERT ON TABLE meridian.card_transactions TO ROLE pci_payment_processor;
-- PCI-DSS: Mask the Primary Account Number (PAN)
CREATE MASK meridian.mask_card_pan
ON meridian.card_transactions
FOR COLUMN card_number
RETURN
CASE
WHEN VERIFY_ROLE_FOR_USER(SESSION_USER, 'PCI_PAYMENT_PROCESSOR') = 1
THEN card_number -- full PAN only for authorized processors
ELSE
'XXXX-XXXX-XXXX-' || RIGHT(card_number, 4)
END
ENABLE;
-- PCI-DSS: Audit all access to cardholder data
CREATE AUDIT POLICY pci_audit_policy
CATEGORIES
EXECUTE WITH DATA STATUS BOTH,
CHECKING STATUS BOTH,
CONTEXT STATUS BOTH
ERROR TYPE AUDIT;
AUDIT TABLE meridian.card_transactions USING POLICY pci_audit_policy;
HIPAA: Health Insurance Portability and Accountability Act
HIPAA's Security Rule requires protections for electronic Protected Health Information (ePHI). DB2 mappings:
| HIPAA Requirement | DB2 Implementation |
|---|---|
| Access Controls (164.312(a)(1)) | RBAC + RCAC row permissions |
| Audit Controls (164.312(b)) | Audit policies on ePHI tables |
| Integrity Controls (164.312(c)(1)) | CHECK constraints + triggers + audit trail |
| Person Authentication (164.312(d)) | RACF/LDAP/Kerberos authentication |
| Transmission Security (164.312(e)(1)) | SSL/TLS encryption (DATA_ENCRYPT) |
| Encryption (164.312(a)(2)(iv)) | Native database encryption |
| Minimum Necessary (164.502(b)) | Column masks + row permissions |
SOX: Sarbanes-Oxley Act
SOX Section 404 requires internal controls over financial reporting. For DB2, this means:
-- SOX: Audit all changes to financial tables
CREATE AUDIT POLICY sox_financial_policy
CATEGORIES
EXECUTE STATUS BOTH,
OBJMAINT STATUS BOTH, -- track schema changes
SECMAINT STATUS BOTH, -- track privilege changes
SYSADMIN STATUS BOTH -- track admin operations
ERROR TYPE AUDIT;
AUDIT TABLE meridian.general_ledger USING POLICY sox_financial_policy;
AUDIT TABLE meridian.accounts USING POLICY sox_financial_policy;
AUDIT TABLE meridian.transactions USING POLICY sox_financial_policy;
-- SOX: Enforce separation of duties
-- Ensure no one holds both DBADM and SECADM
-- (organizational policy, verified by audit query)
SELECT a.GRANTEE, 'DBADM' AS authority
FROM SYSCAT.DBAUTH a WHERE a.DBADMAUTH = 'Y'
INTERSECT
SELECT b.GRANTEE, 'DBADM'
FROM SYSCAT.DBAUTH b WHERE b.SECURITYADMAUTH = 'Y';
-- This query should return ZERO rows
GDPR: General Data Protection Regulation
GDPR requires the ability to mask, anonymize, and delete personal data. DB2's RCAC column masks directly support data minimization:
-- GDPR: Mask personal data for analytics users
CREATE MASK meridian.mask_customer_name
ON meridian.customers
FOR COLUMN customer_name
RETURN
CASE
WHEN VERIFY_ROLE_FOR_USER(SESSION_USER, 'CUSTOMER_SERVICE') = 1
THEN customer_name
WHEN VERIFY_ROLE_FOR_USER(SESSION_USER, 'ANALYTICS') = 1
THEN 'ANONYMIZED_' || CAST(customer_id AS VARCHAR(20))
ELSE '***RESTRICTED***'
END
ENABLE;
-- GDPR: Right to erasure — delete customer data
-- (Requires careful FK handling; typically a stored procedure)
CREATE PROCEDURE meridian.gdpr_erase_customer(IN p_customer_id INTEGER)
LANGUAGE SQL
BEGIN
DELETE FROM meridian.customer_communications
WHERE customer_id = p_customer_id;
DELETE FROM meridian.customer_preferences
WHERE customer_id = p_customer_id;
UPDATE meridian.transactions
SET customer_name = 'ERASED', notes = 'GDPR erasure'
WHERE customer_id = p_customer_id;
-- Retain transaction records for regulatory requirements
-- but anonymize personal identifiers
DELETE FROM meridian.customers
WHERE customer_id = p_customer_id;
END;
19.12 The Meridian National Bank Security Model
Overview
Now we bring everything together. The Meridian National Bank security model demonstrates how authentication, authorization, RCAC, trusted contexts, encryption, and audit work as a unified system. This is not a toy example — it is a production-grade security architecture for a banking database.
Role Definitions
-- ==============================================
-- MERIDIAN NATIONAL BANK: ROLE HIERARCHY
-- ==============================================
-- Base role: all bank employees
CREATE ROLE bank_employee;
-- Operational roles
CREATE ROLE teller;
CREATE ROLE senior_teller;
CREATE ROLE branch_manager;
CREATE ROLE regional_manager;
-- Specialized roles
CREATE ROLE loan_officer;
CREATE ROLE customer_service;
-- Oversight roles
CREATE ROLE auditor;
CREATE ROLE compliance_officer;
-- Technical roles
CREATE ROLE dba_operations;
CREATE ROLE security_admin;
CREATE ROLE app_developer;
CREATE ROLE etl_operator;
-- Role hierarchy
GRANT ROLE bank_employee TO ROLE teller;
GRANT ROLE teller TO ROLE senior_teller;
GRANT ROLE senior_teller TO ROLE branch_manager;
GRANT ROLE branch_manager TO ROLE regional_manager;
GRANT ROLE bank_employee TO ROLE loan_officer;
GRANT ROLE bank_employee TO ROLE customer_service;
Privilege Assignments
-- Bank employee: basic connectivity and read access
GRANT CONNECT ON DATABASE TO ROLE bank_employee;
GRANT SELECT ON TABLE meridian.customers TO ROLE bank_employee;
GRANT SELECT ON TABLE meridian.accounts TO ROLE bank_employee;
-- Teller: transaction processing
GRANT INSERT ON TABLE meridian.transactions TO ROLE teller;
GRANT UPDATE (balance, last_activity_date)
ON TABLE meridian.accounts TO ROLE teller;
GRANT EXECUTE ON PROCEDURE meridian.process_deposit TO ROLE teller;
GRANT EXECUTE ON PROCEDURE meridian.process_withdrawal TO ROLE teller;
-- Branch manager: reporting and overrides
GRANT SELECT ON TABLE meridian.branch_performance TO ROLE branch_manager;
GRANT EXECUTE ON PROCEDURE meridian.override_transaction_limit TO ROLE branch_manager;
GRANT EXECUTE ON PROCEDURE meridian.approve_account_opening TO ROLE branch_manager;
-- Auditor: read everything, modify nothing
GRANT SELECT ON TABLE meridian.accounts TO ROLE auditor;
GRANT SELECT ON TABLE meridian.customers TO ROLE auditor;
GRANT SELECT ON TABLE meridian.transactions TO ROLE auditor;
GRANT SELECT ON TABLE meridian.audit_log TO ROLE auditor;
-- Auditor gets NO INSERT, UPDATE, or DELETE on any table
-- DBA operations: administrative tasks, no business data access by default
GRANT DBADM ON DATABASE TO ROLE dba_operations;
Row-Level Security: Branch Scoping
The most important RCAC rule for Meridian: tellers and branch managers see only their branch's data.
-- Row permission: branch-scoped access for operational roles
CREATE PERMISSION meridian.perm_accounts_branch
ON meridian.accounts
FOR ROWS WHERE
-- Tellers and managers see their branch
branch_id IN (
SELECT branch_id
FROM meridian.employee_assignments
WHERE employee_id = SESSION_USER
AND assignment_status = 'ACTIVE'
)
-- Regional managers see all branches in their region
OR branch_id IN (
SELECT b.branch_id
FROM meridian.branches b
JOIN meridian.region_assignments ra
ON b.region_id = ra.region_id
WHERE ra.employee_id = SESSION_USER
AND ra.assignment_status = 'ACTIVE'
)
-- Auditors and compliance see everything
OR VERIFY_ROLE_FOR_USER(SESSION_USER, 'AUDITOR') = 1
OR VERIFY_ROLE_FOR_USER(SESSION_USER, 'COMPLIANCE_OFFICER') = 1
-- DBAs see everything (for maintenance)
OR VERIFY_ROLE_FOR_USER(SESSION_USER, 'DBA_OPERATIONS') = 1
ENFORCED FOR ALL ACCESS
ENABLE;
ALTER TABLE meridian.accounts ACTIVATE ROW ACCESS CONTROL;
Column Masking: Protecting Sensitive Fields
-- Mask SSN based on role
CREATE MASK meridian.mask_customer_ssn
ON meridian.customers
FOR COLUMN ssn
RETURN
CASE
WHEN VERIFY_ROLE_FOR_USER(SESSION_USER, 'AUDITOR') = 1
THEN ssn
WHEN VERIFY_ROLE_FOR_USER(SESSION_USER, 'COMPLIANCE_OFFICER') = 1
THEN ssn
WHEN VERIFY_ROLE_FOR_USER(SESSION_USER, 'BRANCH_MANAGER') = 1
THEN 'XXX-XX-' || RIGHT(ssn, 4)
WHEN VERIFY_ROLE_FOR_USER(SESSION_USER, 'TELLER') = 1
THEN 'XXX-XX-' || RIGHT(ssn, 4)
ELSE 'XXX-XX-XXXX'
END
ENABLE;
-- Mask account numbers for non-operational roles
CREATE MASK meridian.mask_account_number
ON meridian.accounts
FOR COLUMN account_number
RETURN
CASE
WHEN VERIFY_ROLE_FOR_USER(SESSION_USER, 'TELLER') = 1
THEN account_number
WHEN VERIFY_ROLE_FOR_USER(SESSION_USER, 'BRANCH_MANAGER') = 1
THEN account_number
WHEN VERIFY_ROLE_FOR_USER(SESSION_USER, 'AUDITOR') = 1
THEN account_number
ELSE '****' || RIGHT(account_number, 4)
END
ENABLE;
ALTER TABLE meridian.customers ACTIVATE COLUMN ACCESS CONTROL;
ALTER TABLE meridian.accounts ACTIVATE COLUMN ACCESS CONTROL;
Trusted Context: Online Banking Application
-- Trusted context for the online banking application server
CREATE TRUSTED CONTEXT meridian_online_banking
BASED UPON CONNECTION USING SYSTEM AUTHID meridian_web_svc
ATTRIBUTES (
ADDRESS '10.0.5.0/24',
ENCRYPTION 'HIGH'
)
DEFAULT ROLE bank_employee
ENABLE;
-- Trusted context for the batch processing system
CREATE TRUSTED CONTEXT meridian_batch_processing
BASED UPON CONNECTION USING SYSTEM AUTHID meridian_batch_svc
ATTRIBUTES (
ADDRESS '10.0.6.10',
ENCRYPTION 'HIGH'
)
DEFAULT ROLE etl_operator
ENABLE;
Comprehensive Audit Policy
-- Audit all access to customer and account data
CREATE AUDIT POLICY meridian_data_access_policy
CATEGORIES
EXECUTE STATUS BOTH,
CHECKING STATUS BOTH,
CONTEXT STATUS BOTH
ERROR TYPE AUDIT;
AUDIT TABLE meridian.accounts USING POLICY meridian_data_access_policy;
AUDIT TABLE meridian.customers USING POLICY meridian_data_access_policy;
AUDIT TABLE meridian.transactions USING POLICY meridian_data_access_policy;
-- Audit all security changes
CREATE AUDIT POLICY meridian_security_policy
CATEGORIES
SECMAINT STATUS BOTH,
SYSADMIN STATUS BOTH,
AUDIT STATUS BOTH,
VALIDATE STATUS BOTH
ERROR TYPE AUDIT;
AUDIT DATABASE USING POLICY meridian_security_policy;
-- Enhanced monitoring for DBA activity
CREATE AUDIT POLICY meridian_dba_policy
CATEGORIES
EXECUTE WITH DATA STATUS BOTH,
CONTEXT STATUS BOTH,
OBJMAINT STATUS BOTH
ERROR TYPE AUDIT;
AUDIT ROLE dba_operations USING POLICY meridian_dba_policy;
Security Verification Queries
After implementing the security model, run these verification queries to confirm correct configuration:
-- Verify no user holds both DBADM and SECADM
SELECT GRANTEE FROM SYSCAT.DBAUTH
WHERE DBADMAUTH = 'Y'
INTERSECT
SELECT GRANTEE FROM SYSCAT.DBAUTH
WHERE SECURITYADMAUTH = 'Y';
-- Expected: empty result set
-- List all roles and their members
SELECT r.ROLENAME, ra.GRANTEE, ra.GRANTEETYPE
FROM SYSCAT.ROLES r
JOIN SYSCAT.ROLEAUTH ra ON r.ROLENAME = ra.ROLENAME
ORDER BY r.ROLENAME, ra.GRANTEE;
-- List all RCAC permissions
SELECT CONTROLNAME, TABSCHEMA, TABNAME, CONTROLTYPE, ENABLE
FROM SYSCAT.CONTROLS
ORDER BY TABSCHEMA, TABNAME;
-- List all audit policies and their targets
SELECT AUDITPOLICYNAME, OBJECTTYPE, OBJECTSCHEMA, OBJECTNAME
FROM SYSCAT.AUDITUSE
ORDER BY AUDITPOLICYNAME;
-- Check for users with excessive privileges
SELECT GRANTEE, GRANTEETYPE,
CONTROLAUTH, ALTERAUTH, DELETEAUTH,
INSERTAUTH, SELECTAUTH, UPDATEAUTH
FROM SYSCAT.TABAUTH
WHERE TABSCHEMA = 'MERIDIAN'
ORDER BY GRANTEE;
Security Model Summary
The complete Meridian security architecture follows defense in depth:
| Layer | Mechanism | What It Protects |
|---|---|---|
| Network | SSL/TLS, firewall rules | Data in transit |
| Authentication | RACF (z/OS) / LDAP+Kerberos (LUW) | Identity verification |
| Authorization | Roles + GRANT/REVOKE | Object-level access |
| Row Security | RCAC row permissions | Branch-level data isolation |
| Column Security | RCAC column masks | PII protection (SSN, account numbers) |
| Encryption | Native DB encryption + SSL/TLS | Data at rest and in transit |
| Audit | Audit policies on tables, roles, database | Regulatory compliance trail |
| Monitoring | DBA-specific audit, separation of duties checks | Insider threat detection |
Spaced Review: Chapters 4, 12, and 17
These questions revisit material from earlier chapters to strengthen long-term retention. Answer from memory before checking.
From Chapter 4: Data Types and Table Design
-
What is the difference between CHAR(10) and VARCHAR(10) in terms of storage? CHAR(10) always stores exactly 10 bytes, padding shorter values with spaces. VARCHAR(10) stores only the actual characters plus a 2-byte length prefix. For columns where values vary in length, VARCHAR saves significant storage. For fixed-length codes (state abbreviations, currency codes), CHAR is more efficient.
-
Why does Meridian Bank use DECIMAL(15,2) instead of FLOAT for monetary amounts? FLOAT uses binary floating-point representation, which introduces rounding errors in decimal calculations. DECIMAL(15,2) stores exact decimal values. In banking, a rounding error of even one cent across millions of transactions creates reconciliation failures and regulatory findings.
-
What constraint would you use to ensure that an account balance never goes negative? A CHECK constraint:
ALTER TABLE accounts ADD CONSTRAINT chk_balance CHECK (balance >= 0);. This enforces the rule at the database level regardless of which application performs the update.
From Chapter 12: Indexes and Query Performance
-
When would you create a composite index on (branch_id, account_type) versus two separate indexes? A composite index is preferred when queries frequently filter on both columns together (
WHERE branch_id = 101 AND account_type = 'CHECKING'), because the index can satisfy the entire predicate in a single lookup. Separate indexes require index ANDing, which is less efficient. However, if queries also frequently filter on account_type alone (without branch_id), a separate index on account_type may be needed — a composite index is useful only when the leading columns are specified. -
How does RCAC interact with indexes? When RCAC row permissions filter rows, DB2 applies the permission predicate to the query. The optimizer can use indexes to efficiently evaluate these predicates. If a row permission filters by
branch_id, an index onbranch_idimproves performance for RCAC-filtered queries. Design your indexes with RCAC predicates in mind.
From Chapter 17: Backup, Recovery, and High Availability
-
If a security breach is detected at 2:00 PM, how does the recovery strategy change? Point-in-time recovery becomes relevant. You can restore a backup and roll forward logs to a point before the breach occurred, but this means losing all legitimate transactions after that point. A better approach: identify the specific unauthorized changes from audit logs and reverse them with compensating transactions, preserving all legitimate work. This is why comprehensive audit logging is not optional — it is your forensic evidence.
-
Are audit logs included in database backups? Why does this matter? On LUW, audit logs are separate from database backups. They must be archived independently. If you restore a database from backup but lose the audit logs, you have no record of what happened during the lost period — which is a compliance violation. Ensure audit log archival is part of your backup strategy.
Summary
Security is not a feature — it is an architecture. In this chapter, you have learned:
- DB2 separates authentication (external) from authorization (internal), a design that delegates identity verification to specialized systems while keeping access control within the database engine.
- Privileges follow the principle of least privilege: GRANT only what is needed, at the most specific level possible (column before table, table before schema, schema before database).
- Roles simplify privilege management by creating named collections of privileges that map to job functions, with role hierarchies that mirror organizational structures.
- RCAC provides row-level and column-level security that cannot be bypassed through direct table access — essential for multi-tenant data, branch-scoped access, and PII protection.
- Trusted contexts bridge the gap between three-tier architectures and individual accountability, enabling per-user audit trails and RCAC enforcement even when all connections come through a shared service account.
- Audit policies provide the evidence trail that compliance demands: who accessed what, when, and from where.
- Encryption protects data at rest and in transit, with DB2 supporting native database encryption, SSL/TLS, and integration with enterprise key management systems.
The Meridian National Bank security model demonstrates how all these layers work together: roles define what each job function can do, RCAC limits what data each person can see, trusted contexts ensure individual accountability through shared application servers, and audit policies record everything for regulatory compliance.
In the next chapter, we will turn to performance monitoring and tuning — because a secure database that cannot meet its performance SLAs is a secure database that will be bypassed by frustrated developers. Security and performance must coexist, and we will show you how.
Return to Chapter 19 | Continue to Exercises | Quiz | Key Takeaways
Related Reading
Explore this topic in other books
Advanced COBOL Mainframe Security Advanced COBOL CICS Security Learning COBOL z/OS Security Model