SAP HANA — prerequisites and accounts

What to create on your SAP HANA instance (SAP HANA, express edition or any HANA 2.0 SPS0x deployment — single-container or multi-tenant/MDC) so DBSheriff can monitor it. Everything below is a standard user, grant, or audit policy; DBSheriff installs nothing on the server. Run the statements inside the tenant database your data lives in (connect via hdbsql -d <tenant> or the SYSTEMDB tenant-routing database= option), not against SYSTEMDB. HANA is always self-managed — there is no cloud-managed HANA variant this guide needs to branch on.

The three scripts

On an installed host there is no scripts/ folder, so read every scripts/<name>.py below as sudo /opt/dbsheriff/current/deploy/onprem/stack.sh tool <name> ..., for example sudo /opt/dbsheriff/current/deploy/onprem/stack.sh tool setup_dbsheriff hana hana-01.acme.internal. The scripts/ form is for a source checkout. The details are under "How to start the scripts" in Before you install: creating DBSheriff's database users.

Script What it does Example
setup_dbsheriff.py Recommended. One command: checks/enables the prerequisites, then creates the accounts. scripts/setup_dbsheriff.py hana hana-01.acme.internal
install_prereqs.py Prerequisites only — run this alone if you want to review each step separately before creating any accounts. scripts/install_prereqs.py hana hana-01.acme.internal
create_reset_dbuser.py Accounts only — creates or resets them once prerequisites are already in place. scripts/create_reset_dbuser.py hana hana-01.acme.internal

All three ask for the tenant database name (never SYSTEMDB) and connect only as a database user — never a cloud credential. install_prereqs.py offers to apply global_auditing_state and the DBSHERIFF_AUTH policy (§3), asking "Apply now?" for each; setup_dbsheriff.py applies global_auditing_state, and applies the DBSHERIFF_AUTH policy only when you add --optional-prereqs=dbsheriff_auth_policy — both apply live, no restart needed. The DBSHERIFF_DML/DBSHERIFF_DDL policies stay manual, since each needs an explicit schema/table target list only you can choose (§3). Add --dry-run to any of them to preview without changing anything, or --check for a read-only status report — see pre installation database users for the full flag reference shared by every engine.

0. What must be enabled on the server

The Without it column says what DBSheriff loses when an item is missing, so you can decide what to enable. Nothing optional or recommended stops the product: detection, response, and the evidence pack run on the required items alone.

Item Required? What it unlocks Without it How
The five accounts of §1 with the grants of §2 required everything: statements, sessions, kill, lock, throttle, posture, classification DBSheriff cannot connect or cannot act §2
AUDIT READ for the monitor and posture accounts required for the audit source SYS.AUDIT_LOG returns real rows. Without it, SYS.AUDIT_LOG still resolves as a queryable view but silently returns zero rows — no error, just no data login/statement audit events, failed-login visibility, PS61-63 all silently see nothing §2
global_auditing_state = true (§3) required for any audit trail every CREATE AUDIT POLICY below actually writes records PS09 fails; no audit-based auth or statement evidence at all §3 — automated by install_prereqs.py/setup_dbsheriff.py
Audit policy DBSHERIFF_AUTH (CONNECT), §3 recommended successful and failed logins with client IP — the H3 (Authentication review) evidence section no auth-failure visibility at all (HANA has no other source for this); PS61 flags the coverage gap §3 — offered by install_prereqs.py; setup_dbsheriff.py applies it only with --optional-prereqs=dbsheriff_auth_policy
Audit policies DBSHERIFF_DML (SELECT/INSERT/UPDATE/DELETE on classified tables) and DBSHERIFF_DDL (CREATE/ALTER/DROP TABLE), §3 recommended reads/writes of classified tables with the real user, client IP, and statement text — the H1 (Classified-table access) evidence section; DBSHERIFF_DDL is the fallback DDL feed for the live security-scoring pipeline (used only when M_EXECUTED_STATEMENTS cannot be read), and its audit records also go to the compliance/governance trail — see §5 without DBSHERIFF_DDL, a normal-speed CREATE/ALTER/DROP TABLE is still scored from M_EXECUTED_STATEMENTS; it is invisible to live kill/lock scoring only if that view cannot be read (see §5) §3 — manual only, each needs a schema/table list only you can choose
WORKLOAD ADMIN for the lock account required for the throttle response rung DBSheriff can cap a risky user's statement thread/memory via CREATE WORKLOAD CLASS/CREATE WORKLOAD MAPPING — no edition gate, live-verified on Express (unlike Oracle's Resource Manager, which needs Enterprise Edition and isn't implemented at all for Oracle in this product) the throttle response silently has nothing to apply §2
SELECT ... WITH GRANT OPTION on each classified schema for the lock account required for the revoke response rung DBSheriff can REVOKE/GRANT SELECT on a classified table on a risky user's behalf REVOKE_TABLE fails with insufficient privilege — HANA has no GRANT ANY OBJECT PRIVILEGE equivalent; you must be the object owner or hold the privilege WITH GRANT OPTION yourself §2
CATALOG READ for the monitor, kill, lock, and posture accounts required every SYS.M_*/SYS.* monitoring and catalog view the producer, kill/lock pre-checks, and posture scan cannot see sessions, users, or privileges at all §2

