# Datalore On-Premises security considerations

> **Tip:**
> We strongly advise applying the principle of least privilege when deploying Datalore and its infrastructure.
>
>
>
> For example, if AWS is used as an infrastructure provider, it is crucial that for deployment purposes you use a dedicated IAM account, not the AWS root account.

> **Note:**
> This section covers only Datalore On-Premises-specific aspects. See [Security](security.html) for more information about generic security topics, applicable to both Datalore editions.

## Permissions

Procedure: Runtime

> **Warning:**
> While Datalore itself does not require any admin or elevated privileges within its runtime environment, its notebook agents are expected to be spawned as privileged containers.

Datalore notebook agent relies on two things which require elevated access to the runtime: [CRI-U](https://criu.org/Main_Page) and FUSE mounts within the containers. Both of these things require at least `SYS_ADMIN` capability granted to the runtime, otherwise Reactive mode and attached files won't work properly.

For the same reason, Datalore operational capacity is limited on environments with limited permission scope, like AWS Fargate.

If you need to deploy Datalore within communal infrastructure, we recommend that you provision a dedicated set of host machines specifically for Datalore compute agents.

You can configure Datalore to [use sidecar containers](use-sidecar-container.html) for launching agents without elevated privileges.

We are currently working on more ways to reduce the scope of permissions required.

Procedure: Database

Make sure the Postgres' user for provisioning Datalore has CREATE privileges. This ensures proper execution of ALTER TABLE/COLUMN commands derived from Datalore SQL migrations. EXECUTE privilege is also required.

## Configure TLS certificates for Datalore

Datalore does not provide any TLS-related options to its end users. Instead, it relies on third-party load balancers (or reverse proxies) to perform such a termination. As a consequence, the Datalore app itself is not normally expected to be user-faced directly without some intermediary proxy deployed next to Datalore.

> **Tip:**
> The same steps are applicable for the Hub deployment, if required.

Docker-based deployment:

This procedure describes creating another container with Nginx that will work as a reverse proxy with SSL termination.

> **Note:**
> The code examples are provided for illustration purposes. Pay attention to the comments in the examples.

Procedure:

1. Edit the `docker-compose.yaml` file as shown in the example below.

```YAML
services:
    datalore:
        image: jetbrains/datalore-server:2026.3
        expose: [ "8080", "8081", "5050", "4060" ]
        networks:
            - datalore-agents-network
            - datalore-backend-network
        volumes:
            - "datalore-storage:/opt/data"
            - "/var/run/docker.sock:/var/run/docker.sock"
        environment:
            # change to your domain name
            DATALORE_PUBLIC_URL: "https://datalore.example.com"
            # change to your password
            DB_PASSWORD: "changeme"

    # The following block is not required if the external database is used.
    postgresql:
        image: jetbrains/datalore-postgres:2024.4
        expose: [ "5432" ]
        networks:
            - datalore-backend-network
        volumes:
            - "postgresql-data:/var/lib/postgresql/data"
        environment:
            # change to your password
            POSTGRES_PASSWORD: "changeme"

    nginx:
        image: nginx:1.26
        networks:
            - datalore-backend-network
        volumes:
            # Adjust accordingly, as needed.
            - nginx-selfsigned.crt:/etc/ssl/certs/nginx-selfsigned.crt
            - dhparam.pem:/etc/nginx/dhparam.pem
            - nginx-selfsigned.key:/etc/ssl/private/nginx-selfsigned.key
            - ssl.conf:/etc/nginx/conf.d/ssl.conf
        ports:
            - 80:80
            - 443:443
volumes:
    postgresql-data: { }
    datalore-storage: { }
networks:
    datalore-agents-network:
        name: datalore-agents-network
    datalore-backend-network:
        name: datalore-backend-network
```

2. Edit the nginx `ssl.conf` file as shown in the example below.

```
server {
    listen 443 ssl;
    server_name datalore.example.com;
    # change to your cert and key, accordingly
    ssl_certificate /etc/ssl/certs/nginx-selfsigned.crt;
    ssl_certificate_key /etc/ssl/private/nginx-selfsigned.key;

    ssl_protocols TLSv1.3;
    ssl_prefer_server_ciphers on;

    # If absent, can be generated with
    # openssl dhparam -out dhparam.pem 4096
    ssl_dhparam /etc/nginx/dhparam.pem;

    ssl_ciphers EECDH+AESGCM:EDH+AESGCM;
    ssl_ecdh_curve secp384r1;
    ssl_session_timeout  10m;
    ssl_session_cache shared:SSL:10m;
    ssl_session_tickets off;

    # Comment the following two lines out
    # if the self-signed certificate is used.
    ssl_stapling on;
    ssl_stapling_verify on;

    location / {
        proxy_http_version 1.1;
        proxy_set_header Upgrade $http_upgrade;
        proxy_set_header Connection "upgrade";
        proxy_set_header X-Forwarded-Proto "https";
        proxy_pass http://datalore:8080;
    }
}

server {
    listen 80 default_server;
    server_name _;
    return 301 https://$host$request_uri;
}
```

3. [Restart the Compose stack.](restart-shutdown.html#restart_docker)

Helm-based deployment:

Procedure:

We advise to use either self-acquired certificate and private key (either self-generated or acquired from the trusted certificate authority), or Let's Encrypt as an alternative.

1. Perform the following steps based on a selected method:

Self-acquired certificate and private key:

1.  Create a Kubernetes TLS secret, following the [official Kubernetes guidance](https://kubernetes.io/docs/concepts/configuration/secret/#tls-secrets).

2.

Adjust the `datalore.values.yaml` file, as follows, replacing `datalore.example.com` with your actual FQDN you're going to use with Datalore.

```YAML
ingress:
    enabled: true
    tls:
        - secretName: datalore-tls
          hosts:
              - datalore.example.com
    hosts:
        - host: datalore.example.com
          paths:
              - path: /
                pathType: Prefix
    annotations:
        nginx.ingress.kubernetes.io/proxy-body-size: 8m
        kubernetes.io/ingress.class: nginx
```

Let's Encrypt:

> **Note:**
> In this guidance, it's assumed that NGINX Ingress Controller is used.

1.  Install [CertManager](https://cert-manager.io/docs/installation/kubectl/) into your Kubernetes cluster.

2.  Create a `letsencrypt.yaml` with the following content, replacing the placeholders as required:

```YAML
apiVersion: cert-manager.io/v1
kind: Issuer
metadata:
    name: letsencrypt-prod
spec:
    acme:
        server: 'https://acme-v02.api.letsencrypt.org/directory'
        email:
            - PLACE YOUR EMAIL HERE
        privateKeySecretRef:
            name: letsencrypt-prod
        solvers:
            - http01:
                  ingress:
                      ingressClassName: nginx
```

3.  Apply the manifest: `kubectl apply -f letsencrypt.yaml`

4.

Check the `kubectl get issuer`. Eventually, it should become as follows:

```
kubectl get issuer                                                          1 ↵
NAME                  READY   AGE
letsencrypt-prod      True    14d
```

5.

Adjust the `datalore.values.yaml` file, as follows, replacing `datalore.example.com` with your actual FQDN you're going to use with Datalore.

```YAML
ingress:
    enabled: true
    tls:
        - secretName: datalore-tls
          hosts:
              - datalore.example.com
    hosts:
        - host: datalore.example.com
          paths:
              - path: /
                pathType: Prefix
    annotations:
        nginx.ingress.kubernetes.io/proxy-body-size: 8m
        kubernetes.io/ingress.class: nginx

```

2. Set the `DATALORE_PUBLIC_URL` parameter in the  same `datalore.values.yaml` file. Use the same value you provided to replace `"https://datalore.example.com"` in the step above.

```YAML
dataloreEnv:
    DATALORE_PUBLIC_URL: "https://datalore.example.com"
```

3. Apply the configuration and [restart Datalore.](restart-shutdown.html#restart_kubernetes)

4. Check whether the ingress controller registered the changes: `kubectl get ingress`. The expected result is a `datalore` ingress with the 443 port exposed.

5. Check whether the certificate is issued: `kubectl get certificates`. The expected output is similar to the one below.

```SHELL
kubectl get certificates
NAME           READY   SECRET         AGE
datalore-tls   True    datalore-tls   8m5s
```

## Configuring the Datalore server database connection

> **Note:**
> This section is applicable for Helm-based deployment only.

Procedure:

1. Generate the password and store it in the [Kubernetes secret](https://kubernetes.io/docs/tasks/configmap-secret/managing-secret-using-kubectl/), as described below. The `pwgen` tool is used here as an example. You can use any other tool or method to generate a password.

```SHELL
PASSWORD=$(pwgen -N1 -y 32)
kubectl create secret generic datalore-db-password --from-literal=DATALORE_DB_PASSWORD="$PASSWORD"
```

2. Modify (or add, if not present yet) the `databaseSecret` block in your `datalore.values.yaml` as follows:

```YAML
databaseSecret:
  create: false
  name: datalore-db-password
  key: DATALORE_DB_PASSWORD
```

The value of the name value is referring to a secret name defined at the previous step, while the key value is referring to the key within the secret that contains the password.

> **Tip:**
> If, for any reason, you do not want to create a secret manually, you may specify the password in the Helm config file. In this case, the secret will be provisioned automatically - but keep in mind that the password will be stored in plain text in your configuration file.
>
>
>
> In that scenario, adjust the `databaseSecret` block in `datalore.values.yaml`, as follows:
>
>
>
>
> ```YAML
> databaseSecret:
> create: true
> password: xxxx
> ```

3. (Optional) If you are moving from plain text password storage to the secret reference: remove the `password` key with its value from the `databaseSecret` block.

4. Proceed based on whether this is your fresh deployment or Datalore is already installed.

Fresh deployment:

Proceed with the installation. No further action is required.

Datalore is already installed:

Apply the configuration

> **Warning:**
> If you proceed with this step, the Datalore server will restart.

`helm upgrade --install -f datalore.values.yaml datalore datalore/datalore --version 0.2.45`

## Database password rotation

Datalore requires a permanent connection to a PostgreSQL database to operate properly. Once Datalore is deployed, the database password is saved within the environment so Datalore can re-use it later once restarted.

However, you might want to change this password later due to various compliance or operational reasons.

> **Tip:**
> Changing the password in PostgreSQL itself is outside of the scope of this guide. Below you will find a guidance on updating the password within Datalore context after having it updated on the database server.

Kubernetes:

Procedure:

1. Locate the `values.yaml` file being used for the deployment.

2. Depending on the method used: either replace the password within the `databaseSecret` block, OR update the secret value if the Kubernetes secret is used instead of the plain-text value.

3. Update the Datalore deployment: `helm upgrade --install -f datalore.values.yaml datalore datalore/datalore --version 0.2.45`

4. [Restart Datalore.](restart-shutdown.html#restart_kubernetes)

Docker:

Procedure:

1. Locate the `docker-compose.yaml` file being used for the deployment.

2. Update the `DB_PASSWORD` block in `environment` block.

3. [Restart Datalore.](restart-shutdown.html#restart_docker)

Procedure: Configure TLS between server and agent

Perform the following procedures in the Configuration menu of the Admin panel.

Force TLS encryption:

Procedure:

1. Click the avatar in the upper right corner and select Admin panel from the menu.

2. From the Admin panel, select Configuration.

3. Select the Force agent SSL checkbox.

> **Note:**
> Backward compatibility with old agents without encryption is supported.

Perform certificates rotation:

Procedure:

> **Warning:**
> This procedure will enforce Datalore's root CA certificate to be re-generated. As a consequence, all the currently running computations will terminate abnormally once this procedure is completed.

1. Click the avatar in the upper right corner and select Admin panel from the menu.

2. From the Admin panel, select Configuration.

3. Click the Reset secrets button.

