Prerequisites
Business clusters images
In order to run your Neos cluster in the Kubernetes environment, you will need to provide for each cluster a Docker image of the backend and frontend parts. If your cluster calls background server methods, you will also need to provider a Docker image of the task-runner.
These images should be based on the same Neos version as the application version of the Helm chart.
Important
Docker image tags used in the examples below are illustrative.
Some examples use explicit pinned tags for reproducibility, while others keep a convenience tag for readability.
Choosing, updating, and patching base images (for example mcr.microsoft.com/dotnet/aspnet or nginx) is the responsibility of the team operating the deployment.
In production, prefer explicit and traceable tags.
From the framework perspective, the technical requirement is compatibility with the expected .NET minor version (for example .NET 10.x), not a specific patch tag or Linux distribution tag.
Warning
Keep the base image updated over time. Security fixes are delivered through image updates, so stale image tags can expose known vulnerabilities.
Backend example
# syntax=docker/dockerfile:1.28
# Use this dockerfile to generate technicaldemos-backend image.
#
# Build arguments :
# - NEOS_VERSION : neos-fmk image version to use for cluster generation (default: latest)
#
# /!\ The build command has to be run from the cluster root directory context :
# docker build -t technicaldemos-backend:{version} -f ./docker/backend.Dockerfile --build-arg NEOS_VERSION={version} . #from technicaldemos root directory
ARG NEOS_VERSION=latest
# To build the application, we use a neos-fmk image as base so we can directly run the neos commands
FROM "harbor.hexanet.fr:8443/neos/neos-fmk:${NEOS_VERSION}" AS builder
COPY ./modules /usr/src/technicaldemos/modules
COPY ./*.yml /usr/src/technicaldemos/
# The persistence configuration is mandatory for the build but it can be overridden in the appsettings.json file
RUN echo 'PersistenceType: PostgreSQL' > /usr/src/technicaldemos/technicaldemos.persistence.yml
# /!\ DONT PUT YOUR REAL CONNECTIONSTRING HERE /!\
# We just want to generate the application so we need to set a value but it will not be used by the process.
# In production the connectionstring should be overridden either by :
# - mounting a specific appsettings.json file
# - setting the PersistenceSettings__ConnectionString environment variable
RUN echo 'ConnectionString: None' >> /usr/src/technicaldemos/technicaldemos.persistence.yml
WORKDIR /usr/src/technicaldemos
# We only need to build the server part of the cluster
RUN neos generate --build-configuration Release Server
# The backend will run inside a container having dotnet installed
# Use the most recent available tag of the image for the .NET version your cluster targets
FROM mcr.microsoft.com/dotnet/aspnet:10.0.14-alpine3.24
# Install globalization functionality
RUN apk add --upgrade --no-cache \
icu-data-full \
icu-libs \
tzdata
ENV DOTNET_SYSTEM_GLOBALIZATION_INVARIANT=false
# Copy the result of the AspNetCore application build into the dotnet image
COPY --from=builder /usr/src/technicaldemos/server/bin/TechnicalDemos.AspNetCore/ /app
# Create an unprivileged user to run the application in an isolated directory (/app)
RUN addgroup -g 1001 -S neos && adduser -u 1001 -S -G neos neos && chown -R neos /app
USER 1001
WORKDIR /app
# Indicates the port on with the backend will be listening
ENV ASPNETCORE_URLS=http://+:7000
# When the container is started, it will run the application backend server
ENTRYPOINT ["dotnet", "TechnicalDemos.AspNetCore.dll"]
Task-runner example
# syntax=docker/dockerfile:1.28
# Use this dockerfile to generate technicaldemos-task-runner image.
#
# Build arguments :
# - NEOS_VERSION : neos-fmk image version to use for cluster generation (default: latest)
#
# /!\ The build command has to be run from the cluster root directory context :
# docker build -t technicaldemos-task-runner:{version} -f ./docker/task-runner.Dockerfile --build-arg NEOS_VERSION={version} . #from technicaldemos root directory
ARG NEOS_VERSION=latest
# To build the application, we use a neos-fmk image as base so we can directly run the neos commands
FROM "harbor.hexanet.fr:8443/neos/neos-fmk:${NEOS_VERSION}" AS builder
COPY ./modules /usr/src/technicaldemos/modules
COPY ./*.yml /usr/src/technicaldemos/
# The persistence configuration is mandatory for the build but it can be overridden in the appsettings.json file
RUN echo 'PersistenceType: PostgreSQL' > /usr/src/technicaldemos/technicaldemos.persistence.yml
# /!\ DONT PUT YOUR REAL CONNECTIONSTRING HERE /!\
# We just want to generate the application so we need to set a value but it will not be used by the process.
# In production the connectionstring should be overridden either by :
# - mounting a specific appsettings.json file
# - setting the PersistenceSettings__ConnectionString environment variable
RUN echo 'ConnectionString: None' >> /usr/src/technicaldemos/technicaldemos.persistence.yml
WORKDIR /usr/src/technicaldemos
# We only need to build the server part of the cluster
RUN neos generate --build-configuration Release Server
# The task-runner will run inside a container having dotnet installed
# Use the most recent available tag of the image for the .NET version your cluster targets
FROM mcr.microsoft.com/dotnet/aspnet:10.0.14-alpine3.24
# Install globalization functionality
RUN apk add --upgrade --no-cache \
icu-data-full \
icu-libs \
tzdata
ENV DOTNET_SYSTEM_GLOBALIZATION_INVARIANT=false
# Copy the result of the task-runner application build into the dotnet image
COPY --from=builder /usr/src/technicaldemos/server/bin/TechnicalDemos.TaskRunner/ /app
# Create an unprivileged user to run the application in an isolated directory (/app)
RUN addgroup -g 1001 -S neos && adduser -u 1001 -S -G neos neos && chown -R neos /app
USER 1001
WORKDIR /app
# Indicates the port on with the task-runner will be listening
ENV ASPNETCORE_URLS=http://+:7000
# When the container is started, it will run the application task-runner server
ENTRYPOINT ["dotnet", "TechnicalDemos.TaskRunner.dll"]
Frontend example
Important
Neos generates a static frontend (client/dist). It can be served by any static hosting solution (Nginx, Apache, Caddy, object storage + CDN, Kubernetes ingress static hosting, etc.).
The Nginx-based Dockerfile below is only one possible implementation.
Warning
Keep the base image updated over time. Security fixes are delivered through image updates, so stale image tags can expose known vulnerabilities.
# syntax=docker/dockerfile:1.28
# Use this dockerfile to generate technicaldemos-frontend image.
#
# Build arguments :
# - NEOS_VERSION : neos-fmk image version to use for cluster generation (default: latest)
#
# Use this dockerfile to generate technicaldemos-frontend image.
# /!\ The build command has to be run from the cluster root directory context :
# docker build -t technicaldemos-frontend:{version} -f ./docker/frontend.Dockerfile --build-arg NEOS_VERSION={version} . #from technicaldemos root directory
ARG NEOS_VERSION=latest
# To build the application, we use a neos-fmk image as base so we can directly run the neos commands
FROM "harbor.hexanet.fr:8443/neos/neos-fmk:${NEOS_VERSION}" AS builder
COPY ./modules /usr/src/technicaldemos/modules
COPY ./*.yml /usr/src/technicaldemos/
# The persistence configuration is mandatory for the build but it can be overridden in the appsettings.json file
RUN echo 'PersistenceType: PostgreSQL' > /usr/src/technicaldemos/technicaldemos.persistence.yml
# /!\ DONT PUT YOUR REAL CONNECTIONSTRING HERE /!\
# We just want to generate the application so we need to set a value but it will not be used by the process.
# In production the connectionstring should be overridden either by :
# - mounting a specific appsettings.json file
# - setting the PersistenceSettings__ConnectionString environment variable
RUN echo 'ConnectionString: None' >> /usr/src/technicaldemos/technicaldemos.persistence.yml
WORKDIR /usr/src/technicaldemos
# Build the cluster
RUN neos generate --build-configuration Release
WORKDIR /usr/src/technicaldemos/client
# Build the client website
RUN npm install
RUN npm run build
# Example only: using Nginx to serve the generated static files
# Always pin the base image to an explicit, fixed tag (never a floating tag such as
# "stable-alpine-slim") so every build is reproducible and doesn't silently pick up a
# newer, heavier image over time.
FROM nginx:1.31.6-alpine-slim
# Provides some basic nginx configuration
COPY ./docker/frontend/nginx/nginx.conf /etc/nginx/conf.d/default.conf
# Copy the client website files into the nginx serving directory
COPY --from=builder /usr/src/technicaldemos/client/dist /usr/share/nginx/html
With nginx.conf file :
server_tokens off;
server {
listen 80;
server_name frontend;
underscores_in_headers on;
root /usr/share/nginx/html;
location / {
rewrite ^/$ /index.html break;
try_files $uri =404;
add_header Cache-Control "no-cache";
}
location /index.html {
add_header Cache-Control "no-cache";
}
}
Base image security and maintenance
Keeping container base images up to date is part of deployment operations.
- Regularly update base image tags to include security fixes.
- Scan produced images for vulnerabilities in your CI/CD pipeline.
- Rebuild and redeploy images when upstream security advisories are published.
- Prefer explicit and traceable tags in production (avoid relying on long-lived floating tags).
Secrets
In a deployed environnement, all sensitive data should be stored in Kubernetes secrets. Neos backend services (cluster, Tenant Management, reports, ...) use Dapr secret stores to read values from Kubernetes secrets and mount them as dotnet configuration.
Note
To create a simple key value secret in Kubernetes which will be usable in Neos you can use the following command (example for authentication secret in Powershell) :
kubectl create secret generic neos-auth-env `
--from-literal=Authentication__Preset="AzureAdB2C" `
--from-literal=Authentication__Authority="https://SomeApplication.b2clogin.com/SomeApplication.onmicrosoft.com/B2C_1A_SIGNUP_SIGNIN/v2.0" `
--from-literal=Authentication__ClientId="xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx" `
--from-literal=Authentication__ClientSecret="somesecretvalue" `
--from-literal=Authentication__Scopes__0="xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx"
Authentication
Because authentication configuration needs to be known by gateway you must set the authenticationSecret property in your Helm values files so it contains all the necessary variables for authentication.
Note
The environment variables are dotnet override of the appsettings.json file. Please see this article for more information.
Example (Neos development authentication server) :
Authentication__Preset=NeosDevAuth
Example (Microsoft Entra External ID) :
Authentication__Preset=MicrosoftEntraExternalID
Authentication__Authority=https://SomeApplication.ciamlogin.com/xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx/v2.0
Authentication__ClientId=xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx
Authentication__ClientSecret=somesecretvalue
Example (Azure AD B2C) :
Authentication__Preset=AzureAdB2C
Authentication__Authority=https://SomeApplication.b2clogin.com/SomeApplication.onmicrosoft.com/B2C_1A_SIGNUP_SIGNIN/v2.0
Authentication__ClientId=xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx
Authentication__ClientSecret=somesecretvalue
Authentication__Scopes__0=xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx
Example (Azure Active Directory) :
Authentication__Preset=AzureAd
Authentication__Authority=https://login.microsoftonline.com/xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx/v2.0
Authentication__ClientId=xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx
Authentication__ClientSecret=somesecretvalue
Example (Auth0) :
Authentication__Preset=Auth0
Authentication__Authority=https://someapplication.eu.auth0.com
Authentication__ClientId=xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
Authentication__ClientSecret=somesecretvalue
Example (Okta, with a manual configuration) :
Authentication__Authority=https://someapplication.okta.com
Authentication__ClientId=xxxxxxxxxxxxxxxxxxxx
Authentication__ClientSecret=somesecretvalue
Authentication__Scopes__0=email
Authentication__UserPropertiesMap__Identifier=email
Authentication__UserPropertiesMap__Email=email
Authentication__UserPropertiesMap__FirstName=given_name
Authentication__UserPropertiesMap__LastName=family_name
Note
If one or several cluster in your deployment is not subject to authentication you need to add their host to the AnonymousHosts configuration of the gateway :
AnonymousHosts__0=first.unauthenticated.cluster.com
AnonymousHosts__1=second.unauthenticated.cluster.com
Gateway
The gateway provides authentication and routing to the right cluster version. You can override dotnet configuration using environment variables. These environment variables should be set in a secret which will then be mounted inside the gateway container.
Note
For gateway routing and unavailable-tenants synchronization, see Gateway Routing, CORS, and Unavailable Tenants Settings. For CORS parameters, see Gateway CORS configuration.
You can set the secret name as the value of gateway.envSecret property in your Helm values file.
Note
Status code pages can be configured for the gateway, including dedicated pages for disabled or unavailable tenants. See Custom status code pages for the available settings, image layout, and Dockerfile example.
Note
If you configured a secret for authenticationSecret, its variables will be mounted inside the gateway container.
Note
If your application has server methods which are not subject to authentication (eg Authentication required set to false in the server method configuration), you need to add them to the AnonymousRoutes configuration of the gateway, either with the gateway.anonymousRoutes list of your Helm values file:
gateway:
anonymousRoutes:
- /api/v1/firstanonymousmethod
- /api/v1/secondanonymousmethod
or with environment variables in the gateway secret:
AnonymousRoutes__0=/api/v1/firstanonymousmethod
AnonymousRoutes__1=/api/v1/secondanonymousmethod
Both sources add up: the chart numbers the Helm values from 1000, so keep the indexes of the environment variables below 1000. The path is matched exactly and whatever the host, so the route is anonymous for every cluster behind the gateway: give the server method a route of its own.
A route can contain * segments when a part of the path varies, such as the tenant of a multitenant cluster. Each * stands for exactly one non-empty segment, and the path must have the same number of segments as the route:
gateway:
anonymousRoutes:
- /*/api/v1/webhooks/public/*
This route matches /acme/api/v1/webhooks/public/samsara, but neither /api/v1/webhooks/public/samsara nor /acme/api/v1/webhooks/public/samsara/events. On a route such as /{tenant}/api/v1/..., the gateway always takes the tenant from the path: a Neos-Tenant header sent by the caller is replaced.
Reporting
The Stimulsoft license has to be configured inside the report container so you will need to provide the license key in a secret for the Reporting__StimulsoftLicenceKey environment variable.
You can set the secret name as the value of report.envSecret property in your Helm values file.
Tenant Management
The Tenant Management needs to run with a database so you'll need to provide the connection string in a secret for the PersistenceSettings__ConnectionString environment variable.
Note
Connection string needs to follow the DotNet syntax.
Tenant Management also needs an encryption key in the same secret, for the EncryptionKey environment variable. See Encryption key.
Warning
For Oracle database, you'll also need to disable concurrency access mode.
To do so, you should add PersistenceSettings__DefaultConcurrencyAccessMode key with its value set to Disabled.
You can set the secret name as the value of tenantManagement.envSecret property in your Helm values file.
If you need to expose the Tenant Management cluster outside of Kubernetes, you need to provide a TLS certificate as a Kubernetes secret.
You can set the secret name as the value of tenantManagement.tlsSecret property in your Helm values file.
Encryption key
Tenant Management stores the connection strings of the database servers encrypted in its database. It encrypts and decrypts them with the key read from the EncryptionKey configuration. This key must be a random value of 32 bytes, encoded in base64.
Important
Create the encryption key at the first deployment of Tenant Management, before its first start. The Helm chart replaces the appsettings.json of the Tenant Management image with its own, which has no EncryptionKey: without the key in the secret, Tenant Management fails as soon as it accesses its database, with the error Secret encryption key configuration 'EncryptionKey' is required.
Caution
Outside the Helm chart, a Tenant Management started with the appsettings.json of its image uses the default key of this file. This key is the same for every Neos installation and is not a secret: never use it outside a development environment.
Generate the key with a cryptographically secure random generator, directly into a new file that only you can read:
On Windows, with PowerShell 7, in your profile folder, which only you, the system and the administrators of the machine can read:
$keyFile = Join-Path $HOME 'tenant-management-encryption-key.txt' [Convert]::ToBase64String([System.Security.Cryptography.RandomNumberGenerator]::GetBytes(32)) | Out-File -FilePath $keyFile -NoNewline -NoClobberOn Linux or macOS, with OpenSSL.
umask 077creates the file readable by you only:keyFile=~/tenant-management-encryption-key.txt (umask 077 && set -o noclobber && key=$(openssl rand -base64 32) && printf '%s' "$key" > "$keyFile")
The file contains a string of 44 characters ending with
=. Both commands fail when the file already exists, so the key never lands in an older file with wider permissions. Writing the key to a file keeps it out of the command lines, which the shell history and the process list would otherwise keep in clear.Keep a copy of the key in a secure vault (for example your password manager or your cloud provider's key vault), apart from the Kubernetes cluster. Restoring a backup of the Tenant Management database on another environment requires the same key.
Add the key to the Tenant Management secret, with the connection string.
kubectl create secretcreates the whole secret, so give all its keys in the same command. Create the secret in the namespace of the Helm release, the one given to-ninhelm upgrade --install: the chart looks for the secret in this namespace only and fails withTenant Management secret ... not foundotherwise.kubectl create secret generic neos-tenant-management-env -n <your-namespace> ` --from-literal=PersistenceSettings__ConnectionString="Host=...;Database=...;Username=...;Password=..." ` --from-file=EncryptionKey=$keyFileor with bash:
kubectl create secret generic neos-tenant-management-env -n <your-namespace> \ --from-literal=PersistenceSettings__ConnectionString="Host=...;Database=...;Username=...;Password=..." \ "--from-file=EncryptionKey=$keyFile"Then delete the key file (
Remove-Item $keyFilein PowerShell,rm "$keyFile"in bash). To recreate the secret later, write the key from your vault to a file again rather than typing it in the command.Tip
If your Kubernetes cluster synchronizes its secrets from a vault (for example with the External Secrets Operator), store the key in the vault only and map it to the
EncryptionKeyentry of the synchronized secret.Set the secret name as the value of
tenantManagement.envSecretin your Helm values file:tenantManagement: envSecret: neos-tenant-management-env
Warning
The encryption key is the only way to read the stored connection strings. Once Tenant Management has stored connection strings, never change or lose the key: with another key, Tenant Management can no longer decrypt them and no longer reaches the tenant databases. Tenant Management has no key rotation mechanism.
License Management
The License Management needs to run with a database so you'll need to provide the connection string in a secret for the PersistenceSettings__ConnectionString environment variable.
Note
Connection string needs to follow the DotNet syntax.
You can set the secret name as the value of licenseManagement.envSecret property in your Helm values file.
If you need to expose the License Management cluster outside of Kubernetes, you need to provide a TLS certificate as a Kubernetes secret.
You can set the secret name as the value of licenseManagement.tlsSecret property in your Helm values file.
Task runner actor state store (PostgreSQL)
Neos ecosystem relies on Dapr workflow components for its background server methods to run.
In the Kubernetes cluster, a specific actor state store component needs to be configured. See this article for supported state stores.
Neos Helm chart generates the component specs for Redis and PostgreSQL (v1).
By default the chart will generate the Redis actor state store component spec.
Warning
Redis is not recommended by Dapr as actor state store in production due to its limitations regarding transactions. Thus, we recommend to use postgresql preset instead.
In case you use the PostgreSQL (v1) component spec (actorStateStore.preset property of the Helm values file set to postgresql) you'll need to provide the name of a secret with the PostgreSQL connection string to use in the actorStateStore.postgresqlConnectionStringSecret property of your Helm values file.
The secret should have a connectionString entry like the following example :
kubectl create secret generic neos-actor-state-store-postgresql-secret `
--from-literal=connectionString="host=localhost user=postgres password=example port=5432 connect_timeout=10 database=my_db"
Neos AI
The Neos AI cluster needs to run with a database so you'll need to provide the connection string in a secret for the PersistenceSettings__ConnectionString environment variable.
Note
Connection string needs to follow the DotNet syntax.
You can set the secret name as the value of neosAI.envSecret property in your Helm values file.
If you need to expose the Neos AI cluster outside the Kubernetes cluster, you need to provide a TLS certificate as a Kubernetes secret.
You can set the secret name as the value of neosAI.tlsSecret property in your Helm values file.
Task Scheduler
The Task Scheduler cluster needs to run with a database so you'll need to provide the connection string in a secret for the PersistenceSettings__ConnectionString environment variable.
Note
Connection string needs to follow the DotNet syntax.
You can set the secret name as the value of taskScheduler.envSecret property in your Helm values file.
If you need to expose the Task Scheduler cluster outside the Kubernetes cluster, you need to provide a TLS certificate as a Kubernetes secret.
You can set the secret name as the value of taskScheduler.tlsSecret property in your Helm values file.
Support Center
The Support Center cluster needs to run with a database so you'll need to provide the connection string in a secret for the PersistenceSettings__ConnectionString environment variable.
Note
Connection string needs to follow the DotNet syntax.
You can set the secret name as the value of supportCenter.envSecret property in your Helm values file.
If you need to expose the Support Center cluster outside the Kubernetes cluster, you need to provide a TLS certificate as a Kubernetes secret.
You can set the secret name as the value of supportCenter.tlsSecret property in your Helm values file.
Clusters
If you need to expose the cluster application outside the Kubernetes cluster, you need to provide a TLS certificate as a Kubernetes secret.
You can set the secret name as the value of clusters[n].tlsSecret property in your Helm values file.
If the cluster's backend needs to run with a database so you'll need to provide the connection string in a secret for the PersistenceSettings__ConnectionString environment variable.
Note
Connection string needs to follow the DotNet syntax.
You can set the secret name as the value of clusters[n].backend.envSecret property in your Helm values file.
Encryption key of a business cluster
A cluster that stores encrypted data in its database, such as the secrets of the receivers of the NeosWebhooks module, encrypts and decrypts it with the key read from the EncryptionKey configuration. This key must be a random value of 32 bytes, encoded in base64.
Caution
Without EncryptionKey in the secret, the cluster uses the key of the appsettings.json of its image. Unless the cluster configuration sets one, this is the default key of Neos, the same for every installation and not a secret: never deploy a cluster with it.
Generate a key for each cluster as for Tenant Management, keep a copy in a secure vault, and add it as the EncryptionKey entry of the secret of the cluster: clusters[n].backend.envSecret, or clusters[n].versions[m].backend.envSecret for each version of a multitenant cluster. The task runner of the cluster reads the same secret.
kubectl create secret generic neos-my-cluster-env -n <your-namespace> `
--from-literal=PersistenceSettings__ConnectionString="Host=...;Database=...;Username=...;Password=..." `
--from-file=EncryptionKey=$keyFile
For a multitenant cluster, leave out PersistenceSettings__ConnectionString: the connection strings of the tenants come from Tenant Management.
Warning
Create the key before the first start of the cluster, and never change or lose it afterwards: the data encrypted with a key can only be read with this key. With another key, the receivers of the NeosWebhooks module can no longer read their secrets and refuse every signed request, until an administrator adds their secrets again.
To allow the Kubernetes cluster to pull the images of your cluster, you may need to create a secret containing your registry credentials.
You can set the secret names as the values of clusters[n].backend.imagePullSecret and clusters[n].frontend.imagePullSecret property in your Helm values file.
Configuration of the user synchronization
When the UserPermissions module synchronizes the users with the authentication server, you'll need to provide its configuration to Tenant Management (tenantManagement.envSecret) and to your clusters using UserPermissions (clusters[n].backend.envSecret, or clusters[n].versions[m].backend.envSecret for each version of a multi-tenant cluster).
This configuration allows UserPermissions to create and read the users of the authentication server.
You can set the environment variables of your authentication server in these secrets, as in the following examples.
NeosAuth
UserPermissions__AuthProvider=NeosAuth
UserPermissions__NeosAuth__Authority=https://auth.neos.groupeisagri.com
Microsoft Entra External ID
UserPermissions__AuthProvider=MicrosoftEntraExternalID
UserPermissions__MicrosoftEntraExternalID__ClientId=xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx
UserPermissions__MicrosoftEntraExternalID__TenantId=xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx
UserPermissions__MicrosoftEntraExternalID__TenantName=xxxx.onmicrosoft.com
UserPermissions__MicrosoftEntraExternalID__ClientSecretKey=yoursecret
The cluster sends an email with a temporary password to the created users: see Temporary password email.
Okta
The Okta synchronization is supplied by the UserPermissionsOkta module, which the cluster must reference in addition to UserPermissions.
UserPermissions__AuthProvider=Okta
UserPermissions__Okta__Domain=https://someapplication.okta.com
UserPermissions__Okta__ClientId=xxxxxxxxxxxxxxxxxxxx
UserPermissions__Okta__KeyId=yourkeyid
UserPermissions__Okta__PrivateKey=-----BEGIN PRIVATE KEY-----...-----END PRIVATE KEY-----
UserPermissions__Okta__GroupIds__0=00gxxxxxxxxxxxxxxxxx
UserPermissions__Okta__ApplicationId=0oaxxxxxxxxxxxxxxxxx
UserPermissions__Okta__UseOktaActivationEmail=true
GroupIds, ApplicationId and UseOktaActivationEmail are optional. When UseOktaActivationEmail is false, the cluster sends an email with a temporary password to the created users: see Temporary password email.
Tip
The private key is in PEM format, on several lines. The simplest way to put it in the secret is to read it from its file with --from-file, along with the other variables of the backend, since kubectl create secret creates the whole secret :
kubectl create secret generic northwind-env-secret `
--from-literal=PersistenceSettings__ConnectionString="Host=...;Database=...;Username=...;Password=..." `
--from-literal=UserPermissions__AuthProvider="Okta" `
--from-literal=UserPermissions__Okta__Domain="https://someapplication.okta.com" `
--from-literal=UserPermissions__Okta__ClientId="xxxxxxxxxxxxxxxxxxxx" `
--from-literal=UserPermissions__Okta__KeyId="yourkeyid" `
--from-file=UserPermissions__Okta__PrivateKey=./okta-private-key.pem
Azure AD B2C
UserPermissions__AuthProvider=AzureAdB2C
UserPermissions__AzureAdB2C__ClientId=xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx
UserPermissions__AzureAdB2C__TenantId=xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx
UserPermissions__AzureAdB2C__TenantName=xxxx.onmicrosoft.com
UserPermissions__AzureAdB2C__ClientSecretKey=yoursecret
UserPermissions__AzureAdB2C__B2cExtensionAppClientId=xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx
The cluster sends an email with a temporary password to the created users: see Temporary password email.
Note
The former AuthenticationMode=AzureB2C variable and AzureB2COption__* variables are still read, but are replaced by the UserPermissions__* variables above.
Temporary password email
With Microsoft Entra External ID, Azure AD B2C, and Okta when UseOktaActivationEmail is false, the cluster sends the temporary password of the created users by email, through SendGrid:
UserPermissions__EmailContent__RedirectUrl=https://yourapp/
UserPermissions__EmailContent__Title=Your title
UserPermissions__EmailContent__Content1=Log in with your email address ({Email}) and the temporary password below.
UserPermissions__EmailContent__Content2=Your temporary password: {Password}
UserPermissions__EmailContent__LinkText=Text
SendGrid__Key=yoursecret
SendGrid__From__Name=yourappname
[email protected]
You can disable this email by setting UserPermissions__SendTemporaryPasswordEmail to false. See Email content for the placeholders of the email content: the temporary password must appear in it through the {Password} placeholder.
Configure the first administrator user with UserPermissions module
If your deployed application is not multi-tenant, when the database is created, there are no users yet.
To create the first administrator user, you can configure a new environment variable UserPermissions__DefaultUserAccountLogin or see Configuration in ASP.NET Core.
When the database is migrated, this user will be automatically created with all permissions.
Sending logs to Application Insights
Each Neos application can be configured to send logs to Application Insights, please see this article for more information.
Warning
Backend .NET SDK-based Application Insights settings in this chapter are deprecated and will be removed in a future version. Prefer OpenTelemetry Collector routing for backend telemetry and exporters. See OpenTelemetry collector migration.
Environnement variables for .Net processes
You can configure Application Insights for Neos .Net processes by setting options as environnement variables in the secret associated to the process.
The following processes are supported :
- Gateway
- Reporting
- Tenant Management backend
- License Management backend
- Task Scheduler backend
- Neos AI backend
- Support Center backend
- Cluster backend
Example (cluster backend)
ApplicationInsights__ConnectionString=1a11a111-1a1a-1111-a111-1aaa1a1a1a11;IngestionEndpoint=https://westeurope-5.in. applicationinsights.azure.com/;LiveEndpoint=https://westeurope.livediagnostics.monitor.azure.com/; ApplicationId=2b22b222-2b2b-2222-b222-2bbb2b2b2b22
ApplicationInsights__EnableHeartbeat=false
ApplicationInsights__RoleName=NorthwindServer
ApplicationInsights__RequestCollectionOptions__TrackExceptions=true
Note
For more information on available options, see this article.
Log level
The default setting for Application Insights is to only capture Warning and more severe logs (see this article).
It is possible to modify this configuration with the Logging_ApplicationInsights__LogLevel__Default environment variable.
In the following example, Information and more severe logs will be sent to Application Insights even if Debug logs are emitted in the console output :
Logging__LogLevel__Default=Debug
Logging__ApplicationInsights__LogLevel__Default=Information
Exclude specific successful endpoints
By default, all request and traces will be sent to Application Insights except healthcheck (/hc & /healthz) and metrics (/metrics) endpoints if their status code is unset or less than 400.
If you want to exclude traces and requests associated to specific endpoints when the status code is unset or less than 400, you can set the ApplicationInsights__ExcludedSuccessfulEndpoints value (string array).
Warning
Don't forget to include /hc, /healthz and /metrics in the array in addition to your specific endpoints otherwise it could be overridden.
Example to exclude /api/v1/methods/some-specific-method and /api/v1/SomeEntityView request and traces when the response status code is unset or less than 400 :
ApplicationInsights__ExcludedSuccessfulEndpoints__0=/hc
ApplicationInsights__ExcludedSuccessfulEndpoints__1=/healthz
ApplicationInsights__ExcludedSuccessfulEndpoints__2=/metrics
ApplicationInsights__ExcludedSuccessfulEndpoints__3=/api/v1/methods/some-specific-method
ApplicationInsights__ExcludedSuccessfulEndpoints__4=/api/v1/SomeEntityView
Open Telemetry
You can configure Open telemetry for Neos .Net processes by setting options as environnement variables in the secret associated to the process.
The following processes are supported :
- Gateway
- Reporting
- Tenant Management backend
- License Management backend
- Task Scheduler backend
- Neos AI backend
- Support Center backend
- Cluster backend
Tracing
Exclude specific endpoints
By default, /hc, /healthz and /metrics endpoints are not sent by open telemetry exporter.
You can customize the list of excluded endpoints by setting the Tracing__ExcludedEndpoints value (string array).
Warning
Don't forget to include /hc, /healthz and /metrics in the array in addition to your specific endpoints otherwise it could be overridden.
Example to exclude /api/v1/methods/some-specific-method and /api/v1/SomeEntityView traces :
Tracing__ExcludedEndpoints__0=/hc
Tracing__ExcludedEndpoints__1=/healthz
Tracing__ExcludedEndpoints__2=/metrics
Tracing__ExcludedEndpoints__3=/api/v1/methods/some-specific-method
Tracing__ExcludedEndpoints__4=/api/v1/SomeEntityView
JSON configuration for frontend
To configure Application Insights for frontend, you can create a secret containing an applicationInsights.json file content.
Example
JSON file content :
{
"clusterVersion": "0.5.1",
"connectionString": "1a11a111-1a1a-1111-a111-1aaa1a1a1a11;IngestionEndpoint=https://westeurope-5.in. applicationinsights.azure.com/;LiveEndpoint=https://westeurope.livediagnostics.monitor.azure.com/; ApplicationId=2b22b222-2b2b-2222-b222-2bbb2b2b2b22",
"correlationHeaderExcludedDomains": ["domain1.com", "domain2.com"],
"disableAjaxTracking": true,
"enableAutoRouteTracking": true,
"enableCorsCorrelation": true,
"enableUnhandledPromiseRejectionTracking": true,
"neosVersion": "1.21.0",
"roleName": "NorthwindClient"
}
Associated secret :
apiVersion: v1
kind: Secret
data:
applicationInsights.json: <base64encodedJSONfilecontent>
metadata:
name: northwind-frontend-conf
Note
To create the secret directly from an existing applicationInsights.json file on your computer you can use the following command :
kubectl create secret generic <your-secret-name> --from-file=path/to/the/file/applicationInsights.json
See this article for more information on how to create secrets in Kubernetes.
Note
For more information on available options, see this article.
Ingress controller
This charts is configured to work with a Nginx ingress controller.