erpl-rev is a registered external RFC server: a C++ process registers a PROGRAM_ID at the SAP gateway, and ABAP calls it via a type-T RFC destination. This is the part SAP Basis scrutinises most. The guidance below is what makes the solution safe to run in production (and not the dev shortcut we used while building it).
⚠️ The dev/test setup usedgw/acl_mode=0(open gateway). Never do that in production. Use an explicitreginfoallow-list as below.
| Piece | What it is |
|---|---|
erpl_rev_server |
external C++ process, registers PROGRAM_ID=ERPL_REV at the gateway |
RFC destination ERPL_REV |
type T, registration mode (method='R'), points at the gateway |
Function group ZERPL_REV |
the 5 RFC FMs ABAP calls (Z_DUCKDB_QUERY/INGEST/OPEN/FETCH/CLOSE) |
| RFC user | the user under which ABAP→server calls run / the server is reached |
ABAP→server traffic carries table data (SAP business data leaving the system), so it must be access-controlled and, off-box, encrypted (SNC).
Allow only this program to register, only from the server's host. Maintain
via SMGW → Goto → Expert Functions → External Security → Maintain ACL Files
(or the files referenced by gw/reg_info).
# reginfo — one line, no wildcards on TP/HOST
P TP=ERPL_REV HOST=<server-host-or-ip> ACCESS=<as-host> CANCEL=<as-host>
# deny everything else
P TP=* HOST=*local* ACCESS=*local* CANCEL=*local*
D TP=*
TP= the PROGRAM_ID (exact, no*).HOST= the host(s) the server runs on (FQDN/IP; comma-list if HA). No*.CANCEL= who may cancel the registration (keep tight).- Keep
gw/acl_mode=1(default) so the ACL is enforced.
secinfo is for started programs; our server is registered, so secinfo
needs no entry for it (leave it restrictive for everything else).
If the server runs on a different host than the gateway, protect the channel with SNC (SAP CommonCryptoLib on both ends, X.509 key pairs/PSE):
- Server: NW RFC SDK SNC params (
SNC_LIB,SNC_MYNAME,SNC_PARTNERNAME). - Gateway:
snc/enable=1, and require SNC for the registration. - Same-host loopback only → SNC optional but still recommended.
Create a dedicated Communications-type user (no dialog logon) for the FM calls and give it only the delivered role:
- Role
ZERPL_REV_RFC→S_RFCfor function groupZERPL_REVonly (RFC_TYPE=FUGR,RFC_NAME=ZERPL_REV,ACTVT=16). Nothing else. - The replicator/console reports run under the end user's own authorizations,
gated by who may execute them (
S_PROGRAM/ transaction). CDS views enforce their DCL automatically; a raw-table dynamicSELECTis not implicitlyS_TABU-checked, so restrict report execution accordingly. The native (ADBC) BW calc-view path reads cross-client — treat it as privileged. - Do not grant
S_RFC = *. Do not reuseDDIC/SAP*.
Minimal S_RFC authorization (PFCG):
S_RFC: ACTVT=16, RFC_TYPE=FUGR, RFC_NAME=ZERPL_REV
- Put the FMs on a UCON communication assembly (enforcement mode) so only explicitly exposed FMs are RFC-callable.
- Enable gateway security logging (
gw/logging) and alert on denied registrations/calls. ReviewSMGWregularly.
- Run as a non-root service account; see
deploy/erpl-rev.service. - Credentials for external publish targets (Postgres/DuckLake/object store) go in
the server's
--init-file(CREATE SECRET / ATTACH), never on the RFC wire, never in ABAP. Restrict that file to the service account (chmod 600). - The quack network listener is ON by default, bound to loopback
(
quack:localhost:9494) and always token-protected. It is what theerpl-rev sql/syncsubcommands use to reach a running server, so turning it off means those commands only work while the server is stopped.--no-quack(orERPL_REV_NO_QUACK=1) disables it entirely.- Exposing it beyond loopback requires an explicit non-loopback
--quack-listen; only then isallow_other_hostnamepassed. - Pin the token with
--quack-tokenand treat it as a secret. When quack generates one, it is written to the runtime state file below rather than only logged.
- The runtime state file (
$XDG_RUNTIME_DIR/erpl-rev/server.json, mode0600) records the listen URI, the quack token and the pid so a CLI process on the same host can find the server. It holds a secret: it is written atomically, never world-readable, and removed at shutdown. On a shared host, anyone who can read it can query the DuckDB — which is the same trust boundary as the DuckDB file itself.
- The RFC service user the running server connects as needs only
S_RFC(ACTVT=16,RFC_TYPE=FUGR,RFC_NAME=ZERPL_REV) — the eightZ_DUCKDB_*modules and nothing else. It needs no developer rights. - The user who runs
erpl-rev setupneedsS_DEVELOP(OBJTYPE=CLAS,ACTVT01 and 02, plus PROG/INTF/TABL), because setup creates and activates ABAP. This is a developer authorisation; do not grant it to the service user. On a production system, import the transport instead (docs/INSTALL.md) and never run setup there at all. - The
syncandreplicatesubcommands need no SAP authorisation onceZCL_ERPL_REV_CLIDRVis deployed. They write the command into a DuckDB table and the driver executes it, so the parameters travel as data and nothing is created in SAP. With--queue-onlythe CLI does not contact SAP at all: the periodicERPL_REV_DELTAjob drains the queue. Without the driver they fall back to generating a temporary class, which does needS_DEVELOP—doctorreports which of the two applies. erpl-rev doctorneeds neither: it only reads, and it reports whetherS_DEVELOPis present so the gap is visible before anyone tries to deploy.
- Non-modifying: ships only
Z*objects in packageZERPL; modifies no SAP standard repository/customizing objects; no kernel/core changes. - No background daemons inside SAP; the only persistent process is the external server you control.
- Uninstall = delete the
ZERPLpackage (transport of copies / object deletion), remove the destination + reginfo line, stop the server.