The thingsHub's tenants are managed and configured using the Kubernetes package manager helm. Helm charts are provided at https://helm.smartmakers.de and are documented below. Each tenant is managed with a separate release and therefore with a separate helm configuration.

Heads-up notice

The base configuration of a tenant, as initially created in Creating a Tenant, should only be changed with extra care after the initial creation of the tenant. In particular, this includes the tenant's name and domain, as well as the configuration options affecting where and how data is persisted.

Example configuration file

The following is an example of a minimal configuration of a thingsHub tenant.

Example Configuration File
global:
  domain: thingshub.smartmakers.de
  name: example

  security:
    service_key: <randomly-generated service key>
    admin_password: <randomly generated password>
	password_policy_regex: <user defined regular expression>
    password_help_text: <user defined help text to show on user form>

  sql:
    host: hostname.domain:port
    database: example
    user: example
    password: <the example role's passsword on the sql server>

  tls:
    enabled: true
    cert: |
      -----BEGIN CERTIFICATE-----
      ...
      -----END CERTIFICATE-----
      -----BEGIN CERTIFICATE-----
      ...
      -----END CERTIFICATE-----
      -----BEGIN CERTIFICATE-----
      ...
      -----END CERTIFICATE-----
    key: |
      ----BEGIN RSA PRIVATE KEY-----
      ...
      -----END RSA PRIVATE KEY-----
YML

Updating a tenant’s configuration

The thingsHub helm chart repository is added with the following command:

$ helm repo add smartmakers https://helm.smartmakers.de
...
$ helm repo update
...
$
CODE

The helm repo update command needs to be repeated before every upgrade to a newer version. To update a tenant configuration, first modify the config file as required, then run the helm tool with the following options:

$ helm upgrade --namespace <tenant> -f <tenant>.yaml <tenant> th-tenant
...
$
CODE

Helm chart configuration options

The thingsHub’s tenant chart is an umbrella chart which ties together multiple charts for the different services. Options which affect multiple sub-charts are put in the global section. Some of these options (wherever it makes sense) can be overridden for the sub-chart. These options are marked with an asterisk (*) at the end.

Name

Type

Description

global.domain

string

The base domain name, e.g. thingshub.smartmakers.de.

global.name

string

The name of the tenant, e.g. demo.

This must be alphanumeric, lowercase, and should be kept short but never longer than 63 characters. Dashes are allowed, neither in the beginning nor at the end and also never two consecutive ones.

This is concatenated with the value of global.domain to create the full domain name of the tenant, e.g. demo.thingshub.smartmakers.de.

global.logos.light_name

string

The file name of the logo file. The filename suffix is used to identify the file type, e.g. svg or png.

global.logos.light_content

base64

The contents of the logo file encoded in base64. On Linux, the command cat <file> | base64 can be used to conveniently encode the file.

Keep this small and prefer a scalable format (i.e. svg) over a raster image format (e.g. png or jpg).

Container Images

global.image.registry *

string

The name of the registry from which to pull the container images. By default, this is docker-registry.smartmakers.de.

global.image.repository *

string

This is the path to the repository with the repository naming being the concatenation of the repository option and the name below. By default, this is things-hub.

global.image.name *

string

The name of the container image to pull. This is only meant to be overridden by each subchart.

global.image.tag *

string

The name of the tag to select for the images. The default tag is the version of the chart itself, i.e. docker image versions are tied to helm chart versions.

global.image.credentials.username *

string

The name used for pulling the container images

global.image.credentials.password *

string

The password used for pulling the container images

global.image.pullPolicy *

string

A policy, deciding when images should be pulled. Can be Always (for debugging), Never (for local debugging or in air-gapped networks), IfNotPresent (default).

Security (Authentication & Transport Layer Security)

global.security.service_key

string

A service key, shared by the services for mutual authentication.

global.security.admin_password

string

The password of the admin user.

global.security.password_policy_regex

string

Contains a regular expression as a value and basically reflects the desired  complexity/security of the user's passwords. In other words, when a new user is created or an existing user is updated via the REST API, the given password is checked against the defined regular expression. If such a check fails,  "HTTP 400 Bad Request" error and a message "user's password doesn't match security policy" is returned by the service. The default security policy ensures that any newly created password would match a string of any symbols with length no less than 10.

global.security.password_help_text

string

Contains the string to display on the user creation form to help users understand what the requirement for the password policy is.

global.security.system_user_ip_whitelist

string

The IP subnets from which admin login to the thingsHub is allowed. This is a comma-separated list of CIDR address ranges, e.g. 1.2.3.4/24, to allow any host in the subnet 1.2.3.x admin access to the thingsHub. Note that a personalized user with role TenantOwner can still access the system from other IP addresses. This only affects the built-in admin user.

global.tls.enabled

boolean

Enabled Transport Layer Security. This requires global.tls.cert and global.tls.key to be set.

global.tls.cert

string

The PEM-encoded TLS certificate for the domain name in <global.name>.<global.domain>. It is strongly recommended that this option is set to contain the entire certificate chain (excluding the root CA certificate) with the domain's own certificate first.

global.tls.key

string

The matching key for the certficate in global.tls.cert.

global.tls.issuer

string

The name of the TLS certificate issuer when using CertManager.

global.tls.kind

string

The kind of TLS certificate issuer, either Issuer or ClusterIssuer.

PostgreSQL

global.sql.secret_ref.name

string

The name of the Kubernetes secret which contains the PosrtgreSQL database’s credentials.

global.sql.host

string

Hostname of the PostgreSQL server which hosts the tenants database. The default is postgresql.

global.sql.port

