Security best practices¶
This guide is designed to help configure DataRobot following security best practices. DataRobot is a complex product with a wealth of configuration options -- at the time of writing (Jan 2023), this guide covers a small number of them and may be extended over time.
To configure these options, refer to the Tuning DataRobot Environment Variables section of this guide.
Session expiration¶
Leaving web UI sessions active forever is considered to be a security threat. DataRobot offers flexible control over the session expiration mechanism that allows you to configure session lifetime to be relative to last user visit or to expire after a certain amount of seconds after user login. Once a webui session has expired, a user must re-login and re-authenticate before they can get access to the application again.
Control over the session expiration logic is done by the boolean configuration option WEB_UI_SESSION_ABSOLUTE_EXPIRATION_ENABLED, which determines if the session lifetime should be treated as relative to last user action (request) or absolute to user login.
The lifetime (in seconds) of the session is configured by the WEB_UI_SESSION_LIFE_TIME configuration option. The default value is 0 which means that session lasts forever.
Configuration examples¶
The following configuration options in core.config_env_vars set session lifetime to 10 minutes relative to last user action:
# helm chart values snippet
core:
config_env_vars:
WEB_UI_SESSION_LIFE_TIME: 600
The following configuration options in core.config_env_vars set session lifetime to 10 minutes from the moment of user login:
# helm chart values snippet
core:
config_env_vars:
WEB_UI_SESSION_LIFE_TIME: 600
WEB_UI_SESSION_ABSOLUTE_EXPIRATION_ENABLED: true
Host header protection¶
To prevent host header poisoning, API servers validate the host header against an allowed list.
By default, the ALLOWED_HOSTS includes:
EXTERNAL_WEB_SERVER_URLfor the external load balancer (and for situations there is a proxy in front of the application)DATAROBOT_PUBLIC_LBfor theglobal.domainchart values setting for the application hostname when accessed via Ingress.DATAROBOT_INTERNAL_LBfor the service hostname within the Kubernetes cluster (e.g.datarobot-nginx) used by internal services.CUSTOM_MODEL_WEB_SERVER_URLfor a configurable hostname used by Custom Models for connecting to the API server
If necessary, the ALLOWED_HOSTS setting can be configured in chart values, using a comma-delimited string of hostnames:
core:
config_env_vars:
ALLOWED_HOSTS: "datarobot-nginx,datarobot.example.com"
Although not recommended, to disable host header protection:
core:
config_env_vars:
ALLOWED_HOSTS: "*"
Integrate with customer HTTP proxy¶
It may be required to use a HTTP proxy for providing cluster access to specific resources over the internet or within the corporate network. To accomplish this, users may have a HTTP proxy such as Squid proxy configured to route cluster traffic.
Note
This configuration requires a lot of customization and maintenance to keep up-to-date with upgrades of DataRobot or to reflect changes to your internal infrastructure.
To achieve this, network traffic from application services needs to be routed to the proxy, but ensuring that internal traffic to services within the cluster remains internal and skips the proxy. The following environment variables can be configured globally for all containers:
HTTP_PROXYfor proxying HTTP traffic within the cluster through an external proxyHTTPS_PROXYfor proxying HTTPS traffic within the cluster through an external proxyNO_PROXYfor excluding certain hostnames from routing through the proxy. This should be a comma-separated list of hostnames.
These can be configured in the Helm chart values:
global:
extraEnvVars:
- name: HTTP_PROXY
value: http://proxy.example.com:3128
- name: HTTPS_PROXY
value: http://proxy.example.com:3128
- name: NO_PROXY
value: .dr-app,.svc,.local,.internal,localhost,127.0.0.1,kubernetes,auth-server-hydra-admin,auth-server-hydra-public,blob-view-service,browser-adls,browser-bigquery,browser-controller,browser-databricks,browser-datasphere,browser-s3,browser-snowflake,build-service,buzok-llm-gateway,buzok-web,cfx-session-port-proxy,compute-jobs-service,compute-spark,custom-apps-websocket-proxy,datarobot-analyticsbroker-api,datarobot-analyticsbroker-ingest,datarobot-apigateway-apigateway,datarobot-apps-builder-api,datarobot-apps-builder-internal-api,datarobot-auth-server,datarobot-datasets-service-api,datarobot-internal-api,datarobot-mmapp,datarobot-mmqueue,datarobot-nginx,datarobot-otel-collector,datarobot-pngexport,datarobot-prediction-server,datarobot-prediction-spooler,datarobot-predictions-gateway,datarobot-public-api,datarobot-rsyslog-master,datarobot-tileservergl,datarobot-upload,datavolt-service,identity-resource-service,nbx-audit-logs,nbx-code-assistance,nbx-code-nuggets,nbx-data-retention,nbx-env-vars,nbx-exec-envs,nbx-filesystems,nbx-ingress,nbx-notebook-import,nbx-notebook-revisions,nbx-notebooks,nbx-orchestrator,nbx-permissions,nbx-scheduling,nbx-session-port-proxy,nbx-terminals,nbx-usage-tracking,nbx-users,nbx-vcs,nbx-websockets,network-policy-consumer-service,notification-service,oauth-providers-service,ocr-service,pcs-elasticsearch,pcs-elasticsearch-master-hl,pcs-mongo-0,pcs-mongo-1,pcs-mongo-2,pcs-mongo-arbiter-headless,pcs-mongo-headless,pcs-pgpool,pcs-postgresql,pcs-postgresql-headless,pcs-rabbitmq,pcs-rabbitmq-headless,pcs-redis,pcs-redis-headless,pred-environments-api,service-registration-controller
Make sure to replace proxy.example.com:3128 with your desired proxy address.
For internal service communications in Kubernetes, this covers all <service>.<namespace>.svc.cluster.local fully-qualified names for DataRobot services.
You MUST also add the following to NO_PROXY based on your configuration:
- The namespace where DataRobot is installed (e.g.
.dr-appby default; replace it if you use another namespace) - The ClusterIP associated with the Kubernetes API accessed by pods, as returned by
kubectl get svc kubernetes(e.g.10.100.0.1for EKS by default) - The
global.domainhost where users access your DataRobot application (e.g.datarobot.example.com) - Hostnames for cloud services endpoints when deployed into a VPC.
For cloud providers' service endpoints:
- AWS: you can specify
.amazonaws.comfor all regions or.<region>.amazon.aws.comto limit to a specific region such asus-east-1. See AWS Service Endpoints for the supported list of hostnames. - GCP: you can specify
.googleapis.comto allow list all services, otherwise refer to Access Google APIs through endpoints for supported list of hostnames. - Azure: see Azure Private Endpoints for a list of supported hostnames.
Additionally, you SHOULD add the following if they apply to your situation:
- Internal IP addresses for corporate networks that shouldn't be accessed through the proxy (e.g.
1.2.3.4). NOTE - CIDR ranges aren't supported due to limitations in python. - Internal hostnames for resources that are accessible without the tunnel proxy (e.g.
.example.com)
When upgrading to 10.2 or later, make sure to remove HTTP_PROXY, HTTPS_PROXY and NO_PROXY settings from other sections of the values YAML (e.g. core.common_env_vars). When set in global.extraEnvVars the settings should correctly be applied to all pods.
Network policy for custom workloads on long running services (LRS)¶
Custom workloads (custom models, custom jobs, custom apps) running on LRS have a deny-by-default NetworkPolicy setup, accompanied by Network Policies
to allow specific ingress or egress with external services as needed.
These pages explain the specifics to each workload:
LRS's egress for custom workloads is governed by CUSTOM_WORKLOADS_PUBLIC_ACCESS_RULES, a JSON list of {cidr, except} rules. CUSTOM_WORKLOADS_PUBLIC_ACCESS_IGNORE_CIDRS is shorthand for the except list of a single default rule.
Default value of CUSTOM_WORKLOADS_PUBLIC_ACCESS_RULES
{"cidr": "0.0.0.0/0", "except": ["10.0.0.0/8", "172.16.0.0/12", "192.168.0.0/16"]}
CUSTOM_WORKLOADS_PUBLIC_ACCESS_RULES overrides CUSTOM_WORKLOADS_PUBLIC_ACCESS_IGNORE_CIDRS entirely
Setting CUSTOM_WORKLOADS_PUBLIC_ACCESS_RULES directly replaces the default above, so CUSTOM_WORKLOADS_PUBLIC_ACCESS_IGNORE_CIDRS no longer has any effect once you do—the two settings are not merged.
Allow egress to internal destinations¶
Some workloads need to reach an internal destination even though the default rule above denies egress to internal networks.
Because Kubernetes network policy rules are additive, the supported way to allow egress to a specific internal destination is to add a second rule to CUSTOM_WORKLOADS_PUBLIC_ACCESS_RULES for that destination, alongside the existing rule. If you've already customized CUSTOM_WORKLOADS_PUBLIC_ACCESS_IGNORE_CIDRS (see Restrict egress to specific CIDR ranges), carry those same CIDR ranges into the first rule's except list instead of the defaults shown below—setting CUSTOM_WORKLOADS_PUBLIC_ACCESS_RULES replaces that customization entirely rather than merging with it. For example, to allow egress to a target internal service at 172.16.5.10 while keeping the default except CIDR ranges for everything else:
core:
config_env_vars:
CUSTOM_WORKLOADS_PUBLIC_ACCESS_RULES: '[{"cidr":"0.0.0.0/0","except":["10.0.0.0/8","172.16.0.0/12","192.168.0.0/16"]},{"cidr":"172.16.5.10/32","except":[]}]'
The first rule keeps denying egress to the standard private ranges; the second rule adds an allow for 172.16.5.10/32 specifically, regardless of the first rule's except list.
If the additional rule has no effect
Although NetworkPolicy rules are meant to be additive, some clusters don't apply a second rule this way in practice—the effective behavior can depend on the CNI plugin and how it compiles multiple rules. If egress to the destination is still denied after adding the rule above, exclude the destination from the except CIDR ranges directly instead, as described in Restrict egress to specific CIDR ranges—narrowing the except list doesn't depend on multi-rule behavior, since it changes what a single rule excludes rather than relying on a second rule to add exceptions.
Restrict egress to specific CIDR ranges¶
To restrict egress for LRS to specific CIDR ranges, the CUSTOM_WORKLOADS_PUBLIC_ACCESS_IGNORE_CIDRS setting can be configured in chart values:
core:
config_env_vars:
CUSTOM_WORKLOADS_PUBLIC_ACCESS_IGNORE_CIDRS: '10.0.0.0/8,172.16.0.0/12,192.168.0.0/16'
This should be a comma-delimited list of CIDR ranges. This setting has no effect if CUSTOM_WORKLOADS_PUBLIC_ACCESS_RULES is already set directly (see the warning above)—edit that setting's first rule's except list instead.
It's important that LRS can egress to the datarobot-nginx pod for workloads to use the Public API.
Workloads should be using the internal server name datarobot-nginx instead of the external hostname (e.g. datarobot.example.com).
In order for LRS to communicate with the Public API using Ingress, the Network Policy would need to be modified to allow egress to the
CIDR range covering the ingress controller.
To stop restricting an entire range when nothing else in it needs to stay restricted, remove it from the except list entirely (e.g. 172.16.0.0/12), for example:
core:
config_env_vars:
CUSTOM_WORKLOADS_PUBLIC_ACCESS_IGNORE_CIDRS: '10.0.0.0/8,192.168.0.0/16'
To exclude specific IP addresses from an except CIDR while keeping the rest of it restricted, split the range into smaller CIDR ranges that leave those addresses out (e.g. 172.16.5.10/32). Compute the complement of the destination address against the excepted range with Python's ipaddress.address_exclude to avoid manual CIDR-math errors, for example:
import ipaddress
excepted_range = ipaddress.ip_network("172.16.0.0/12")
destination_host = ipaddress.ip_network("172.16.5.10/32")
remaining_cidrs = sorted(excepted_range.address_exclude(destination_host))
print(",".join(str(cidr) for cidr in remaining_cidrs))
This prints the comma-delimited list of CIDR ranges to use in CUSTOM_WORKLOADS_PUBLIC_ACCESS_IGNORE_CIDRS in place of 172.16.0.0/12:
172.16.0.0/22,172.16.4.0/24,172.16.5.0/29,172.16.5.8/31,172.16.5.11/32,172.16.5.12/30,172.16.5.16/28,172.16.5.32/27,172.16.5.64/26,172.16.5.128/25,172.16.6.0/23,172.16.8.0/21,172.16.16.0/20,172.16.32.0/19,172.16.64.0/18,172.16.128.0/17,172.17.0.0/16,172.18.0.0/15,172.20.0.0/14,172.24.0.0/13
core:
config_env_vars:
CUSTOM_WORKLOADS_PUBLIC_ACCESS_IGNORE_CIDRS: '10.0.0.0/8,172.16.0.0/22,172.16.4.0/24,172.16.5.0/29,172.16.5.8/31,172.16.5.11/32,172.16.5.12/30,172.16.5.16/28,172.16.5.32/27,172.16.5.64/26,172.16.5.128/25,172.16.6.0/23,172.16.8.0/21,172.16.16.0/20,172.16.32.0/19,172.16.64.0/18,172.16.128.0/17,172.17.0.0/16,172.18.0.0/15,172.20.0.0/14,172.24.0.0/13,192.168.0.0/16'
This narrows the except set so only 172.16.5.10 (target internal service) falls outside the excepted range, while every other address in 172.16.0.0/12—including the rest of 172.16.5.0/24—remains restricted.
Wrangler on Spark with external object storage¶
If your cluster is configured with an external s3-compatible object store (e.g. Minio), you must ensure that LRS pods hosting the interactive spark session for Data Wrangling have egress to the object store.
If your cluster uses Cilium CNI, create the following CiliumNetworkPolicy. Make sure to replace DATAROBOT-NAMESPACE and MINIO-API-HOSTNAME-GOES-HERE accordingly.
apiVersion: cilium.io/v2
kind: CiliumNetworkPolicy
metadata:
name: allow-lrs-spark-app-access-to-external-object-store
namespace: DATAROBOT-NAMESPACE
spec:
endpointSelector:
matchLabels:
datarobot-type: lrs
egress:
- toFQDNs:
- matchName: "MINIO-API-HOSTNAME-GOES-HERE"
toPorts:
- ports:
- port: "443"
protocol: TCP
Without Cilium, configure a NetworkPolicy to allow egress to the IP addresses that the DNS hostname resolves to. Make sure to replace DATAROBOT-NAMESPACE and X.X.X.X accordingly.
apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
name: allow-lrs-spark-app-access-to-external-object-store
namespace: DATAROBOT_NAMESPACE
spec:
podSelector:
matchLabels:
datarobot-instance-name: datarobot-lrs
datarobot-lrs-type: spark_app
egress:
- ports:
- protocol: TCP
port: 443
to:
- ipBlock:
cidr: X.X.X.X/32
policyTypes:
- Egress
Set up custom DNS policies¶
A default configuration would create two policies for DNS access from LRS pods. The first policy is for standard DNS access in k8s cluster which covers all egress from LRSes to kube-dns pods on 53/5353 TCP/UDP ports. And the second policy covers the similar traffic but for OpenShift installations. Here are both policies:
apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
name: allow-kube-dns-egress
namespace: <installation_namespace>
spec:
egress:
- ports:
- port: 53
protocol: UDP
- port: 53
protocol: TCP
- port: 5353
protocol: UDP
- port: 5353
protocol: TCP
to:
- namespaceSelector: {}
podSelector:
matchLabels:
k8s-app: kube-dns
podSelector:
matchLabels:
datarobot-type: lrs
policyTypes:
- Egress
apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
name: allow-openshift-dns-egress
namespace: <installation_namespace>
spec:
egress:
- ports:
- port: 53
protocol: UDP
- port: 53
protocol: TCP
- port: 5353
protocol: UDP
- port: 5353
protocol: TCP
to:
- namespaceSelector: {}
podSelector:
matchLabels:
dns.operator.openshift.io/daemonset-dns: default
podSelector:
matchLabels:
datarobot-type: lrs
policyTypes:
- Egress
These policies should be enough to cover most cases. If any other custom policy is required then lrsEgressNetworkPolicies could be overwritten. For example, to define an egress DNS policy to pods with custom-label-name=custom-label-value selector on 53 UDP port in kube-system namespace. The overwritten piece should look like:
operator:
lrsEgressNetworkPolicies:
- name: "allow-custom-label-name-egress"
podSelectorLabel: "custom-label-name"
podSelectorValue: "custom-label-value"
namespaceSelector: "kube-system"
ports:
- protocol: "UDP"
port: 53
Note
The lrsEgressNetworkPolicies field can define any custom egress policy for LRSes, not only DNS-specific.
Security banner¶
DataRobot has the capability to display a Security Banner at the top of the screen.
Configuration¶
To configure these options, refer to the Tuning DataRobot Environment Variables section of this guide.
# helm chart values snippet
core:
config_env_vars:
SHOW_SECURITY_BANNER: True
SHOW_SECURITY_BANNER_COLOR: red
SHOW_SECURITY_BANNER_TEXT: This system has a security banner.
SHOW_SECURITY_BANNER¶
Default value: False Description: This environment variable controls the display of the banner. If it's False, then the banner isn't displayed.
SHOW_SECURITY_BANNER_COLOR¶
Default value: red Value choices: red, yellow, green Description: This controls the color of the banner and the text. The predefined choices are: * Red: Red background with white text * Yellow: Yellow background with black text * Green: Green background with white text
SHOW_SECURITY_BANNER_TEXT¶
Default value: 'Default banner text' Description: The text that's displayed in the banner. It's center aligned and it's recommended that the text be less than 100 characters long.
Tenancy enforcement¶
In DataRobot, privacy between organizations can be enforced through the ENABLE_MULTITENANCY_PRIVACY config.
9.0¶
By default, the config is set to true, which implies users with administrative roles (via RBAC) are unable to view, search, create, or modify entities (such as projects and deployments) outside their current organization.
If cross-organization visibility is necessary, ENABLE_MULTITENANCY_PRIVACY can be overridden to false in core.config_env_vars, however, this isn't a recommended practice in most cases.
9.1 and later¶
DataRobot in 9.1 requires all users to be a member of an Organization. The system now has a named default Organization. The database migration scripts in 9.1.0 place all users in the default Organization who aren't already members of an Organization.
Administrative roles (via RBAC) can view, search, create, or modify entities (such as projects and deployments) in their current organization. Additional Admin users are recommended per Organization to view all deployments/projects in a cluster.
Note: ENABLE_MULTITENANCY_PRIVACY cannot be disabled via config.
Seat licenses¶
The Seat License concept allows for detailed control over premium features.
Cluster administrators can manage the allocation of seat licenses to various organizations within the installation. At the same time, organization administrators can control the assignments of these allocated seats to users within their organization, enabling specific features for end users.
For 11.0, only the GenAI functionality is governed by the seat licenses, specifically through the GenAI Builder seat license.
Allocate seat licenses to organizations¶
To restrict the usage of seat licenses, a new license key that includes seat license limits must be applied.
A DataRobot engineer generates this key, which must include the limits corresponding to the seat licenses. For instance, genai_seat_licenses_limit param is used to restrict the number of GenAI Builder seats in the cluster.
Once the key is generated, it should be applied to the cluster by following these steps:
1. In the user settings page, turn on the Enable Application Management feature flag for the user who manages the cluster. The License page then appears in the admin menu.
2. Go to the License page, paste the license key provided by the DataRobot engineer into the New license key input field, and then press Validate.
3. If the validation is successful, a comparison between the new license and the current one appears. Press the Submit button. The License page displays the Seat Licenses section.
- Click on a specific Seat License card. A new
Allocate Seatssection appears for viewing the current allocations and creating new allocations for organizations. -
Click the
+ Allocate seatsbutton. A new modal window appears where you can search for an organization and allocate a number of seats to it. -
Click
Allocate. The organization admin then has access to theSeat Licenseadmin page for granting the seat to users.
Manage seat licenses assignments¶
To assign a seat to a user within your organization:
1. Navigate to the Seat License page in the admin menu. This page displays all seat licenses allocated to your organization, along with their limits and current number of assignments.
- Click on the specific seat license you want to assign. A new
Assigned seatssection appears, showing the users who currently have that seat. - Press the
+ Assign seatbutton to grant the seat to a new user. A modal window is displayed, allowing you to search for a user, view the number of remaining assignments, and remove existing user assignments. - Click the
Assignbutton. The page is updated with the new list of seat assignments. The user you assigned the seat to should now have access to the functionality associated with that seat license (for example, GenAI functionality for a GenAI Builder seat license).
Docker Hub artifacts¶
All images of DataRobot are available on Docker Hub under the DataRobot organization.
Authentication¶
Each repository requires a dedicated token, which is provided during the installation phase.
Endpoints¶
Docker Hub provides a curated list of endpoints for each type of service. To ensure complete connectivity, these are the required endpoints:
- https://auth.docker.io
- https://index.docker.io
- https://registry-1.docker.io
- https://production.cloudflare.docker.com