Server
This chapter is aimed solely at system admins. It contains instructions on how to get the BOMnipotent server up and running, and how to configure it to your needs.
This chapter is aimed solely at system admins. It contains instructions on how to get the BOMnipotent server up and running, and how to configure it to your needs.
This section aims to make setting up your server to host an instance of BOMnipotent Server as easy as possible.
The setup consists of the following, necessary steps:
After that you can configure the server to your personal needs.
Several setup variants are presented here. You can pick the one best suited to your needs, and modify it at will.
After following the steps of one of the variants, your server has a default configuration and should be reachable from the internet. After that, you should create an admin user account .
The recommended and easiest setup for BOMnipotent Server uses docker compose . This variant of the setup will make BOMnipotent Server directly reachable from the internet. If you want to handle traffic through a reverse proxy, check out another setup instead.
The suggested file structure in the favourite directory of your server looks like this:
├── .env
├── bomnipotent_config
│ ├── config.toml
│ └── config.toml.default
└── compose.yaml
This tutorial will walk through the files and explain them one by one.
BOMnipotent server communicates with a database. Currently, only PostgreSQL is supported as a backend. The database is protected by a password. It is best practice to store the password inside a separate .env file instead of directly in the compose.yaml.
The name of the file must be “.env”, otherwise docker will not recognise it.
Your .env file should look like this:
BOMNIPOTENT_DB_PW=<your-database-password>
SMTP_SECRET=<your-smtp-authentication-secret>
If you are using a versioning system to store your setup, do not forget to add “.env” to your .gitignore or analogous ignore file!
BOMnipotent Server needs a configuration file, which is explained in more detail in another section .
The name of the file is arbitrary in principle, but the ready-to-deploy BOMnipotent Server docker container is set up to look for “config.toml”.
A minimal configuration looks like this:
# The db_url has the structure [db_client]://[user]:[password]@[container]:[port]/[db]
# Note that ${BOMNIPOTENT_DB_PW} references an environment variable.
db_url = "postgres://bomnipotent_user:${BOMNIPOTENT_DB_PW}@bomnipotent_db:5432/bomnipotent_db"
# Domain behind which bomnipotent server will be hosted
domain = "https://bomnipotent.<your-domain>.<top-level>"
[tls]
# The path to your full TLS certificate chain
certificate_chain_path = "/etc/ssl/certs/<your-TLS-certificate-chain.crt>"
# The path to your secret TLS key
secret_key_path = "/etc/ssl/private/<your-secret-TLS-key>"
[smtp]
# The username for your mail provider, typically your mail address
user = "<you@yourdomain.com>"
# The smtp endpoint of your mail provider
endpoint = "<your.smtp.host>"
# The secret to authenticate against the mail provider, typically your password
secret = "${SMTP_SECRET}"
# Publisher data according to the CSAF Standard linked below
[provider_metadata.publisher]
name = "<Provide the name of your organsiation>"
# Namespace of your organisation, in form of a complete URL
namespace = "https://<your-domain>.<top-level>"
# This is most likely the enum variant you want
category = "vendor"
# Contact details are optional and in free form
contact_details = "<For security inquiries, please contact us at...>"
Fill in the braces with your data.
The section about TLS configuration contains more detailed information to avoid common pitfalls.
If you prefer using a local smtp releay station, have a look at the necessary adjustments to the compose file.
The publisher data is used to comply with the OASIS CSAF standard .
The section about provider-metadata goes into more details what the fields actually mean.
It is recommended to store your config.toml file inside a dedicated directory, “bomnipotent_config” in this example. The docker compose file will grant read access to this folder. This setup has two advantages:
Many configuration values support hot reloading, meaning they can be modified without restarting the server.
After having set up your config.toml, you may want to copy it as for example config.toml.default, to be able to quickly restore your initial configuration. This is entirely optional, though.
The compose file is where you specify the container setup. Once it is running smoothly, it does not need to be modified very often, but initially understanding it can take some time if you are new to docker.
The file needs to be called “compose.yaml”, docker can be a bit pecky otherwise.
A completely ready to deploy compose file looks like this:
# Giving the setup a name is optional, it will be derived by docker otherwise.
name: bomnipotent_server_containers
# The docker containers need to communicate, and they need a network for that.
networks:
# This network needs a reference
bomnipotent_network:
# Since the containers are on the same docker host, "bridge" is a reasonable driver choice.
driver: bridge
# Giving the network the same name as the reference is ok.
name: bomnipotent_network
volumes:
# Define the volume for persistent storage of the database
bomnipotent_data:
driver: local
# The server itself also needs persistence if you do not want to activate the subscription after every reboot
bomnipotent_subscription:
driver: local
services:
bomnipotent_db:
# Name of the database container
container_name: bomnipotent_db
deploy:
resources:
limits:
# Limit the CPU usage to 0.5 cores
cpus: "0.5"
# Limit the memory usage to 512MB
memory: "512M"
environment:
# Set the database name
POSTGRES_DB: bomnipotent_db
# Set the database user
POSTGRES_USER: bomnipotent_user
# Set the database password from the .env file variable
POSTGRES_PASSWORD: ${BOMNIPOTENT_DB_PW}
healthcheck:
# Check if the database is ready
test: ["CMD-SHELL", "pg_isready -U bomnipotent_user -d bomnipotent_db"]
# Interval between health checks
interval: 60s
# Timeout for each health check
timeout: 10s
# Number of retries before considering the container unhealthy
retries: 5
# Start period before the first health check
start_period: 10s
# Use the specified PostgreSQL image
# You may ddjust the container tag at will
image: postgres:17
logging:
# Use the local logging driver
driver: local
options:
# Limit the log size to 10MB
max-size: "10m"
# Keep a maximum of 3 log files
max-file: "3"
networks:
# Connect to the specified network
- bomnipotent_network
# Restart the container if it has stopped for some reason other than a user command
restart: always
volumes:
# Mount the volume for persistent data storage
- bomnipotent_data:/var/lib/postgresql/data
bomnipotent_server:
# Name of the server container
container_name: bomnipotent_server
depends_on:
# Ensure the database service is healthy before starting the server
bomnipotent_db:
condition: service_healthy
deploy:
resources:
limits:
# Limit the CPU usage to 0.5 cores
cpus: "0.5"
# Limit the memory usage to 512MB
memory: "512M"
environment:
# Pass the database password on to the server.
BOMNIPOTENT_DB_PW: ${BOMNIPOTENT_DB_PW}
# Pass the SMTP secret on to the server.
SMTP_SECRET: ${SMTP_SECRET}
healthcheck:
# Check if the server is healthy
# Your TLS certificate is most likely not valid for "localhost"
# Hence the --insecure flag
test: ["CMD-SHELL", "curl --fail --insecure https://localhost:8443/health || exit 1"]
# Interval between health checks
interval: 60s
# Timeout for each health check
timeout: 10s
# Number of retries before considering the container unhealthy
retries: 5
# Start period before the first health check
start_period: 10s
# This is the official docker image running a BOMnipotent Server instance.
image: wwhsoft/bomnipotent_server:latest
logging:
# Use the local logging driver
driver: local
options:
# Limit the log size to 10MB
max-size: "10m"
# Keep a maximum of 3 log files
max-file: "3"
networks:
# Connect to the specified network
- bomnipotent_network
ports:
# Map port 443 on the host to port 8443 on the container
# This allows to connect to it via encrypted communication from the internet
- target: 8443
published: 443
# Restart the container if it has stopped for some reason other than a user command
restart: always
volumes:
# Bind mount the config folder on the host
- type: bind
source: ./bomnipotent_config
target: /etc/bomnipotent_server/configs/
read_only: true
# Bind mount the SSL directory, so that BOMnipotent can find the TLS certificate and key
- type: bind
source: /etc/ssl
target: /etc/ssl
read_only: true
# The subscription can be stored inside the container
- bomnipotent_subscription:/root/.config/bomnipotent
name: bomnipotent_server_containers
networks:
bomnipotent_network:
driver: bridge
name: bomnipotent_network
volumes:
bomnipotent_data:
driver: local
bomnipotent_subscription:
driver: local
services:
bomnipotent_db:
container_name: bomnipotent_db
deploy:
resources:
limits:
cpus: "0.5"
memory: "512M"
environment:
POSTGRES_DB: bomnipotent_db
POSTGRES_USER: bomnipotent_user
POSTGRES_PASSWORD: ${BOMNIPOTENT_DB_PW}
healthcheck:
test: ["CMD-SHELL", "pg_isready -U bomnipotent_user -d bomnipotent_db"]
interval: 60s
timeout: 10s
retries: 5
start_period: 10s
image: postgres:17
logging:
driver: local
options:
max-size: "10m"
max-file: "3"
networks:
- bomnipotent_network
restart: always
volumes:
- bomnipotent_data:/var/lib/postgresql/data
bomnipotent_server:
container_name: bomnipotent_server
depends_on:
bomnipotent_db:
condition: service_healthy
deploy:
resources:
limits:
cpus: "0.5"
memory: "512M"
environment:
BOMNIPOTENT_DB_PW: ${BOMNIPOTENT_DB_PW}
SMTP_SECRET: ${SMTP_SECRET}
healthcheck:
test: ["CMD-SHELL", "curl --fail --insecure https://localhost:8443/health || exit 1"]
interval: 60s
timeout: 10s
retries: 5
start_period: 10s
image: wwhsoft/bomnipotent_server:latest
logging:
driver: local
options:
max-size: "10m"
max-file: "3"
networks:
- bomnipotent_network
ports:
- target: 8443
published: 443
restart: always
volumes:
- type: bind
source: ./bomnipotent_config
target: /etc/bomnipotent_server/configs/
read_only: true
- type: bind
source: /etc/ssl
target: /etc/ssl
read_only: true
- bomnipotent_subscription:/root/.config/bomnipotent
Store this as “compose.yaml”. Then, call:
docker compose --detach
docker compose -d
Your server is now up and running!
Run “docker ps” to check if it is healthy.
This variant of the very similar setup with docker compose not only sets up a running BOMnipotent Server, but also an nginx reverse proxy.
The suggested file structure in the favourite directory of your server looks like this:
├── .env
├── bomnipotent_config
│ ├── config.toml
│ └── config.toml.default
├── proxy_config
│ └── conf.d
│ └── default.conf
└── compose.yaml
This tutorial will walk through the files and explain them one by one.
The use of nginx as the reverse proxy is merely a suggestion. You can substitute it with any other server software you prefer.
In very crude terms, the reverse proxy serves as a gateway to your server: It allows you to host several services (BOMnipotent Server, a website, etc.) behind the same IP address. Any request to one of your URLs will end up at the reverse proxy, which then passes them on to the correct service. This is how you land on a different website when you visit doc.bomnipotent.de than when you visit www.bomnipotent.de , although they are hosted behind the same IP address.
Nginx looks up its configuration in various locations. Later on in the compose.yaml we will use mount binding to sneakily inject our configuration into the nginx docker container.
You can use the following as the starting point for your default.conf:
# Rate limiting: Allows up to 5 requests per second per IP address, stored in a memory zone of 10 MB.
limit_req_zone $binary_remote_addr zone=api_limit:10m rate=5r/s;
# BOMnipotent Server
server {
# This makes the server listen on port 443, which is typically used for HTTPS.
listen 443 ssl http2;
# Replace this with the actual domain of your BOMnipotent Server.
server_name bomnipotent.your-domain.com;
# Replace this with the actual certificate for your domain.
ssl_certificate /etc/ssl/certs/your-domain-fullchain.crt;
# Replace this with the actual private key for your certificate.
ssl_certificate_key /etc/ssl/private/your-domain_private_key.key;
ssl_protocols TLSv1.2 TLSv1.3;
ssl_prefer_server_ciphers on;
ssl_ciphers "ECDHE-ECDSA-AES256-GCM-SHA384:ECDHE-RSA-AES256-GCM-SHA384";
location / {
# Apply rate limiting
limit_req zone=api_limit burst=10 nodelay;
# This tells nginx to pass on requests to port 8080 of the docker container.
proxy_pass http://bomnipotent_server:8080;
proxy_set_header Host $host;
# The following lines assure that the BOMnipotent logs contain the IP of the sender,
# instead of the local IP of the reverse proxy.
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto $scheme;
}
}
You probably want to add more “server” blocks – why else would you decide to set up a reverse proxy?
BOMnipotent server communicates with a database. Currently, only PostgreSQL is supported as a backend. The database is protected by a password. It is best practice to store the password inside a separate .env file instead of directly in the compose.yaml.
The name of the file must be “.env”, otherwise docker will not recognise it.
Your .env file should look like this:
BOMNIPOTENT_DB_PW=<your-database-password>
SMTP_SECRET=<your-smtp-authentication-secret>
If you are using a versioning system to store your setup, do not forget to add “.env” to your .gitignore or analogous ignore file!
BOMnipotent Server needs a configuration file, which is explained in more detail in another section .
The name of the file is arbitrary in principle, but the ready-to-deploy BOMnipotent Server docker container is set up to look for “config.toml”.
A minimal configuration for a BOMnipotent Server behind a reverse proxy looks like this:
# The db_url has the structure [db_client]://[user]:[password]@[container]:[port]/[db]
# Note that ${BOMNIPOTENT_DB_PW} references an environment variable.
db_url = "postgres://bomnipotent_user:${BOMNIPOTENT_DB_PW}@bomnipotent_db:5432/bomnipotent_db"
# Domain behind which bomnipotent server will be hosted
domain = "https://bomnipotent.<your-domain>.<top-level>"
[tls]
# TLS encryption is handled by the reverse proxy,
# BOMnipotent Server is not directly reachable from the internet.
allow_http = true
[smtp]
# The username for your mail provider, typically your mail address
user = "<you@yourdomain.com>"
# The smtp endpoint of your mail provider
endpoint = "<your.smtp.host>"
# The secret to authenticate against the mail provider, typically your password
secret = "${SMTP_SECRET}"
# Publisher data according to the CSAF Standard linked below
[provider_metadata.publisher]
name = "<Provide the name of your organsiation>"
# Namespace of your organisation, in form of a complete URL
namespace = "https://<your-domain>.<top-level>"
# This is most likely the enum variant you want
category = "vendor"
# Contact details are optional and in free form
contact_details = "<For security inquiries, please contact us at...>"
Fill in the braces with your data.
If you prefer using a local smtp releay station, have a look at the necessary adjustments to the compose file.
The publisher data is used to comply with the OASIS CSAF standard .
The section about provider-metadata goes into more details what the fields actually mean.
It is recommended to store your config.toml file inside a dedicated directory, “bomnipotent_config” in this example. The docker compose file will grant read access to this folder. This setup has two advantages:
Many configuration values support hot reloading, meaning they can be modified without restarting the server.
After having set up your config.toml, you may want to copy it as for example config.toml.default, to be able to quickly restore your initial configuration. This is entirely optional, though.
The compose file is where you specify the container setup. Once it is running smoothly, it does not need to be modified very often, but initially understanding it can take some time if you are new to docker.
The file needs to be called “compose.yaml”, docker can be a bit pecky otherwise.
A completely ready to deploy compose file looks like this:
# Giving the setup a name is optional, it will be derived by docker otherwise.
name: bomnipotent_server_containers
# The docker containers need to communicate, and they need a network for that.
networks:
# This network needs a reference
bomnipotent_network:
# Since the containers are on the same docker host, "bridge" is a reasonable driver choice.
driver: bridge
# Giving the network the same name as the reference is ok.
name: bomnipotent_network
# The reverse proxy needs to communicate with BOMnipotent Server, but not with the database.
proxy_network:
driver: bridge
name: proxy_network
volumes:
# Define the volume for persistent storage of the database
bomnipotent_data:
driver: local
# The server itself also needs persistence if you do not want to activate the subscription after every reboot
bomnipotent_subscription:
driver: local
services:
reverse_proxy:
# Name of the reverse proxy container
container_name: reverse_proxy
deploy:
resources:
limits:
# Limit the CPU usage to 0.5 cores
cpus: "0.5"
# Limit the memory usage to 512MB
memory: "512M"
healthcheck:
# Check if nginx is running and could parse the config.
test: ["CMD-SHELL", "nginx -t || exit 1"]
# Interval between health checks
interval: 60s
# Timeout for each health check
timeout: 10s
# Number of retries before considering the container unhealthy
retries: 3
# Start period before the first health check
start_period: 60s
image: nginx:latest
logging:
# Use the local logging driver
driver: local
options:
# Limit the log size to 10MB
max-size: "10m"
# Keep a maximum of 3 log files
max-file: "3"
networks:
# Connect to the specified network
- proxy_network
ports:
# Expose port 443 of the container
# This allows to connect to it via encrypted communication from the internet
- "443:443"
# Restart the container if it has stopped for some reason other than a user command
restart: on-failure
volumes:
# Bind mount the SSL directory, so that nginx can find the TLS certificate and key
- type: bind
source: /etc/ssl
target: /etc/ssl
read_only: true
# Bind mount the config folder on the host
- type: bind
source: ./proxy_config/conf.d
target: /etc/nginx/conf.d
read_only: true
bomnipotent_db:
# Name of the database container
container_name: bomnipotent_db
deploy:
resources:
limits:
# Limit the CPU usage to 0.5 cores
cpus: "0.5"
# Limit the memory usage to 512MB
memory: "512M"
environment:
# Set the database name
POSTGRES_DB: bomnipotent_db
# Set the database user
POSTGRES_USER: bomnipotent_user
# Set the database password from the .env file variable
POSTGRES_PASSWORD: ${BOMNIPOTENT_DB_PW}
healthcheck:
# Check if the database is ready
test: ["CMD-SHELL", "pg_isready -U bomnipotent_user -d bomnipotent_db"]
# Interval between health checks
interval: 60s
# Timeout for each health check
timeout: 10s
# Number of retries before considering the container unhealthy
retries: 5
# Start period before the first health check
start_period: 10s
# Use the specified PostgreSQL image
# You may ddjust the container tag at will
image: postgres:17
logging:
# Use the local logging driver
driver: local
options:
# Limit the log size to 10MB
max-size: "10m"
# Keep a maximum of 3 log files
max-file: "3"
networks:
# Connect to the specified network
- bomnipotent_network
# Restart the container if it has stopped for some reason other than a user command
restart: always
volumes:
# Mount the volume for persistent data storage
- bomnipotent_data:/var/lib/postgresql/data
bomnipotent_server:
# Name of the server container
container_name: bomnipotent_server
depends_on:
# Ensure the database service is healthy before starting the server
bomnipotent_db:
condition: service_healthy
deploy:
resources:
limits:
# Limit the CPU usage to 0.5 cores
cpus: "0.5"
# Limit the memory usage to 512MB
memory: "512M"
environment:
# Pass the database password on to the server.
BOMNIPOTENT_DB_PW: ${BOMNIPOTENT_DB_PW}
# Pass the SMTP secret on to the server.
SMTP_SECRET: ${SMTP_SECRET}
healthcheck:
# Check if the server is healthy
test: ["CMD-SHELL", "curl --fail http://localhost:8080/health || exit 1"]
# Interval between health checks
interval: 60s
# Timeout for each health check
timeout: 10s
# Number of retries before considering the container unhealthy
retries: 5
# Start period before the first health check
start_period: 10s
# This is the official docker image running a BOMnipotent Server instance.
image: wwhsoft/bomnipotent_server:latest
logging:
# Use the local logging driver
driver: local
options:
# Limit the log size to 10MB
max-size: "10m"
# Keep a maximum of 3 log files
max-file: "3"
networks:
# Connect the server to the reverse proxy
- proxy_network
# Connect the server to the database
- bomnipotent_network
# Restart the container if it has stopped for some reason other than a user command
restart: always
volumes:
# Bind mount the config folder on the host
- type: bind
source: ./bomnipotent_config
target: /etc/bomnipotent_server/configs/
read_only: true
# The subscription can be stored inside the container
- bomnipotent_subscription:/root/.config/bomnipotent
name: bomnipotent_server_containers
networks:
bomnipotent_network:
driver: bridge
name: bomnipotent_network
proxy_network:
driver: bridge
name: proxy_network
volumes:
bomnipotent_data:
driver: local
bomnipotent_subscription:
driver: local
services:
reverse_proxy:
container_name: reverse_proxy
deploy:
resources:
limits:
cpus: "0.5"
memory: "512M"
healthcheck:
test: ["CMD-SHELL", "nginx -t || exit 1"]
interval: 60s
timeout: 10s
retries: 3
start_period: 60s
image: nginx:latest
logging:
driver: local
options:
max-size: "10m"
max-file: "3"
networks:
- proxy_network
ports:
- "443:443"
restart: on-failure
volumes:
- type: bind
source: /etc/ssl
target: /etc/ssl
read_only: true
- type: bind
source: ./proxy_config/conf.d
target: /etc/nginx/conf.d
read_only: true
bomnipotent_db:
container_name: bomnipotent_db
deploy:
resources:
limits:
cpus: "0.5"
memory: "512M"
environment:
POSTGRES_DB: bomnipotent_db
POSTGRES_USER: bomnipotent_user
POSTGRES_PASSWORD: ${BOMNIPOTENT_DB_PW}
healthcheck:
test: ["CMD-SHELL", "pg_isready -U bomnipotent_user -d bomnipotent_db"]
interval: 60s
timeout: 10s
retries: 5
start_period: 10s
image: postgres:17
logging:
driver: local
options:
max-size: "10m"
max-file: "3"
networks:
- bomnipotent_network
restart: always
volumes:
- bomnipotent_data:/var/lib/postgresql/data
bomnipotent_server:
container_name: bomnipotent_server
depends_on:
bomnipotent_db:
condition: service_healthy
deploy:
resources:
limits:
cpus: "0.5"
memory: "512M"
environment:
BOMNIPOTENT_DB_PW: ${BOMNIPOTENT_DB_PW}
SMTP_SECRET: ${SMTP_SECRET}
healthcheck:
test: ["CMD-SHELL", "curl --fail http://localhost:8080/health || exit 1"]
interval: 60s
timeout: 10s
retries: 5
start_period: 10s
image: wwhsoft/bomnipotent_server:latest
logging:
driver: local
options:
max-size: "10m"
max-file: "3"
networks:
- proxy_network
- bomnipotent_network
restart: always
volumes:
- type: bind
source: ./bomnipotent_config
target: /etc/bomnipotent_server/configs/
read_only: true
- bomnipotent_subscription:/root/.config/bomnipotent
Store this as “compose.yaml”. Then, call:
docker compose --detach
docker compose -d
Your server is now up and running!
Run “docker ps” to check if it is healthy.
You are not required to run the official BOMnipotent Server docker container . Instead, you can download and directly run the BOMnipotent Server binary as a standalone application.
This setup only really makes sense for version 0.4.2 onwards, because the server did not offer port adjustments and logging to files before that.
BOMnipotent Server requires a PostgreSQL database for storing its data. The setup depends on your server operating system.
On the most common distributions, PostgreSQL is offered as a package. You can install it via for example apt/apt-get/aptitude:
sudo apt-get install postgresql postgresql-contrib
Now PostgeSQL is running as a service. To further modify it, you need to become the postgres system user:
sudo -i -u postgres
Now you can open the interactive PostgreSQL shell:
psql
Inside the shell, you need to add the user “bomnipotent_user”, a password, and create a database “bomnipotent_db”:
CREATE USER bomnipotent_user WITH PASSWORD 'your-password';
CREATE DATABASE bomnipotent_db OWNER bomnipotent_user;
GRANT ALL PRIVILEGES ON DATABASE bomnipotent_db TO bomnipotent_user;
\q
You could use different names for the user and database, but would need to adjust the “db_url” entry of your config file accordingly.
Finally, restart PostgreSQL and switch back to your regular user:
sudo systemctl restart postgresql;
exit
For Windows, PostgreSQL offers an interactive installer .
After it has completed, PostgeSQL is running as a service. Open an interactive PostgreSQL shell by starting an admin console and prompting:
psql -U postgres
Inside the shell, you need to add the user “bomnipotent_user”, a password, and create a database “bomnipotent_db”:
CREATE USER bomnipotent_user WITH PASSWORD 'your-password';
CREATE DATABASE bomnipotent_db OWNER bomnipotent_user;
GRANT ALL PRIVILEGES ON DATABASE bomnipotent_db TO bomnipotent_user;
\q
You could use different names for the user and database, but would need to adjust the “db_url” entry of your config file accordingly.
If you only want to run BOMnipotent Server as a standalone application, but still want to containerise PostgreSQL, you can spin it up via:
docker run --name bomnipotent_db \
-e POSTGRES_DB=bomnipotent_db \
-e POSTGRES_USER=bomnipotent_user \
-e POSTGRES_PASSWORD=<your-password> \
-p 5432:5432 \
-v pgdata:/var/lib/postgresql/data \
-d postgres:latest
This creates a container named “bomnipotent_db”, with a database also called “bomnipotent_db”, a user called “bomnipotent_user”, and a password that you need to set. It exposes port 5432 of the container, persists the data in a docker volume, and spins up the “postgres:latest” image in detached mode.
You could use different names for the user and database, but would need to adjust the “db_url” entry of your config file accordingly.
The suggested file structure in the favourite directory of your server looks like this:
├── bomnipotent_config
│ ├── .env
│ ├── config.toml
│ └── config.toml.default
└── bomnipotent_server
This tutorial will walk through the files and explain them one by one.
BOMnipotent server communicates with a database. Currently, only PostgreSQL is supported as a backend. The database is protected by a password. It is best practice to store the password inside a separate .env file instead of directly in the compose.yaml.
The name of the file must be “.env”, otherwise BOMnipotent Server will not recognise it.
Your .env file should look like this:
BOMNIPOTENT_DB_PW=<your-database-password>
SMTP_SECRET=<your-smtp-authentication-secret>
If you are using a versioning system to store your setup, do not forget to add “.env” to your .gitignore or analogous ignore file!
BOMnipotent Server needs a configuration file, which is explained in more detail in another section .
The name of the file is arbitrary.
A minimal configuration looks like this:
# The db_url has the structure [db_client]://[user]:[password]@[address]:[port]/[db]
# Note that ${BOMNIPOTENT_DB_PW} references an environment variable.
db_url = "postgres://bomnipotent_user:${BOMNIPOTENT_DB_PW}@localhost:5432/bomnipotent_db"
# Domain behind which bomnipotent server will be hosted
domain = "https://bomnipotent.<your-domain>.<top-level>"
# Bind to the typical port used for HTTPS
https_port = 443
[log]
# Tell the server to log to a file instead of to stdout
file = "/var/log/bomnipotent.log"
[tls]
# The path to your full TLS certificate chain
certificate_chain_path = "/etc/ssl/certs/<your-TLS-certificate-chain.crt>"
# The path to your secret TLS key
secret_key_path = "/etc/ssl/private/<your-secret-TLS-key>"
[smtp]
# The username for your mail provider, typically your mail address
user = "<you@yourdomain.com>"
# The smtp endpoint of your mail provider
endpoint = "<your.smtp.host>"
# The secret to authenticate against the mail provider, typically your password
secret = "${SMTP_SECRET}"
# Publisher data according to the CSAF Standard linked below
[provider_metadata.publisher]
name = "<Provide the name of your organsiation>"
# Namespace of your organisation, in form of a complete URL
namespace = "https://<your-domain>.<top-level>"
# This is most likely the enum variant you want
category = "vendor"
# Contact details are optional and in free form
contact_details = "<For security inquiries, please contact us at...>"
Fill in the braces with your data.
The section about TLS configuration contains more detailed information to avoid common pitfalls.
If you prefer using a local smtp releay station, have a look at the necessary adjustments to the compose file.
The publisher data is used to comply with the OASIS CSAF standard .
The section about provider-metadata goes into more details what the fields actually mean.
It is recommended to store your config.toml file inside a dedicated directory, “bomnipotent_config” in this example. BOMnipotent Server will watch the directory for any changes, meaning that it has less to watch the less files are in the folder. The server will try to reload the configuration file and the .env file if either have changed.
Many configuration values support hot reloading, meaning they can be modified without restarting the server.
After having set up your config.toml, you may want to copy it as for example config.toml.default, to be able to quickly restore your initial configuration. This is entirely optional, though.
This is the binary that runs BOMnipotent Server. You can download any version for your server platform from www.bomnipotent.de .
In principle, all BOMnipotent Server needs to run is to know the path to its config file. If you run the binary and provide the path as the first argument, you have created a working server instance. However, your terminal is now eternally blocked, and the service will not restart if you reboot your system. The rest of this section only serves to ensure that the operating system properly supports the server.
Unlike BOMnipotent Client, which runs under all major operating systems, BOMnipotent Server is currently only supported under Linux and Windows. If you want to host it on a server running MacOS, please create an issue .
This setup requires your distribution to incorporate systemd.
If you’re not sure if it does, it probably does.
If you’re sure that it does not, you probably don’t need these instructions.
Create the file “/etc/systemd/system/bomnipotent.service” with the following content:
[Unit]
Description=BOMnipotent Server
After=network.target
[Service]
ExecStart=/path/to/bomnipotent_server /path/to/bomnipotent_config/config.toml
WorkingDirectory=/path/to/bomnipotent_config
Restart=on-failure
User=<youruser>
[Install]
WantedBy=multi-user.target
Make sure to adjust the values to your specific server. Then run:
sudo systemctl daemon-reexec
sudo systemctl enable --now bomnipotent.service
Open the Task Scheduler (taskschd.msc).
In the right panel, click Create Task.
In the “General” tab:
In the “Triggers” tab:
In the “Actions” tab:
Click “OK” to save the task.
Several interactions with BOMnipotent require a user with admin rights. One of these is granting a new user admin rights. This means that some kind of bootstrapping mechanism is required.
First, you will need to create a user account :
bomnipotent_client --domain=<server> user request <your-email>
bomnipotent_client -d <server> user request <your-email>
[INFO] Generating new key pair
[INFO] Storing secret key to "/home/simon/.config/bomnipotent/secret_key.pem" and public key to "/home/simon/.config/bomnipotent/public_key.pem"
[INFO] User request submitted. It now needs to be confirmed by a user manager.
To make things a litle less verbose, let’s store the domain of your server and your email address in a user session :
bomnipotent_client --domain=<server> --email=<your-email> session login
bomnipotent_client -d <server> -e <your-email> session login
[INFO] Storing session data in /home/simon/.config/bomnipotent/session.toml
Due to security reasons, the user needs to already exist in the database at this point. Otherwise, a malicious actor could anticipate the email address you use for your admin, and make their own request at an opportune time. To prevent this, the tmp admin mechanism blocks all requests to newly add this particular user to the database.
Next, you will become the user manager that was mentioned in the server reply: Log onto your server machine, and in your server configuration file prepend
tmp_admin = "<your-email>"
It is important to add this line at the beginning of the file, otherwise BOMnipotent might try to interpret this field as part of another section.
Your server logs should now show that the configuration has been reloaded, in addition to the user request you made earlier.
docker logs bomnipotent_server
...
2025-03-06 11:30:15 +00:00 [INFO] Received POST request from 101.102.103.104 to https://bomnipotent.wwh-soft.com/user/info@wwh-soft.com
2025-03-06 11:32:56 +00:00 [INFO] Configuration successfully reloaded from "/etc/bomnipotent_server/configs/config.toml"
...
The server now treats authenticated requests from that user as if that user was an admin. To become a permanent admin, you first need to approve your user request. Back on the client, call
bomnipotent_client user approve <your-email>
[INFO] Changed status of info@wwh-soft.com to APPROVED
Now you can make yourself a full server admin:
bomnipotent_client user-role add <your-email> admin
[INFO] Added role to user
The stat of being a temporary admin is intended to be, well, temporary. The server logs a warning whenever you use temporary access rights:
docker logs bomnipotent_server -n 4
2025-03-06 14:51:35 +00:00 [INFO] Received POST request from info@wwh-soft.com to https://bomnipotent.wwh-soft.com/user/info@wwh-soft.com/roles
2025-03-06 14:51:35 +00:00 [WARN] Temporary admin functionality is enabled for info@wwh-soft.com
2025-03-06 14:51:35 +00:00 [INFO] User info@wwh-soft.com was authenticated as a temporary admin
2025-03-06 14:51:35 +00:00 [INFO] Temporary admin info@wwh-soft.com has permission USER_MANAGEMENT to perform this action
But now that you have successfully made yourself a permanent admin, you can and should remove the “tmp_admin” field from the configuration file again.
You are now ready to activate your subscription .
Most actions that add data to your BOMnipotent database require an active subscription, while reading and removing data do not. This policy ensures that your users do not loose access to the existing data should you one day choose to stop paying for the product.
Commercial entities like companies can acquire a subscription on bomnipotent.de . If you are a non-commercial entity, you can use BOMnipotent without any charge. Request access by sending an email to info@wwh-soft.com .
Shortly after you have acquired a subscription, you will receive an email containing your subscription key.
Subscriptions can only be managed by a user with the “admin” role. Create one if you haven’t already.
Logged in as that user, call
bomnipotent_client subscription activate <your-subscription-key>
[INFO] Successfully stored subscription key.
To check the current status of your subscription, run
bomnipotent_client subscription status
╭──────────┬─────────────┬─────────────────────┬─────────────────────────┬─────────────────────────┬───────────────────────────╮
│ Key │ Product │ Subscription Status │ Valid Until │ Last Updated │ Assessment │
├──────────┼─────────────┼─────────────────────┼─────────────────────────┼─────────────────────────┼───────────────────────────┤
│ ***ccfb3 │ BOMnipotent │ active │ 2025-04-10 17:26:29 UTC │ 2025-03-10 16:26:29 UTC │ The subscription is valid │
│ │ │ │ │ │ . │
╰──────────┴─────────────┴─────────────────────┴─────────────────────────┴─────────────────────────┴───────────────────────────╯
This section describes how you can make an instance of BOMnipotent server your own. It introduces the config file , and explains all required and optional parameters it understands.
Your instance of BOMnipotent Server is configured using a config file. It contains several values, provided in TOML Format . The setup instructions each contain a config file that you can fill with your specific data. All configurations accepted by BOMnipotent Server are described in the rest of this section .
Many configurations support hot reloading. This means that you can change them inside the file, and they take effect without requiring a restart of the server. BOMnipotent Server achieves this by watching for changes of files in the directory that the config file resides in. You can verify a successful reload of the configurations by looking at the logs:
docker logs bomnipotent_server -n 1
2025-03-06 15:34:45 +00:00 [INFO] Configuration successfully reloaded from "/etc/bomnipotent_server/configs/config.toml"
If something does not work as intended, BOMnipotent will also let you know in the logs:
docker logs bomnipotent_server -n 6
2025-03-06 16:11:03 +00:00 [ERROR] Failed to read config file "/etc/bomnipotent_server/configs/config.toml": Failed to parse config file: TOML parse error at line 5, column 1
|
5 | starlight_throughput = "16 GW"
| ^^^^^^^^^^^^^^^^^^^^
unknown field `starlight_throughput`, expected one of `allow_http`, `allow_tlp2`, `certificate_chain_path`, `db_url`, `default_tlp`, `domain`, `dos_prevention_limit`, `dos_prevention_period`, `log_level`, `provider_metadata_path`, `publisher_data`, `secret_key_path`, `tmp_admin`, `user_expiration_period`
If the configuration loading produces an error during server startup, the process is aborted. If the configuration cannot be reloaded for an already running server, then the last valid configuration is left untouched.
The official BOMnipotent Server docker image looks for the config file at the path “/etc/bomnipotent_server/configs/config.toml” inside the container. It is recommended to read-only bind the container path “/etc/bomnipotent_server/configs/” to a directory of your choice on the host machine.
Important: For the hot reloading to work, your docker volume must bind to the directory in which the config file is located, not to the file itself. With a direct file binding BOMnipotent will not receive file events and thus cannot reload the config on change.
Inside your config files, you can reference environment variables. To do so, simply use ${<some-env-var>}
anywhere within the file, where “<some-env-var>” is replaced with the name of the variable.
For example, if you provide
BOMNIPOTENT_DB_PW=eHD5B6S8Kze3
export BOMNIPOTENT_DB_PW=eHD5B6S8Kze3
set BOMNIPOTENT_DB_PW=eHD5B6S8Kze3
$env:BOMNIPOTENT_DB_PW = "eHD5B6S8Kze3"
docker run -e BOMNIPOTENT_DB_PW=eHD5B6S8Kze3 wwhsoft/bomnipotent_server --detach
db_url = "postgres://bomnipotent_user:${BOMNIPOTENT_DB_PW}@bomnipotent_db:5432/bomnipotent_db"
You wouldn’t actually use this publicly available example passwort, would you?
BOMnipotent Server supports reading variables from a .env file. If a file with that exact name, “.env”, is located next to your config file, the server will try to evaluate it before loading the config.
Changing the .env file while BOMnipotent Server is running will trigger a hot reloading and a re-evaluation of both the .env and the config file.
This section explains all parameters which you need to set in order for BOMnipotent Server to start. This required data is specific to you and your setup, which is why it is impossible to assume a meaningful default here.
The “db_url” configuration does not support hot reloading. You will need to restart the server after modifying it.
BOMnipotent Server is your gateway for providing supply chain security data and managing access to it. The data itself is stored in a SQL database.
At the moment, only PostgreSQL is supported as a driver.
This database can in principle run in the same environment, in a different container, or on a remote server. BOMnipotent needs to be taught how to reach it. The parameter for providing this information in the config file is “db_url”, and the syntax is the following:
db_url = "<driver>://<user>:<password>@<domain>:<port>/<database>"
BOMnipotent will be cross with you if the string you provide does not adhere to this format.
An actual entry could for example be
db_url = "postgres://bomnipotent_user:${BOMNIPOTENT_DB_PW}@bomnipotent_db:5432/bomnipotent_db"
Let’s break this down:
If BOMnipotent Server cannot reach the database, it will let you know in the logs.
BOMnipotent Server is not only reachable per API, but also displays some static XML and HTML pages. One important example is that it may generate CSAF Provider Metadata for you. As some of these pages reference one another, the server needs to know the full domain behind which it is reachable from the internet.
The parameter is simply called “domain”. Providing a protocol is optional, “https” is assumed as a default.
The relevant part in the config file may for example look like this:
domain = "https://bomnipotent.wwh-soft.com"
domain = "bomnipotent.wwh-soft.com"
The TLS configuration does not support hot reloading. You will need to restart the server after modifying it.
This section serves to give people who never had to deal with TLS a broad understanding of the process. Feel free to skip ahead to the section about configuration .
Transport Layer Security (TLS), sometimes also called by its legacy name Secure Socket Layer (SSL), is what puts the “S” in “HTTPS”. It is a very sophisticated, smart and widely used method for end-to-end encrypting of communication over the internet, but it can also lead to a lot of head scratching.
In very broad terms, TLS works as outlined in the following paragraphs:
Your server generates a pair of secret and public key. Anyone can use the public key to either encrypt a message that only the secret key can decrypt, or to decrypt a message that was encrypted with the secret key.
When a client reaches out to your sever asking for encryption, the latter responds by sending a TLS certificate. It contains several important field:
The digital signature is not created with the server’s secret key, because the client does not trust that key yet. Instead, there are some (several hundred) public keys stored on your machine that belong to so called “Root Certificate Authorities”. The job of these is to sign server certificates after they have verified that the bearer of the secret key is also the owner of the domains they claim.
For practical reasons the root CAs usually do not directly sign a server certificate, but rather an intermediate certificate, which is then used to sign the final certificate.
All in all, the chain of trust thus looks like this:
Thus, the client decides to trust the server and establich an encrypted connection.
Because BOMnipotent is secure-by-default, it requires you to make at least one statement about TLS encryption. The “tls” section of your configuration file accepts the following fields:
[tls]
allow_http = false # Optional, is false by default
certificate_chain_path = "your-chain.crt"
secret_key_path = "your-key.pem"
Providing the TLS certificate paths is required if HTTP is not allowed (because the server could not offer any connection otherwise), and it is optional if HTTP is explicityl allowed by setting allow_http to true. If you set either the certificate_chain_path or the secret_key_path , you will also need to set the other. Furthermore, the server checks if there is a mismatch between the two.
If you set this optional field to true, your BOMnipotent Server will allow unencrypted connections. This makes sense if your server is running behind a reverse proxy, and is communicating to it only over the local network. In this setup, the server is not directly reachable from the internet, so the reverse proxy can handle encryption for it.
The default port for HTTPS is 8080, but it can be freely configured .
Please note that the OASIS CSAF Standard requires that the access to your CSAF documents is encrypted!
The value of “secret_key_path” needs to point to a file that is reachable for BOMnipotent server. One common value is:
secret_key_path = "/etc/ssl/private/<yourdomain>_private_key.key"
If your BOMnipotent Server is running inside a docker container, you may want to bind mount the container directory “/etc/ssl” to the directory with the same name on the host.
The file needs to be an ASCII-armoured secret key in PEM-Format . Luckily, this is the format you typically receive when obtaining a TLS certificate.
The contents of the file could for example look like this:
-----BEGIN PRIVATE KEY-----
MC4CAQAwBQYDK2VwBCIEIHru40FLuqgasPSWDuZhc5b2EhCGGcVC+j3DuAqiw0/m
-----END PRIVATE KEY-----
This is the secret key from a certificate generated for the BOMnipotent integration tests.
Likewise, the “certificate_chain_path” needs to point to a file reachable by BOMnipotent Server. A typical location is:
certificate_chain_path = "/etc/ssl/certs/<yourdomain>-fullchain.crt"
The chain needs to contain all certificates in the chain of trust concatenated together, beginning with the one for your sever and ending with the root certificate authority.
The contents of the full certificate chain for the integration test looks like this:
-----BEGIN CERTIFICATE-----
MIIB8jCCAaSgAwIBAgIBAjAFBgMrZXAwPTELMAkGA1UEBhMCREUxHDAaBgNVBAoT
E0JPTW5pcG90ZW50IFRlc3QgQ0ExEDAOBgNVBAMTB1Rlc3QgQ0EwHhcNMjUwMzA1
MTMxNzEwWhcNMjUwNDI0MTMxNzEwWjBFMQswCQYDVQQGEwJERTEgMB4GA1UEChMX
Qk9Nbmlwb3RlbnQgVGVzdCBTZXJ2ZXIxFDASBgNVBAMTC1Rlc3QgU2VydmVyMCow
BQYDK2VwAyEAMzw8ZVgiuP3bSwh+xcBXu62ORwakr/D+s0XQks1BTFOjgcAwgb0w
DAYDVR0TAQH/BAIwADBIBgNVHREEQTA/gglsb2NhbGhvc3SCCTEyNy4wLjAuMYIT
c3Vic2NyaXB0aW9uX3NlcnZlcoISYm9tbmlwb3RlbnRfc2VydmVyMBMGA1UdJQQM
MAoGCCsGAQUFBwMBMA4GA1UdDwEB/wQEAwIGwDAdBgNVHQ4EFgQUC/RAGubXMfx1
omYTXChtqneWDLcwHwYDVR0jBBgwFoAUStstIFLzDjBSHYSsSr9hSgRVZT4wBQYD
K2VwA0EAXN/6PpJQ0guaJq67kdKvPhgjWVdfxxeCAap8i24R39s7XxNz5x5lPyxA
DQG63NS/OED43+GfpkUguoKxfZLBBA==
-----END CERTIFICATE-----
-----BEGIN CERTIFICATE-----
MIIBazCCAR2gAwIBAgIBATAFBgMrZXAwPTELMAkGA1UEBhMCREUxHDAaBgNVBAoT
E0JPTW5pcG90ZW50IFRlc3QgQ0ExEDAOBgNVBAMTB1Rlc3QgQ0EwHhcNMjUwMzA1
MTMxNzEwWhcNMjUwNjEzMTMxNzEwWjA9MQswCQYDVQQGEwJERTEcMBoGA1UEChMT
Qk9Nbmlwb3RlbnQgVGVzdCBDQTEQMA4GA1UEAxMHVGVzdCBDQTAqMAUGAytlcAMh
AIoFFlU/ADa77huqAb5aBY9stDwzzDd/Tdocb9RZDBG2o0IwQDAPBgNVHRMBAf8E
BTADAQH/MA4GA1UdDwEB/wQEAwIBBjAdBgNVHQ4EFgQUStstIFLzDjBSHYSsSr9h
SgRVZT4wBQYDK2VwA0EARYL+v9oDGjaSW5MhjjpQUFXnAVMFayaKFfsfbbkmTkv4
+4SRWFb4F/UULlbbvlskSgt8jAaaTSk7tu/iX67YDw==
-----END CERTIFICATE-----
The first certificate (“MIIB8j…”) authenticates the server, the second one (“MIIBaz…”) is that of the root CA.
There is no intermediate certificate authority here because it is not required for the tests. In your productive environemnt with real certificates you will most likely need to add an intermediate certificate in the middle.
Simple Mail Transfer Protocol (SMTP) is the protocol used for sending emails. In the context of BOMnipotent, the server uses it to verify that newly requested users have access to the email address they provided. To enable the server to do that, it needs to be taught to reach an SMTP endpoint.
The smtp section of the configuration file looks like this:
[smtp]
user = "you@yourdomain.com"
endpoint = "your.smtp.host"
secret = "${SMTP_SECRET}" # Optional
starttls = true # Optional, defaults to false
The SMTP user is the email address you use when authenticating with your mail server.
The SMTP endpoint tells BOMnipotent where to send the data to. It can point directly to your mailserver, or to an SMTP relay.
If the endpoint begins with the “smtp://” marker, BOMnipotent Server will try to directly connect to that URL. This is typically what you want when connecting to a locally running relay. Otherwise, it will connect to an external relay.
When directly communicating with your mailserver, you have to authenticate. The secret will either be your password, or an API key if your mail provider offers one. In the example above, the secret is read from an environmen variable called “SMTP_SECRET”, which could for example come from a .env file.
A locally running SMTP relay does not necessarily require a password to accept mails, which is why this field is optional.
STARTTLS is one option to encrypt sending emails, the other being SMTPS. Since 2018, the Internet Engineering Task Force recommends against using STARTTLS . However, if your mailserver does not support SMTPS, STARTTLS is better than no encryption, which is why it is still supported by BOMnipotent Server.
If you do not (yet) have access to an SMTP server, you can eliminate the need for the smtp configuration by adding the following line to the global context (meaning at the beginning) of your config.toml:
skip_user_verification = true
BOMnipotent Server will then not send a verification email to newly requested users. It will instead log a warning message each time it does not send said mail, because this configuration reduces the security of your server.
The OASIS Standard requires that providers of CSAF documents offer a “provider-metadata.json”, which needs to follow a specific schema .
BOMnipotent strives to make it as easy as possible to fulfil this requirement. You can either generate the file from a few inputs, or provide a file for BOMnipotent to load.
By providing some user-specific inputs, you can make BOMnipotent generate a valid provider-metadata.json file. This is much easier than creating the file by hand, but offers somewhat less control.
The relevant section in your config file looks like this:
[provider_metadata.publisher]
name = "<name of your organsiation>"
namespace = "https://<your-domain>.<top-level>"
category = "vendor"
issuing_authority = "<Additional info>" # Optional
contact_details = "<Please contact us at...>" # Optional
This field requires you to provide the name of your company, organisation, or you as an individual.
While the “name” field is primarily aimed at humans, the “namespace” is used by machines to identify your organisation across various security documents. It needs to be in URI format, including protocol, domain and top-level domain. Because it refers to your whole organisation, it should not contain a subdomain.
This is what sets the “provider_metadata.publisher.namespace” field apart from the “domain” configuration: The latter points to your instance of BOMnipotent Server, while the former is much more general.
The publisher category is a machine readable classification of who you are. According to the CSAF Standard , the publisher categories allows the values “coordinator”, “discoverer”, “other”, “translator”, “user” or “vendor”. As a user of BOMnipotent Server, you are most likely a “vendor”, meaning a developer or retailer of products or a service.
This optional field can be used to clarify your connection to the hosted documents. Are you the developer and maintainer? Are you a retailer? The input is in free form.
This optional field allows you to offer contact details for general or security inquiries. The input is a string in free form.
Once you have provided the data and started the server, the generated document will host it under “your-domain/.well-known/csaf/provider-metadata.json”. You can see a live example here and a static example here:
{
"canonical_url": "https://bomnipotent.wwh-soft.com/.well-known/csaf/provider-metadata.json",
"distributions": [
{
"rolie": {
"feeds": [
{
"summary": "WHITE advisories",
"tlp_label": "WHITE",
"url": "https://bomnipotent.wwh-soft.com/.well-known/csaf/white/csaf-feed-tlp-white.json"
},
{
"summary": "GREEN advisories",
"tlp_label": "GREEN",
"url": "https://bomnipotent.wwh-soft.com/.well-known/csaf/green/csaf-feed-tlp-green.json"
},
{
"summary": "AMBER advisories",
"tlp_label": "AMBER",
"url": "https://bomnipotent.wwh-soft.com/.well-known/csaf/amber/csaf-feed-tlp-amber.json"
},
{
"summary": "RED advisories",
"tlp_label": "RED",
"url": "https://bomnipotent.wwh-soft.com/.well-known/csaf/red/csaf-feed-tlp-red.json"
},
{
"summary": "UNLABELED advisories",
"tlp_label": "UNLABELED",
"url": "https://bomnipotent.wwh-soft.com/.well-known/csaf/unlabeled/csaf-feed-tlp-unlabeled.json"
}
]
}
}
],
"last_updated": "2025-03-06T16:13:24.632235974Z",
"list_on_CSAF_aggregators": true,
"metadata_version": "2.0",
"mirror_on_CSAF_aggregators": true,
"publisher": {
"category": "vendor",
"contact_details": "For security inquiries, please contact info@wwh-soft.com",
"name": "Weichwerke Heidrich Software",
"namespace": "https://wwh-soft.com"
},
"role": "csaf_provider"
}
This file contains a ROLIE feed for all your CSAF documents, which is probably the main reason why you do not want to create this document by hand.
The “last_updated” field is generated from the last modification timestamp of your config file.
BOMnipotent assumes that you want your CSAF documents listed and mirrored on publicly available repositories. This only concerns the documents labeled TLP:WHITE / TLP:CLEAR! The aggregators do not have access to any documents classified otherwisely.
BOMnipotent helps you fulfil all requirements to be a CSAF Provider , according to the OASIS standard.
If for some reason you want to have full control of the provider-metadata document, you can provide a filepath in the config file:
[provider_metadata]
path = "<filepath>"
BOMnipotent will then read the file, check that it follows the provider-metadata json schema , and host it.
You have to provide either a path to a file, or publisher data. If you provide neither or both, the config will not be loaded.
This section lists all optional configuration parameters for BOMnipotent. They can be used to further customise the server’s behaviour. If they are not provided, they assume a meaningful default value.
BOMnipotent is secure-by-default, meaning you can in good conscience ignore these parameters for the inital sever setup.
To keep track of the history of interactions with BOMnipotent Server, every event potentially results in a log being written. These logs are printed to the standard output by default. If the server is running inside a docker container named “bomnipotent_server”, you can see the last 3 lines of logs by calling
docker logs bomnipotent_server -n 3
2025-03-08 09:16:10 +00:00 [INFO] Database is ready.
2025-03-08 09:16:15 +00:00 [DEBUG] Header X-Auth-Email was not found in request
2025-03-08 09:16:15 +00:00 [DEBUG] Received healthcheck request from 127.0.0.1
The logs have the format “Date, Time, Timezone, Log Level, Message”.
The relevant section of your config file to manipulate logging looks like this:
[log] # This section is optional
level = "debug" # Default severity level is "info"
file = "/var/log/bomnipotent.log" # Default is to log to stdout
The logs do not contain confidential information. For example, the notification about the database connection obfuscates username and password:
2025-03-08 09:16:10 +00:00 [INFO] Creating connection pool for database: postgres://[user]:[password]@database:5432/bomnipotent_db
BOMnipotent Server supports five log levels:
Each severity level includes the log messages from the previous ones. The default severity level is “info”, meaning it prints log messages with severities “error”, “warn” and “info”.
An error indicates that an operation has to be aborted. Either the user input or the configuration has to change for it to work, and it needs to be triggered again.
Common examples include:
A warning is displayed when some input or configuration is suboptimal. The operation is still completed, but you or the user are urged to change either input or configuration.
Common examples include:
This is the default severity level for logs.
Logs with level info indicate regular events that are important, but rare enough to not overwhelm the output.
Common examples include:
Configure debug log severity level to find errors in the configuration or user input. These logs help to understand, step by step, what the program does, and where something may go wrong.
Common exmples include:
As the lowest possible severity level, trace logs contain a lot of output. In contrast to the debug level, the trace level is meant to assist in finding errors in BOMnipotent itself. It is thus unlikely that you will ever need to configure this level, because it is mainly targeted at the developer. Common examples include:
If you provide a valid path for the “file” key under the “log” section of your config file, BOMnipotent Server will print its outputs there instead of stdout. This is mainly useful if you run the server outside of any container.
[log]
file = "/var/log/bomnipotent.log"
If the file already exists, BOMnipotent Server will mercilessly overwrite it upon a restart, if it has the permissions to do so.
Only an admin can give admin permissions to a user. In order to create the first admin, you therefore need to enable these permissions via another, temporary path. This is done with the config parameter “tmp_admin”, which takes the email of a user as an input:
tmp_admin = "<email>"
The whole procedure is described in the setup instructions .
For security reasons, the rules surrounding temporary adminship are rather strict, and allow only one specific order of operations:
If the rules were less strict and you could designate a temporary admin before the user is registered in the database, an attacker could potentially request a new user with the correct email address and would then have admin permissions on your system.
CSAF documents can and in fact should be classified using the Traffic Light Protocol (TLP) . It clarifies if and with whom you can share documents that you have access to. The somewhat older TLP v1.0 standard knows four different classifications:
The more current TLP v2.0 standard replaces TLP:WHITE with TLP:CLEAR, and adds the new classification TLP:AMBER+STRICT, which only allows sharing on a need-to-know basis with the recipient’s organisation, but not beyond.
Documents hosted by BOMnipotent Server that are classified as TLP:WHITE or TLP:CLEAR are visible to everyone, be they admin, completely unauthenticated user or crawler bot!
The “tlp” section of your configuration file may contain the following fields:
[tlp]
allow_tlp2 = true # Default is false
default_tlp = "amber+strict" # Default is "red"
The current OASIS CSAF Standard requires documents to be classified with TLP v1.0 labels. However, many companies would prefer to use the TLP:AMBER+STRICT classification from the TLP v2.0 standard for their documents. Furthermore, the TLP v2.0 standard will become mandatory once the CSAF standard 2.1 is released.
To be fully compliant with the CSAF standard, BOMnipotent does not allow TLP v2.0 labels by default. You can, however, set the field “allow_tlp2” to true in the “tlp” section of your config file:
[tlp]
allow_tlp2 = true
If you do, both TLP v1.0 and TLP v2.0 labels will be accepted.
If you do not, and BOMnipotent encounters TLP v2.0 labels, it will silently convert TLP:CLEAR to TLP:WHITE. Because TLP:AMBER+STRICT has no direct equivalent in TLP v1.0, BOMnipotent will take the conservative approach, convert it to TLP:RED, and log a warning.
Classifying a CSAF document with a TLP label is optional, and a TLP classification is not even part of the CycloneDX standard for BOM documents. BOMnipotent needs to at least know if the document is labelled TLP:CLEAR / TLP:WHITE and thus publicly available, or if access to it is restricted.
It is good practice to define a TLP classification that BOMnipotent can fall back to for an unlabelled document. You can do that in your config file via:
[tlp]
default_tlp = "amber"
The deserialisation gives you some leeway: It does not consider the casing, and the “TLP:” prefix is optional. The values “amber”, “AMBER”, “tlp:amber” and “TLP:AMBER” are all recognised as TLP:AMBER.
If you do not provide a default TLP label, and BOMnipotent encounters an unlabelled document, it will default to TLP:RED and log a warning.
The default TLP label is evaluated at the time of access, not at the time of writing. Unlabelled documents remain unlabelled in the database. If at any point you change the default TLP label, you thus change it for all unlabelled documents of past and future .
When a request for a new user account is made, it deposits a public key in the database.
This key has an expiration data, after which it is not accepted anymore. This can be seen by calling:
./bomnipotent_client user list
╭───────────────────┬──────────┬───────────────────────────┬───────────────────────────╮
│ User Email │ Status │ Expires │ Last Updated │
├───────────────────┼──────────┼───────────────────────────┼───────────────────────────┤
│ info@wwh-soft.com │ APPROVED │ 2026-03-03 11:30:15.62432 │ 2025-03-02 11:47:38.51048 │
│ │ │ 5 UTC │ 5 UTC │
╰───────────────────┴──────────┴───────────────────────────┴───────────────────────────╯
By default, the key is valid for a little over a year after it was requested. This time can be configured with the “user_expiration_period” parameter. As values it accepts a time period in the human readable format “user_expiration_period = "366 days"
user_expiration_period = "5 years"
user_expiration_period = "1 month"
user_expiration_period = "3 weeks"
user_expiration_period = "5 days"
If you really hate your users you could also use “hours”, “minutes”, seconds", “ms”, “us” or “ns” as units. BOMnipotent does not question how realistic your expectations are.
Changing this configuration does not affect the expiration dates of existing users! It will only influence how much time is given to newly requested users.
Denial of Service (DOS) attacks target programs or servers with the goal of making them unresponsive. They are notoriously hard to mitigate, because they are often based on flooding the service with otherwise legitimate requests.
BOMnipotent has several DOS prevention mechanisms in place (from disallowing any code that might crash the server to limiting the length of log outputs), but one particular technique can be tweaked by the user.
If the number of requests from a single source exceeds a limit within a time period, that source is put on a greylist for one hour, which automatically denies requests.
By default, this happens if the number of requests exceeds 100 within one minute, but you can modify this behaviour in your config file:
[dos_prevention]
limit = 50 # Default is 100
period = "30 seconds" # Default is "1 minute"
This new config would make the server react faster to a possible DOS attack, but has a higher risk to falsely classify request as an attack.
While IP addresses are used to identify your server on the internet, ports are used to identify individual services running on it. Upon startup, BOMnipotent offers one or two services: An HTTP service for unencrypted communication, an HTTPS service for encrypted communication, or both.
Important: Use unencrypted communication only within a machine! Pure HTTP communication over the internet is a thing of the past, and rightly so.
By default, BOMnipotent offers its services over the ports 8080 and 8443. It does so to avoid collisions, and because it is primarily intended to be run inside a container. If you want to run BOMnipotent without the container abstraction, you can instead offer the services via the ports typically associated with HTTP and HTTPS:
http_port = 80 # Default is 8080
https_port = 443 # Default is 8443
Any other unsigned 16 bit number will also do.