Oracle Security Migration to Azure¶
Migrating Oracle security features to Azure: VPD/OLS to row-level security, TDE key migration, Oracle audit to Azure Monitor/Sentinel, Oracle roles to Azure RBAC, and network encryption.
Key principle
Oracle's security model is database-centric -- security is enforced inside the database engine. Azure's security model is platform-centric -- security is enforced across the platform (Entra ID, Key Vault, Azure Monitor, Defender) with database-level controls as one layer. Migration means moving from a single-layer database security model to a multi-layer platform security model.
1. Security model comparison¶
| Security domain | Oracle approach | Azure approach |
|---|---|---|
| Identity | Oracle users, roles, profiles | Entra ID + database roles |
| Authentication | Password, Kerberos, certificate, wallet | Entra ID (MFA, conditional access), managed identity |
| Authorization | Object privileges, system privileges, roles | Azure RBAC + database permissions |
| Row-level access | Virtual Private Database (VPD), Oracle Label Security (OLS) | Row-Level Security (RLS) policies |
| Encryption at rest | Transparent Data Encryption (TDE), tablespace encryption | TDE (included), storage encryption |
| Encryption in transit | Oracle Net encryption (sqlnet.ora) | TLS 1.2+ enforced by default |
| Data masking | Data Redaction | Dynamic Data Masking, static masking |
| Auditing | Unified Auditing, Fine-Grained Auditing | SQL Auditing, Azure Monitor, Microsoft Sentinel |
| Key management | Oracle Wallet, Oracle Key Vault | Azure Key Vault |
| Network security | Oracle Net ACL, firewall rules | VNet integration, Private Endpoints, NSGs |
2. Identity and authentication migration¶
2.1 Oracle users to Entra ID¶
-- Oracle: Database users with password authentication
CREATE USER app_user IDENTIFIED BY "ComplexP@ss123"
DEFAULT TABLESPACE users
QUOTA UNLIMITED ON users
PROFILE app_profile;
CREATE PROFILE app_profile LIMIT
PASSWORD_LIFE_TIME 90
PASSWORD_REUSE_TIME 365
PASSWORD_REUSE_MAX 12
FAILED_LOGIN_ATTEMPTS 5
PASSWORD_LOCK_TIME 1/24;
GRANT CREATE SESSION TO app_user;
GRANT SELECT ON hr.employees TO app_user;
-- Azure SQL MI: Entra ID authentication (recommended)
-- 1. Create Entra ID user (no password managed by database)
CREATE USER [app_user@agency.onmicrosoft.com] FROM EXTERNAL PROVIDER;
ALTER ROLE db_datareader ADD MEMBER [app_user@agency.onmicrosoft.com];
-- 2. Or create Entra ID group for role-based access
CREATE USER [DBA-Team-SecurityGroup] FROM EXTERNAL PROVIDER;
ALTER ROLE db_owner ADD MEMBER [DBA-Team-SecurityGroup];
-- 3. Managed identity for applications (no credentials to manage)
CREATE USER [app-managed-identity] FROM EXTERNAL PROVIDER;
GRANT SELECT ON dbo.employees TO [app-managed-identity];
-- PostgreSQL: Entra ID authentication
-- Configure in server parameters: azure.extensions = pgaadauth
-- Then create users mapped to Entra ID
SELECT * FROM pgaadauth_create_principal('app_user@agency.onmicrosoft.com', false, false);
GRANT SELECT ON ALL TABLES IN SCHEMA app_schema TO "app_user@agency.onmicrosoft.com";
2.2 Oracle roles to Azure RBAC + database roles¶
| Oracle role pattern | Azure equivalent |
|---|---|
DBA role | Entra ID group mapped to db_owner (database) + Azure RBAC SQL MI Contributor (platform) |
CONNECT role | Entra ID user with CREATE SESSION equivalent (login permission) |
RESOURCE role | db_ddladmin + db_datawriter |
SELECT_CATALOG_ROLE | db_datareader on system views |
| Custom application role | Custom database role with specific object permissions |
EXP_FULL_DATABASE | db_backupoperator |
3. Virtual Private Database (VPD) to Row-Level Security¶
VPD is one of Oracle's most powerful security features. It attaches security policies to tables that automatically inject WHERE clause predicates based on the session context.
3.1 Oracle VPD example¶
-- Oracle VPD: Restrict employees to see only their department's data
CREATE OR REPLACE FUNCTION dept_security_policy(
p_schema IN VARCHAR2,
p_object IN VARCHAR2
) RETURN VARCHAR2 IS
v_dept_id NUMBER;
BEGIN
-- Get current user's department from context
v_dept_id := SYS_CONTEXT('HR_CTX', 'DEPARTMENT_ID');
IF v_dept_id IS NOT NULL THEN
RETURN 'department_id = ' || v_dept_id;
ELSE
RETURN '1=0'; -- No access if no department context
END IF;
END;
/
-- Apply policy to table
BEGIN
DBMS_RLS.ADD_POLICY(
object_schema => 'HR',
object_name => 'EMPLOYEES',
policy_name => 'DEPT_ACCESS_POLICY',
function_schema => 'HR',
policy_function => 'DEPT_SECURITY_POLICY',
statement_types => 'SELECT,INSERT,UPDATE,DELETE'
);
END;
/
3.2 Azure SQL MI Row-Level Security equivalent¶
-- Azure SQL MI: Row-Level Security
-- 1. Create schema for security predicates
CREATE SCHEMA Security;
GO
-- 2. Create predicate function
CREATE FUNCTION Security.fn_dept_security_predicate(
@department_id int
)
RETURNS TABLE
WITH SCHEMABINDING
AS
RETURN SELECT 1 AS fn_result
WHERE @department_id = (
SELECT department_id
FROM dbo.user_department_mapping
WHERE user_name = SUSER_SNAME()
)
OR IS_MEMBER('db_owner') = 1; -- DBA bypass
GO
-- 3. Create security policy
CREATE SECURITY POLICY Security.DeptAccessPolicy
ADD FILTER PREDICATE Security.fn_dept_security_predicate(department_id)
ON dbo.employees,
ADD BLOCK PREDICATE Security.fn_dept_security_predicate(department_id)
ON dbo.employees AFTER INSERT,
ADD BLOCK PREDICATE Security.fn_dept_security_predicate(department_id)
ON dbo.employees AFTER UPDATE
WITH (STATE = ON);
GO
3.3 PostgreSQL Row-Level Security equivalent¶
-- PostgreSQL: Row-Level Security
-- 1. Enable RLS on the table
ALTER TABLE employees ENABLE ROW LEVEL SECURITY;
-- 2. Create policy
CREATE POLICY dept_access_policy ON employees
USING (
department_id = (
SELECT department_id
FROM user_department_mapping
WHERE user_name = current_user
)
OR current_user IN (SELECT rolname FROM pg_roles WHERE rolsuper)
);
-- 3. Force RLS for table owner too (optional)
ALTER TABLE employees FORCE ROW LEVEL SECURITY;
4. Oracle Label Security (OLS) migration¶
OLS provides multi-level security with labels (classification levels, compartments, and groups). There is no direct equivalent in Azure SQL MI or PostgreSQL.
4.1 OLS to RLS conversion pattern¶
-- Oracle OLS: Row labeled with security classification
-- Labels: UNCLASSIFIED, CUI, SECRET, TOP_SECRET
-- Users have maximum label clearance
-- Azure SQL MI equivalent: Classification column + RLS
-- 1. Add classification column to table
ALTER TABLE sensitive_documents ADD security_level nvarchar(20) NOT NULL DEFAULT 'UNCLASSIFIED';
-- 2. Create user-clearance mapping table
CREATE TABLE dbo.user_clearance (
user_name nvarchar(128) PRIMARY KEY,
max_clearance_level int NOT NULL -- 0=UNCLASS, 1=CUI, 2=SECRET, 3=TS
);
-- 3. Create clearance-level mapping
CREATE TABLE dbo.clearance_levels (
level_name nvarchar(20) PRIMARY KEY,
level_order int NOT NULL
);
INSERT INTO dbo.clearance_levels VALUES
('UNCLASSIFIED', 0), ('CUI', 1), ('SECRET', 2), ('TOP_SECRET', 3);
-- 4. Create RLS predicate that enforces clearance
CREATE FUNCTION Security.fn_classification_predicate(
@security_level nvarchar(20)
)
RETURNS TABLE WITH SCHEMABINDING AS
RETURN SELECT 1 AS result
WHERE (
SELECT cl.level_order FROM dbo.clearance_levels cl WHERE cl.level_name = @security_level
) <= (
SELECT uc.max_clearance_level FROM dbo.user_clearance uc WHERE uc.user_name = SUSER_SNAME()
);
-- 5. Apply security policy
CREATE SECURITY POLICY Security.ClassificationPolicy
ADD FILTER PREDICATE Security.fn_classification_predicate(security_level)
ON dbo.sensitive_documents
WITH (STATE = ON);
5. TDE encryption migration¶
5.1 Oracle TDE to Azure SQL MI¶
Oracle TDE encrypts data at rest using tablespace or column-level encryption with keys stored in an Oracle Wallet or Oracle Key Vault.
Azure SQL MI TDE is automatic and included at no additional cost:
-- Oracle: TDE configuration
ALTER SYSTEM SET ENCRYPTION KEY IDENTIFIED BY "wallet_password";
ALTER TABLESPACE users ENCRYPTION USING 'AES256' ENCRYPT;
-- Azure SQL MI: TDE is enabled by default
-- No configuration needed for service-managed keys
-- For customer-managed keys (BYOK):
-- 1. Create key in Azure Key Vault
-- az keyvault key create --vault-name kv-feddb --name tde-key --kty RSA --size 2048
-- 2. Configure SQL MI to use customer-managed key
-- az sql mi tde-key set --server-key-type AzureKeyVault \
-- --kid "https://kv-feddb.vault.azure.net/keys/tde-key/..." \
-- --managed-instance mi-instance \
-- --resource-group rg-prod
5.2 PostgreSQL encryption¶
PostgreSQL on Azure uses storage-level encryption (AES-256) by default. Column-level encryption uses pgcrypto:
-- PostgreSQL: Column-level encryption (pgcrypto)
CREATE EXTENSION IF NOT EXISTS pgcrypto;
-- Encrypt sensitive column
UPDATE employees
SET ssn_encrypted = pgp_sym_encrypt(ssn, 'encryption_key')
WHERE ssn IS NOT NULL;
6. Audit migration¶
6.1 Oracle Unified Auditing to Azure Monitor¶
-- Oracle: Unified audit policy
CREATE AUDIT POLICY sensitive_data_access
ACTIONS SELECT ON hr.employees,
UPDATE ON hr.employees,
DELETE ON hr.employees;
AUDIT POLICY sensitive_data_access;
-- Oracle: Fine-grained auditing
BEGIN
DBMS_FGA.ADD_POLICY(
object_schema => 'HR',
object_name => 'EMPLOYEES',
policy_name => 'FGA_SALARY_ACCESS',
audit_column => 'SALARY,SSN',
statement_types => 'SELECT'
);
END;
/
-- Azure SQL MI: SQL Auditing (automatic, logs to Azure Monitor)
-- Enabled via Azure Portal or CLI:
-- az sql mi audit-policy update \
-- --resource-group rg-prod \
-- --managed-instance mi-instance \
-- --state Enabled \
-- --storage-account staudit \
-- --log-analytics-target-state Enabled \
-- --log-analytics-workspace-resource-id /subscriptions/.../workspaces/law-prod
-- Query audit logs in Log Analytics
-- AzureDiagnostics
-- | where Category == "SQLSecurityAuditEvents"
-- | where statement_s contains "employees"
-- | project TimeGenerated, server_principal_name_s, statement_s, response_rows_d
-- PostgreSQL: pgAudit extension
-- Enable in server parameters: shared_preload_libraries = 'pgaudit'
CREATE EXTENSION IF NOT EXISTS pgaudit;
-- Configure audit logging
ALTER SYSTEM SET pgaudit.log = 'read, write, ddl';
ALTER SYSTEM SET pgaudit.log_catalog = 'off';
ALTER SYSTEM SET pgaudit.log_relation = 'on';
-- Object-level auditing
ALTER ROLE auditor SET pgaudit.role = 'auditor';
GRANT SELECT ON hr.employees TO auditor;
-- Now all SELECT on hr.employees is audited
6.2 Integration with CSA-in-a-Box audit framework¶
CSA-in-a-Box provides a tamper-evident audit path (CSA-0016) that integrates with Azure Monitor:
- Database audit logs flow to Azure Monitor / Log Analytics
- Log Analytics forwards to Microsoft Sentinel for security analytics
- Purview audit tracks data access across the analytics platform
- The tamper-evident audit logger provides hash-chained evidence for compliance
7. Network security migration¶
| Oracle network security | Azure equivalent |
|---|---|
Oracle Net Encryption (sqlnet.ora SQLNET.ENCRYPTION_SERVER) | TLS 1.2+ enforced by default |
Oracle Net ACL (DBMS_NETWORK_ACL_ADMIN) | VNet integration + Network Security Groups |
Firewall rules (TCP.VALIDNODE_CHECKING) | Private Endpoints + NSG rules |
| Oracle Connection Manager (CMAN) | Azure Application Gateway or VNet peering |
| Oracle Wallet for client certificates | Azure Key Vault + managed certificates |
7.1 Private Endpoint configuration¶
# Azure SQL MI: Already deployed in a VNet (inherently private)
# External access is controlled by the MI's public endpoint setting
# PostgreSQL: Create Private Endpoint
az network private-endpoint create \
--resource-group rg-prod \
--name pe-postgres-prod \
--vnet-name vnet-prod \
--subnet snet-data \
--private-connection-resource-id /subscriptions/.../flexibleServers/pg-prod \
--group-id postgresqlServer \
--connection-name pg-prod-connection
8. Compliance mapping¶
| Oracle security feature | Compliance control | Azure equivalent | CSA-in-a-Box evidence |
|---|---|---|---|
| TDE | NIST AC-3, SC-28 | TDE / storage encryption | nist-800-53-rev5.yaml SC-28 |
| VPD | NIST AC-3, AC-4 | Row-Level Security | nist-800-53-rev5.yaml AC-3 |
| Unified Auditing | NIST AU-2, AU-3, AU-6 | Azure SQL Auditing + Monitor | nist-800-53-rev5.yaml AU-2 |
| Network encryption | NIST SC-8, SC-13 | TLS 1.2+ enforced | nist-800-53-rev5.yaml SC-8 |
| Oracle Wallet | NIST SC-12 | Azure Key Vault | nist-800-53-rev5.yaml SC-12 |
| Database Vault | NIST AC-6, CM-7 | Azure RBAC + no sa access | nist-800-53-rev5.yaml AC-6 |
Maintainers: csa-inabox core team Last updated: 2026-04-30