DLH.io Documentation logoDLH.io Documentation
AgentsSQL Server Agent

Security

How the DLH.io SQL Server Agent protects SQL Server passwords, API keys and storage credentials, what it sends over the network, and how to run it with least privilege.

The agent is designed for environments where the database must not be exposed to the internet and where credentials must stay inside your network. This page explains what is stored where, what leaves the host, and the controls you have.

Credentials at rest

SecretWhere it livesProtection
SQL Server passworddlh_sql_server_credentials.secEncrypted on the first run. The plaintext value in dlh_sql_server_credentials.yaml is replaced with <encrypted>.
DLH.io API key (dlh_ref.api_key)dlh_agent_config.yamlEncrypted in place on the first run; is_encrypted_api_key: true is set automatically.
Static storage credentials (dlh_storage, dlh_log_store, dlh_credential__* of type storage)dlh_agent_config.yamlSecret values are encrypted in place on the first run; is_encrypted_storage_password: true is set automatically.
SCM and API tokens (dlh_credential__* of type scm or api)dlh_agent_config.yamlEncrypted in place on the first run; is_encrypted_credential: true is set automatically.
Platform issued storage credentialsEncrypted bootstrap cache under %PROGRAMDATA%\DLH\dlh-agent-sql-serverShort-lived, refreshed from the platform, never written to your YAML files. Remove with --clear-credentials-cache.
Webhook URLsdlh_agent_config.yaml or an environment variableUse url_env_var to keep the URL out of the file entirely.
SendGrid API keydlh_agent_config.yaml or DLH_SENDGRID_API_KEYPrefer the environment variable.

Encryption key

All encrypted values use a single symmetric key. The agent looks for it in this order:

  1. The DLH_AGENT_SECRET_KEY environment variable (recommended for RMM and image-based deployments so that the key is never on disk next to the encrypted files).
  2. The dlh_agent_secret.key file in the agent directory, generated automatically on first run if it does not exist.

Treat the key like a password: back it up with the state database, restrict NTFS permissions on the agent directory to administrators and the service account, and do not copy it into support bundles. If the key is lost the agent cannot decrypt stored secrets; on the next interactive run it offers to re-enter the SQL Server credentials and, for the API key and storage secrets, you re-enter the plaintext values in the YAML and they are encrypted again.

Setting the key for the scheduled task

When you set DLH_AGENT_SECRET_KEY it must be visible to the account that runs the scheduled task (the service account), not only to the administrator who installed the agent. Set it as a system environment variable or in the task definition.

Least privilege

  • SQL Server: grant the agent login SELECT on the tables and views it syncs plus VIEW CHANGE TRACKING (CT) or membership in the CDC gating role. The agent never writes to the source database.
  • Windows: the installer creates a dedicated local account (svc_dlh_agent_runner) and grants it the Log on as a batch job and Log on as a service rights. The account needs Modify on the agent directory for state, logs and output.
  • Object storage: platform issued credentials are scoped to your connection's container or bucket. If you supply static credentials, scope the SAS token or IAM policy to the container / prefix the agent writes to (list, read, write, delete are required for Delta and Iceberg maintenance).

Network egress

The agent makes outbound HTTPS calls only. No inbound ports are opened.

DestinationPurposeCan it be disabled?
api.datalakehouse.ioLicense validation and storage credential bootstrap on each run; run start / completion / failure reportsBootstrap: no, but without it the agent runs in Community mode. Run reports: platform_run_report: false.
Amazon S3 or Azure Storage endpointsData and log uploadsOnly by running in Community mode (local output only).
hooks.slack.com, Microsoft Teams / Power Automate, your generic webhook hostAlertsdlh_notifications.enabled: false or remove the webhook entries.
api.sendgrid.comEmail alertsRemove the email settings.
api.github.com, gitlab.com, api.bitbucket.org, api-dbdeux.datalakehouse.ioLifecycle actionspost_completion_actions.enabled: false.
Microsoft download serversOnly when you run --install-driver --autoInstall the ODBC driver yourself instead.

--diagnose --offline performs every local check without any network access, which is useful on hosts that must be reviewed before egress rules are opened.

What is sent to the DLH.io platform

  • Bootstrap: your organization, project and connection GUIDs, the agent version and the API key. The response contains your tier and, for Customer and Trial accounts, short-lived storage credentials.
  • Run reports (platform_run_report): run identifier, start and end time, status, per-table row counts and outcomes (capped at 50 tables per report), error messages and the storage location of the shipped log folder. Row data is never included.
  • Log shipping to your dlh_log_store: the run log and a JSON run summary. Logs are scrubbed of passwords, keys, tokens and SAS signatures before upload.

Data handling

  • Row data is written only to the storage you configure (or the local output_path in Community mode). It is not sent to DLH.io servers.
  • Column masking (hash, partial, redact, round) is applied in memory before rows are written, so masked values never reach storage. See Data retrieval.
  • The audit trail (produce_audit_trail: true) writes per-table CT/CDC diagnostic files, including raw extracted rows, to the local audit/ folder. Disable it or shorten audit_trail_retention_days on hosts where local copies of source data are not acceptable.
  • The DuckDB state database contains sync pointers, schema metadata and run history. It does not contain row data.

Binary integrity

The agent ships as a single Windows executable with a private runtime folder. Builds are hardened against casual decompilation and the installer preserves your configuration, keys and state across upgrades. Report suspected tampering or a lost installer to DLH.io support.

Support bundles

When you send logs to support:

  1. Prefer the shipped log folder in your dlh_log_store (already scrubbed) or run --diagnose --json > diagnose.json, which redacts secrets.
  2. If you attach a local logs/dlh_agent_*.log, it contains hostnames and table names but no passwords or keys.
  3. Never attach dlh_agent_secret.key, dlh_sql_server_credentials.sec or the state database.