string

Port of the PostgreSQL server. The default is 5432.

global.sql.database

string

The database which stores the data of the different tenant’s services. The default is thingshub.

global.sql.user

string

The role with which the services shall access the PostgreSQL database. The default is thingshub.

global.sql.password

string

The password for the role with which the services shall access the PostgreSQL database.

global.sql.operator.enabled

string

Use the PostgreSQL operator to create the database secret.

global.sql.operator.server_ref

string

The database server on which the PostgreSQL operator shall create the database.

InfluxDB

global.influxdb.address

string

The hostname (with schema and port) of the InfluxDB server.

global.influxdb.user

string

The user with which to login to the InfluxDB server.

global.influxdb.password

string

The password for the above user.

global.influxdb.database

string

The database in which thingsHub shall store its data.

global.visualizer.auth.enabled

boolean

Set this to true to manage the Visualizer users with the thingsHub (recommended).

Email Notifications & SMTP

global.smtp.enabled

boolean

Enable SMTP notifications

global.smtp.address

string

The SMTP server’s address (e.g. smtp.gmail.com:587)

global.smtp.user

string

The username for logging into the SMTP server

global.smtp.password

string

The password for authentication at the SMTP server

global.smtp.host

string

The SMTP host name (this is usually identical to the address, except that this doesn’t contain the port, while the address usually does)

global.smtp.form

string

The “From” line of the email

Miscellaneous

global.node.selector *

string

The node selector to force deployment of the tenant’s pods on specific nodes.

When overriding this option, the two maps for the base and overridden selectors will be merged.

global.log.level *

string

The lowest level of logs which shall be generated. One of debug, info, warning, error, fatal. By default, this is warning.

global.mqtt.qos *

string

The quality of service with which data shall be sent to the built-in MQTT broker.

grafana.plugins.hostPath

string

Set this to a path on the Kubernetes host machine in which Grafana plugins are stored. Make sure that the contents of this path are identical on all nodes of the cluster, so that grafana behaves consistently.

For each version of grafana in use, introduce a separate subpath with the version number, e.g. if the path is /mnt/plugins and some tenants are running version 5.0.4, the plugins for this tenant should be in the path /mnt/plugins/5.0.4.

How to...

... set a logo for the index page

You require a logo in an image format supported by your browser. It is preferable to use a vector graphic (svg) over a raster image format. The logo must be supplied as a base64-encoded helm configuration option and suffix in the filename should match the real image type. Set the logo as in the example below:

global:
  logos:
    light_name: company-logo.png
    light_content: iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAYAAAAfFcSJAAAACklEQVR4nGMAAQAABQABDQottAAAAABJRU5ErkJggg==
YML

In order to convert the image to base64, you can use an online encoder such as: https://www.base64-image.de/ or search google for others. If you run a linux machine you can execute the following command

$ cat logo.png | base64 -w 0
iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAYAAAAfFcSJAAAACklEQVR4nGMAAQAABQABDQottAAAAABJRU5ErkJggg==
$
BASH

... generate a secure, random password on the command line

You can generate a secure, random password from the command line using the command line tool openssl:

$ openssl rand -base64 30
pNABkkecqQTdTrck9IzhrPgulvNY4qELUgaC3JDA
$
BASH

…change data retention policies

Retention policies cannot be set in the helm configuration, but need to be set directly in InfluxDB. For this, log into the InfluxDB with an admin user and execute the following commands:

ALTER RETENTION POLICY receptions_retention_policy ON <tenant-influxdb-name> DURATION 744h REPLICATION 1;
ALTER RETENTION POLICY thub_device_data ON <tenant-influxdb-name> DURATION 744h REPLICATION 1;
ALTER RETENTION POLICY logs_rp ON <tenant-influxdb-name> DURATION 744h REPLICATION 1;
ALTER RETENTION POLICY things ON <tenant-influxdb-name> DURATION 744h REPLICATION 1;
CODE

… create the PostgreSQL database secret

There are three ways to create a secret for the PostgreSQL database access:

Use a pre-defined secret

This is the default behavior. You create a secret of type Opaque or kubernetes.io/basic-auth with the fields hostname, port, database, username, password. Next you set the helm configuration option global.sql.secret_ref.name to the name of that secret. Now install the helm chart and all services will pick up the secret and connect to the SQL database.
This can also be used in combination with a tool such as terraform to create the secret.

Create a secret with the helm chart itself

Set the configuration options global.sql.hostname, global.sql.port, global.sql.database, global.sql.username, and global.sql.password. The helm chart will generate a secret automatically if it detects that the password option is set. The secret will be placed at global.sql.secret_ref.name. Note that with this option the secret is in the values.yaml file. As this file is usually checked into a version control system, this approach is depreciated.

Create a secret using the PostgreSQL operator

Do not set the any of the options from the above approach. Instead set the option global.sql.operator.enabled to true and the option global.sql.operator.server_ref to the name of the PostgreSQL server resource on which the database shall be created. The operator will create the database on the PostgreSQL server and then create the secret at global.sql.secret_ref.name for the tenant to use.

Password policy regex examples

The following examples for regular password policy checking regular expression can be used as inspiration for defining your own regular expressions:

Regular expression

Description

^.{8,}$

A password with at least 8 characters.

^(?=.*[A-Z])[A-Za-z\d@$!%*?&]{8,}$

Minimum eight characters, at least one uppercase letter

^(?=.*[a-z])(?=.*[A-Z])(?=.*\d)[A-Za-z\d@$!%*?&]{8,}$

Minimum eight characters, at least one uppercase letter, one lowercase letter and one number