The floor. The five accounts with CATALOG READ + SESSION ADMIN (kill) + USER ADMIN (lock) gives you live statement monitoring, kill, and lock — DBSheriff's core detection and response. The audit policies and AUDIT READ add the compliance/evidence layer (auth failures, statement history with real identity) that M_ACTIVE_STATEMENTS/M_SQL_PLAN_CACHE alone can't provide. WORKLOAD ADMIN and the schema WITH GRANT OPTION add the two graduated-response rungs (throttle, revoke).

1. The five accounts

Account What it does Grants
hana_monitor reads M_ACTIVE_STATEMENTS/M_CONNECTIONS (live), M_SQL_PLAN_CACHE (completed/burst), M_BLOCKED_TRANSACTIONS (lock waits), SYS.AUDIT_LOG CATALOG READ, AUDIT READ
hana_kill_user disconnects sessions (ALTER SYSTEM DISCONNECT SESSION) SESSION ADMIN, CATALOG READ
hana_lock_user deactivates/reactivates users, terminates their open sessions, the throttle and revoke response rungs USER ADMIN, SESSION ADMIN, CATALOG READ, WORKLOAD ADMIN, SELECT ... WITH GRANT OPTION on each classified schema
hana_posture (optional — the monitor is used when absent) the posture scan and the hourly governance collection CATALOG READ, AUDIT READ
dbsheriff_classify reads column metadata and samples values for classification SELECT on the schemas to scan

If you want a test or victim account for your own validation, create it yourself — it is not one of DBSheriff's accounts and no script creates it. None of the five holds SYSTEM ADMIN, DATA ADMIN, AUDIT ADMIN, or CATALOG ADMIN. Posture (PS63) flags any other account holding AUDIT ADMIN/CATALOG ADMIN as a tampering-exposure risk — DBSheriff's own accounts are exempt by name pattern.

CREATE USER hana_monitor PASSWORD "<pick a strong password>" NO FORCE_FIRST_PASSWORD_CHANGE;
GRANT CATALOG READ TO hana_monitor;
GRANT AUDIT READ TO hana_monitor;

CREATE USER hana_kill_user PASSWORD "<pick a strong password>" NO FORCE_FIRST_PASSWORD_CHANGE;
GRANT SESSION ADMIN TO hana_kill_user;
GRANT CATALOG READ TO hana_kill_user;

CREATE USER hana_lock_user PASSWORD "<pick a strong password>" NO FORCE_FIRST_PASSWORD_CHANGE;
GRANT USER ADMIN TO hana_lock_user;
GRANT SESSION ADMIN TO hana_lock_user;
GRANT CATALOG READ TO hana_lock_user;
GRANT WORKLOAD ADMIN TO hana_lock_user;
-- per classified schema (repeat for every schema holding a CRITICAL/SENSITIVE table):
GRANT SELECT ON SCHEMA <schema> TO hana_lock_user WITH GRANT OPTION;

CREATE USER hana_posture PASSWORD "<pick a strong password>" NO FORCE_FIRST_PASSWORD_CHANGE;
GRANT CATALOG READ TO hana_posture;
GRANT AUDIT READ TO hana_posture;

CREATE USER dbsheriff_classify PASSWORD "<pick a strong password>" NO FORCE_FIRST_PASSWORD_CHANGE;
GRANT SELECT ON SCHEMA <schema> TO dbsheriff_classify;   -- repeat per schema to scan

2. Grant reference (why each one is needed)

scripts/setup_dbsheriff.py hana <hostname> --optional-prereqs=dbsheriff_auth_policy   # automates global_auditing_state + DBSHERIFF_AUTH below (without the flag: global_auditing_state only)

Enable auditing once, instance-wide (by hand, or automated by the command above):

ALTER SYSTEM ALTER CONFIGURATION ('global.ini','SYSTEM')
  SET ('auditing configuration','global_auditing_state')='true' WITH RECONFIGURE;

Known gotcha, live-verified: SYS.M_INIFILE_CONTENTS returns one row per configuration layer (DEFAULT, SYSTEM, DATABASE, HOST) for the same key — after the ALTER SYSTEM above, a fresh instance shows DEFAULT='FALSE' (factory baseline) and SYSTEM='true'/DATABASE='true' (the active override) simultaneously. Always read the most specific layer present, never assume there's only one row.

Then three policies — login/logout (also automated by the command above, since it needs no schema/table target), DML on your classified tables (repeat the ON clause for every table/schema; there's no wildcard-schema form — stays manual), and the fallback fast-DDL detection on each schema you want covered (also manual, same reason; DBSheriff uses it only if M_EXECUTED_STATEMENTS cannot be read, see §5):

CREATE AUDIT POLICY DBSHERIFF_AUTH AUDITING ALL CONNECT LEVEL INFO TRAIL TYPE TABLE RETENTION 90;
ALTER AUDIT POLICY DBSHERIFF_AUTH ENABLE;

CREATE AUDIT POLICY DBSHERIFF_DML AUDITING ALL SELECT, INSERT, UPDATE, DELETE
  ON <schema1>.<table1>, <schema2>.<table2>
  LEVEL INFO TRAIL TYPE TABLE RETENTION 90;
ALTER AUDIT POLICY DBSHERIFF_DML ENABLE;

-- Fallback DDL feed (see §5): DBSheriff reads DDL from M_EXECUTED_STATEMENTS
-- and uses this policy only if that view cannot be read — repeat the ON
-- clause for every schema you want DDL coverage on; there's no
-- wildcard-schema form here either.
CREATE AUDIT POLICY DBSHERIFF_DDL AUDITING ALL CREATE TABLE, ALTER TABLE, DROP TABLE
  ON SCHEMA <schema1>
  LEVEL INFO TRAIL TYPE TABLE RETENTION 90;
ALTER AUDIT POLICY DBSHERIFF_DDL ENABLE;

Note TRAIL TYPE TABLE RETENTION <days> (not just TRAIL TYPE TABLE) is required on multi-tenant (MDC) systems — omitting the retention clause fails with feature not supported: No audit trail types on multidb systems, except TABLE with RETENTION.

Records land in SYS.AUDIT_LOG (columns: TIMESTAMP, USER_NAME, APPLICATION_NAME, CLIENT_IP, EVENT_ACTION, EVENT_STATUS, SCHEMA_NAME, OBJECT_NAME, STATEMENT_STRING, AUDIT_POLICY_NAME, ...) — readable by any account holding AUDIT READ.

HANA also ships a built-in MandatoryAuditPolicy that always logs security-relevant DDL (CREATE/ALTER/DROP AUDIT POLICY, and similar) — no setup needed for that one.

4. Verification

-- global auditing actually on (read the effective layer, not just any row)
SELECT LAYER_NAME, VALUE FROM SYS.M_INIFILE_CONTENTS
  WHERE SECTION='auditing configuration' AND KEY='global_auditing_state';

-- policies enabled
SELECT AUDIT_POLICY_NAME, IS_AUDIT_POLICY_ACTIVE, EVENT_ACTION FROM SYS.AUDIT_POLICIES;

-- audit trail actually has content (as hana_monitor / hana_posture, not SYSTEM)
SELECT COUNT(*) FROM SYS.AUDIT_LOG;

-- live query capture
SELECT s.CONNECTION_ID, c.USER_NAME, s.STATEMENT_STRING
  FROM SYS.M_ACTIVE_STATEMENTS s JOIN SYS.M_CONNECTIONS c ON s.CONNECTION_ID = c.CONNECTION_ID;

Expected producer log line on first successful poll: [<server>][live-poll] nothing new next poll in <n>s (or a captured statement if one was running) — no M_ACTIVE_STATEMENTS/M_CONNECTIONS/M_SESSION_CONTEXT query failed error.

5. Known limitations

Fast DDL is read from SYS.M_EXECUTED_STATEMENTS, not from the live poll. SYS.M_SQL_PLAN_CACHE never caches DDL statements at all (live-reconfirmed: zero rows for any CREATE/ALTER/DROP TABLE), and the live poll of SYS.M_ACTIVE_STATEMENTS (every second by default; the interval can be changed in the Admin Console) is longer than a typical CREATE/ ALTER/DROP TABLE's real runtime (80-100ms) — so a normal-speed DDL statement is seen by neither. DBSheriff therefore reads DDL from SYS.M_EXECUTED_STATEMENTS, which HANA keeps by default: it needs no audit policy and no setup, and each statement goes through the exact same scoring pipeline every other completed HANA event uses. Only if that view cannot be read does DBSheriff fall back to the DBSHERIFF_DDL audit policy (§3), read from SYS.AUDIT_LOG; it never reads both at once, so a DDL statement is not scored twice. The fallback needs no new grant: the existing monitor account already holds AUDIT READ (§2). DDL slow or blocked enough to also be caught live via M_ACTIVE_STATEMENTS is unaffected — still scored and killed exactly as before.

Connecting to the target securely

setup_dbsheriff.py, create_reset_dbuser.py, install_prereqs.py and onboard_target.py connect as your administrator, and the administrator password and every new account's password cross that connection, so they verify the server's certificate by default (--ssl-mode verify-full; --ca-file <bundle> names the CA, for HANA a PEM trust store (sslTrustStore); --ssl-mode verify-ca skips only the host-name comparison). A refused certificate stops the run and the message names the flag; --ssl-mode require encrypts without verifying (an explicit opt-down that prints a warning) and --ssl-mode disable --allow-plaintext sends everything in clear text (a trusted private link only). A generated password is never printed: it is stored in the registry (encrypted), or written to a new mode-600 file (--credentials-file) whose path is shown. Account names must match [A-Za-z][A-Za-z0-9_]*, and every database, schema or warehouse name the scripts discover is quoted as an identifier before it goes into a statement.