# Hauptkonfiguration - bffh.dhall

BFFH verwendet [Dhall](https://docs.fab-access.org/books/awesome-fabinfra/page/glossar-begrifflichkeiten-und-abkurzungen#bkmrk-dhall) für die Struktur von Ressourcen (z.B. Maschinen), Rollen, Aktoren und Initiatoren. Die Konfiguration von BFFH befindet sich in der Datei `<span class="pre">bffh.dhall</span>`. Die Datei kann auch umbenannt werden. Wichtig ist, dass sie dann überall korrekt referenziert wird (z.B. in Service Scripts). Der betreffende Quellcode findet sich in [GitLab](https://gitlab.com/fabinfra/fabaccess/bffh/-/blob/main/bffhd/config/dhall.rs?ref_type=heads).

[![grafik.png](https://docs.fab-access.org/uploads/images/gallery/2025-02/scaled-1680-/1EBzdHIzCwSBbKoT-grafik.png)](https://docs.fab-access.org/uploads/images/gallery/2025-02/1EBzdHIzCwSBbKoT-grafik.png)

*Offizielles Dhall Logo*

## Tipps &amp; Tricks in Dhall

Dhall ist eine umfangreiche Sprache für die Konfiguration und erlaubt äußerst komplexe Datenstrukturen. Vieles davon wird für FabAccess vermutlich nur im kleineren Rahmen benötigt, jedoch besteht die Kompatibilität auch für komplizierte Gebilde. Im Rahmen dieser Dokumentationen gehen wir nur auf grundlegende, wichtige und besonders praktische Konfigurationsaspekte ein.

<p class="callout success">Ein nutzbringenden Cheatsheet für Dhall findet sich unter [https://docs.dhall-lang.org/howtos/Cheatsheet.html](https://docs.dhall-lang.org/howtos/Cheatsheet.html)</p>

### Literal für leere Einträge

Dhall-Records können auch leer übergeben werden. Dafür gibt es eine spezielle Syntax: `{=}`. Siehe [https://hackage.haskell.org/package/dhall-1.42.1/docs/Dhall-Tutorial.html#g:6](https://hackage.haskell.org/package/dhall-1.42.1/docs/Dhall-Tutorial.html#g:6)

**Beispiel:**

```ini
initiators = {=}
```

### Literal "Some"

Die folgenden beiden Angaben sind inhaltlich gleich. Das Wörtchen "Some" macht in unserem Beispiel den Wert `port` optional. Diese Notation kann verwendet werden, um innerhalb einer Konfiguration darauf hinzuweisen, dass ein Wert fest gesetzt werden könnte, aber aktuell nicht von Nöten ist. Siehe [https://hackage.haskell.org/package/dhall-1.42.1/docs/Dhall-Tutorial.html#g:5](https://hackage.haskell.org/package/dhall-1.42.1/docs/Dhall-Tutorial.html#g:5)

**Beispiel:**

```ini
listens = [{ address = "127.0.0.1" }]
```

```ini
listens = [{ address = "127.0.0.1", port = Some 59661 }]
```

### Kommentare  


<p class="callout info">Siehe [https://docs.dhall-lang.org/tutorials/Language-Tour.html#comments](https://docs.dhall-lang.org/tutorials/Language-Tour.html#comments)</p>

Zeilen, die mit `--` beginnen, werden automatisch als Kommentar gewertet. Das kann auch verwendet werden, um z.B. nicht mit dem Literal "`Some`" zu arbeiten. So können wir z.B. eine Originalzeile auskommentieren und darunter unsere angepasste Zeile schreiben.

**Beispiel Zeilenkommentar:**

```ini
--listens = [{ address = "127.0.0.1", port = 59661 }]
listens = [{ address = "127.0.0.1" }]
```

Kommentare können auch in Blöcken geschrieben werden, wenn sie in einem Block beginnend `{-` und endend mit `-}` stehen. So werden diese bei etwaigen Formatieroperationen mit `dhall format <Datei>` nicht entfernt!

**Beispiel Blockkommentar**:

```ini
{- Main configuration file for bffh
   ================================
  
   In this configuration file you configure almost all parts of how bffh operates, but most importantly:
        * Machines
        * Initiators and Actors
        * Which Initiators and Actors relate to which machine(s)
        * Roles and the permissions granted by them
 -}
```

**Beispiel Blockkommentar an beliebiger Stelle**:

```ini
    roles = ./roles.dhall, {- Kommentar mitten im Text -}
```

### Zeichenketten erzeugen

Werte können zusammengefügt werden (concatenation). Das geht zum Beispiel mit dem Syntax `++` wie folgt:

```ini
certfile = env:BFFH_CFG_PATH as Text ++ "/cert/bffh.crt"
```

Oder als Verkettungsbefehl:

```ini
hobbies = concatSep ", " [ "piano", "reading", "skiing" ]
```

### Dhall-Konfigurationen verschlanken

Folgende Möglichkeiten der Vereinfachung und Granulierung von Dhall-Dateien stellen wir vor. Wir berufen uns unter anderem auf die Dokumentation [https://github.com/dhall-lang/dhall-lang/blob/master/standard/imports.md](https://github.com/dhall-lang/dhall-lang/blob/master/standard/imports.md)

#### Variablen/Konstanten innerhalb einer Datei setzen

Folgendes Beispiel erzeugt ein Listing `VARS`, welches drei Variablen enthält, die vereinheitlicht angesprochen werden können. Variablen lassen sich auf diese Art und Weise beliebig tief schachteln. Zu beachten ist das kleine Wörtchen `in`, welches im darauffolgenden Block (Record) eine Ersetzung bzw. Referenzierung anstrebt.

```ini
let VARS = {
	BFFH_CFG_PATH = "/etc/bffh/",
	MQTT_USER = "fabinfra101",
	MQTT_PASSWD = "fablocal"
	}
in {
    listens = [
        { address = "0.0.0.0", port = 59661 }
        ],
    certfile = VARS.BFFH_CFG_PATH ++ "certs/bffh.crt",
    keyfile = VARS.BFFH_CFG_PATH ++ "certs/bffh.key",
    mqtt_url = "mqtt://" ++ VARS.MQTT_USER ++ ":" ++ VARS.MQTT_PASSWD ++ "@0.0.0.0:1883",
    db_path = VARS.BFFH_CFG_PATH ++ "bffh.db"
    }
```

#### Umgebungsvariablen verwenden

Wir setzen z.B. ein einer Bash-Umgebung einen Variablenwert und führen ein Kommando aus, welches die nachfolgende Dhall-Datei verwendet. Der Prozess, der die Dhall-Datei interpretiert, sucht in seiner übergebenen Umgebung (Environment) nach passenden Variablen und ersetzt die Werte entsprechend.

Als Rohtext in Dhall:

```bash
# bash
export BFFH_CFG_PATH="/etc/bffh"
```

```ini
bffh_cfg = env:BFFH_CFG_PATH as Text
```

oder als aufgelöster Pfad in Dhall:

```bash
# bash
export BFFH_CFG_PATH="~/bffh"
```

```ini
bffh_cfg = env:BFFH_CFG_PATH as Location
```

#### Inhalte aus URLs importieren

Folgender Syntax lädt den Content der entfernten URL als Variableninhalt:

```ini
let concatSep = http://prelude.dhall-lang.org/Prelude/Text/concatSep sha256:fa909c0b2fd4f9edb46df7ff72ae105ad0bd0ae00baa7fe53b0e43863f9bd34a
```

Importe können mit Integritätsprüfungen geschützt werden, wenn ein SHA-256-Hash angehängt wird (wie beim obigen `concatSep`-Import). Dadurch verhindern wir Manipulation von außerhalb.

#### Dhall-Dateien innerhalb anderer Dhall-Dateien referenzieren (verschachteln)

Importierte Ausdrücke können transitiv andere Ausdrücke importieren. Eine exemplarische Datei `./schema.dhall` kann andere Dateien importieren:

```ini
{ 
    name : ./schema/name.dhall, 
    age  : ./schema/age.dhall, 
    hobbies : ./schema/hobbies.dhall
}
```

... und wenn `./schema/hobbies.dhall` einen relativen Import enthielte wie z.B.:

```ini
List ./hobby.dhall
```

... dann würde sich der relative Import von `./hobby.dhall` tatsächlich auf `./schema/hobby.dhall` beziehen. Dies ist als "Importverkettung" bekannt: die Auflösung von Importen relativ zur Position des aktuellen Ausdrucks.

### Auf Kommas achten

In verschiedenen Konfigurationssprachen wie JSON, TOML und Dhall verhalten sich die Syntaxregeln unterschiedlich. In Dhall-Dateien ist es für einige Parser schädlich, wenn innerhalb einer List oder eines Records ein "trailing" Komma auftaucht. Folgendes sollte vermieden werden:

```ini
listens = [
    { address = "127.0.0.1" },
    { address = "::1" },
    ]
```

Syntaktisch korrekt ist:

```ini
listens = [
    { address = "127.0.0.1" },
    { address = "::1" }
    ]
```

<p class="callout info">BFFH kommt mit diesem Kommaproblem aus, jedoch der offizielle [dhall-haskell](https://github.com/dhall-lang/dhall-haskell) Parser nicht.</p>

### Kurze oder lange Schreibweise

Wir können die Unterlemente `Dummy_123`, `Dummy_234` und `Dummy_345` im Beispiel in ein neues Klammernpaar schreiben oder direkt mit einem Punkt abtrennen und auf die gleiche Zeile schreiben:

```ini
actors = { 
    Dummy_123 = { 
          module = "Dummy", 
          params = {=}
          },
    Dummy_234 = { 
          module = "Dummy", 
          params = {=}
          },
    Dummy_345 = { 
          module = "Dummy", 
          params = {=}
          }
    }
```

Oder entsprechend eingekürzt:

```ini
actors.Dummy_123 = { 
    module = "Dummy", 
    params = {=}
    },
actors.Dummy_234 = { 
    module = "Dummy", 
    params = {=}
    },
actors.Dummy_345 = { 
    module = "Dummy", 
    params = {=}
    }
```


Oder bei Rollen:

```ini
roles = {
    Admin = {
       permissions =  [
               "bffh.users.manage",
               "bffh.users.info",
               "bffh.users.admin"
             ]
        }
    }
```

... eingekürzt:

```ini
roles.Admin.permissions =  [
    "bffh.users.manage",
    "bffh.users.info",
    "bffh.users.admin"
    ]
```

<p class="callout info">Das eignet sich bei [Rollen](#bkmrk-roles-1), [Aktoren](#bkmrk-actors%3A%3Arecord) und [Initiatoren](#bkmrk-initiators%C2%A0%28object%29)! Wie es verwendet werden soll ist hier Geschmackssache.</p>

### Dhall-Dateien parsen, prüfen und formatieren

Dhall-Dateien können mit einer eigenen Bibliothek geparsed und auf Fehler geprüft werden. Das Resultat kann zudem neu formatiert ausgegeben werden - auch unter den Stichworten *Beautify* oder *Prettyprint* bekannt. Hierfür muss die Bibliothek `dhall` installiert werden.

```bash
sudo apt install dhall
```

Falls die Installation scheitert, kann das Paket auch manuell installiert werden (siehe [https://pkgs.org/search/?q=dhall)](https://pkgs.org/search/?q=dhall)) - Beispiel für Raspberry Pi mit Debian Bookworm:

```bash
wget http://ports.ubuntu.com/pool/universe/h/haskell-dhall/dhall_1.32.0-1build1.1_arm64.deb
dpkg -i dhall_1.32.0-1build1.1_arm64.deb
```

Das Folgende Kommando setzt zunächst die Konfigurationsdatei als Variable. Wenn diese Datei erfolgreich geparsed werden konnte, dann formatieren wir diese und überschreiben dann die Originaldatei - beim Scheitern unternehmen wir nichts.

<p class="callout warning">**Warnung:**  
Durch das automatische Formatieren werden alle etwaigen Kommentare entfernt (bekanntes Problem von Dhall, siehe [hier](https://github.com/dhall-lang/dhall-haskell/issues/145)), es sei denn diese werden in als Blockkommentar an den **Anfang** der Datei esetzt ([siehe oben](#bkmrk-kommentare)). Falls der [FabAccess Config Generator](https://docs.fab-access.org/books/fabaccess-konfiguration/page/einfache-konfiguration-mit-dem-fabaccess-config-generator "Einfache Konfiguration mit dem FabAccess Config Generator") genutzt wird, gehen dabei u.a. auch die Anfangs- und End-Tags `--- ||| GENERATOR START` und `--- ||| GENERATOR END` verloren!  
  
Unterreferenzierte Dhall-Dateien werden nicht automatisch mitgeprüft. Eine Rekursion findet also **nicht** statt. D.h. jede Dhall-Datei muss einzeln geprüft/formatiert werden.  
</p>

Wir nutzen folgende Kommandos zum Formatieren:

```bash
CFG="/etc/bffh/bffh.dhall" && \
dhall format < $CFG && \
dhall format < $CFG > $CFG.bup && \
rm $CFG && \
mv $CFG.bup $CFG
```

Es können jedoch auch die offiziellen Flags verwendet werden. Siehe:

```bash
Usage: dhall format [--inplace FILE] [--check]
  Standard code formatter for the Dhall language

Available options:
  --inplace FILE           Modify the specified file in-place
  --check                  Only check if the input is formatted
  -h,--help                Show this help text
```

```bash
#nur formatieren
dhall format --inplace /etc/bffh/bffh.dhall --check

# formatieren und überschreiben
dhall format --inplace /etc/bffh/bffh.dhall
```

<p class="callout info">Siehe auch [Konfiguration von BFFH auf Synax und Inhalt prüfen](#bkmrk-konfiguration-auf-in) für eine BFFH-spezifische Kontrolle der Daten.  
</p>

### Syntax-Highlighting: Dhall-Dateien schöner bearbeiten

Für verschiedene Editoren gibt es Highlighter-Plugins, dabei unter anderem für Vim, VS Code und Emacs. Siehe [hier](https://github.com/dhall-lang/awesome-dhall?tab=readme-ov-file#text-editor-support). Eine Referenz findet sich auch in [https://docs.dhall-lang.org/howtos/Text-Editor-Configuration.html](https://docs.dhall-lang.org/howtos/Text-Editor-Configuration.html).

Für Vim funktioniert das zum Beispiel so:

```bash
curl -fLo ~/.vim/autoload/plug.vim --create-dirs https://raw.githubusercontent.com/junegunn/vim-plug/master/plug.vim
```

```bash
vim ~/.vimrc
```

```ini
call plug#begin()
Plug 'vmchale/dhall-vim'
call plug#end()
```

Beim nächsten Öffnen des Editors führen wir das Kommando `:PlugInstall` aus, installieren damit das Plugin und öffnen dann beliebige Dhall-Dateien und sehen, dass uns Syntax-Highlighting nun zur Verfügung steht.

<p class="callout info">Damit die Datei als Dhall erkannt wird, muss die Dateiendung \*.dhall lauten.</p>

[![grafik.png](https://docs.fab-access.org/uploads/images/gallery/2024-12/scaled-1680-/uuqU8K5FopchuDY7-grafik.png)](https://docs.fab-access.org/uploads/images/gallery/2024-12/uuqU8K5FopchuDY7-grafik.png)  
*Beispiel-Screenshot für Vim*

## Die Konfiguration von BFFH  


Den FabAccess Server zu konfigurieren ist zweifellos eine der wichtigsten Aufgaben und erfordert die Auseinandersetzung mit einigen [Konzepten](https://docs.fab-access.org/books/was-ist-fabaccess-grundkonzepte/chapter/grundkonzepte "Grundkonzepte").

<p class="callout danger">Bei jeder Änderung der Konfigurationsdatei muss BFFH neugestartet werden, um die Änderungen zu übernehmen!</p>

### Übersicht über alle Einstellungen

In der Config gespeichert werden grundlegende, überwiegend **pflichtmäßig** anzugebende Informationen zu ...

- allgemeine Einstellungen (z.B. Interface, Port, Zertifikate, Audit, Datenbank, etc.)  
    
    - [`listens`](#bkmrk-listens)
    - [`db_path`](#bkmrk-db_path-%28string%29)
    - [`certfile`](#bkmrk-certfile%C2%A0%28string%29-un)
    - [`keyfile`](#bkmrk-certfile%C2%A0%28string%29-un)
    - `<a href="#bkmrk-tls_min_version%3A%3Astr">tls_min_version</a>` (optional)
    - [`ciphers`](#bkmrk-ciphers%3A%3Astring-%28opt) (optional)
    - [`mqtt_url`](#bkmrk-mqtt_url)
    - [`auditlog_path`](#bkmrk-auditlog_path-%28strin)
- Rollen, Berechtigungen, Ressourcen (Maschinen) 
    - [`roles`](#bkmrk-roles-1)
    - [`machines`](#bkmrk-machines%3A%3Arecord)
- Aktoren, Initiatoren und ihre Mappings 
    - [`actors`](#bkmrk-actors%3A%3Arecord)
    - [`initiators`](#bkmrk-initiators%C2%A0%28object%29)
    - [`actor_connections`](#bkmrk-actor_connections-1)
    - [`init_connections`](#bkmrk-init_connections-1)
- Föderation &amp; FabFire 
    - [`spacename`](#bkmrk-spacename)
    - [`instanceurl`](#bkmrk-instanceurl)

### Allgemeine Einstellungen

#### `<span class="pre">listens</span>`::List

Enthält eine Liste aus Einträgen mit einer Adresse (`address`::String (notwendig)), auf die BFFH bei der Verbindung für die API hört sowie einer Portangabe (`port`::Integer (optional)). Die Adresse kann eine IPv4, IPv6 oder ein Hostname sein. Wird der Port nicht angegeben, dann wird der Standardport verwendet. Dieser Port lautet für BFFH `<span class="pre">59661</span>` und dabei handelt es sich um einen dynamischen/privaten Port, der auch ohne Root-Zugriff genutzt werden kann (siehe auch "[registrierte Ports](https://www.digitalocean.com/community/tutorials/opening-a-port-on-linux#introduction)").

Es ist möglich mehrere Einträge (verschiedene Adressen und Ports) anzugeben. BFFH versucht alle Verbindungen zu etablieren. BFFH kann also z.B. auch gleichzeitig auf `0.0.0.0:59661` und `0.0.0.0:5961` lauschen.

<p class="callout warning">**Achtung:** Wenn BFFH keinen Port für die angegebene Kombination binden kann, wird ein Fehler protokolliert, aber mit den übrigen Ports fortgefahren.  
</p>

**Beispiele für listens:**

```ini
listens = [
    { address = "127.0.0.1", port = Some 59661 },
    { address = "::1", port = 59661 },
    { address = "steak.fritz.box", port = 59661 } ]
```

<div class="document" id="bkmrk--1" itemscope="itemscope" itemtype="http://schema.org/Article" role="main"><div itemprop="articleBody"><div class="section"><div class="section"><div class="section" id="bkmrk--2"></div></div></div></div></div>#### `<span class="pre">mqtt_url</span>`::String  


Enthält die Adresse des [MQTT](https://docs.fab-access.org/books/awesome-fabinfra/page/glossar-begrifflichkeiten-und-abkurzungen#bkmrk-mqtt)-Servers, mit dem sich BFFH verbindet.

Die Adresse hat das Format `<span class="pre"><protocol>://[user]:[password]@<server>:[port]</span>`

<div class="document" id="bkmrk-protocol-is-required" itemscope="itemscope" itemtype="http://schema.org/Article" role="main"><div itemprop="articleBody"><div class="section"><div class="section"><div class="section">- `<span class="pre">protocol</span>` (notwendig) - kann eins der folgenden Werte annehmen: `<span class="pre">mqtt</span>`,`<span class="pre">tcp</span>`,`<span class="pre">mqtts</span>`,`<span class="pre">ssl</span>`
- `<span class="pre">user</span>` (optional)
- `<span class="pre">password</span>` (optional)
- `<span class="pre">server</span>` (notwendig) - kann IP-Adresse oder Hostname sein
- `<span class="pre">port</span>` (optional) - Der Standardport ist `1883`

</div></div></div></div></div>**Beispiele für mqtt\_url:**

```ini
mqtt_url = "tcp://localhost:1883" 
```

```ini
mqtt_url = "mqtts://user:password@server.tld:port"
```

<p class="callout warning">**Achtung:** Der MQTT-Server muss laufen und erreichbar sein, sonst startet BFFH nicht. Wird die MQTT-Verbindung getrennt, während BFFH läuft, stürzt BFFH nicht ab und protokolliert stattdessen die Verbindungsfehler in die Log-Ausgabe.</p>

#### `certfile`::String und `keyfile`::String


Unsere Kommunikation über [Cap'n Proto](https://docs.fab-access.org/books/was-ist-fabaccess-grundkonzepte/page/capn-proto-api "Cap'n Proto API") erfolgt grundsätzlich verschlüsselt. Dafür benötigen wir ein [TLS](https://docs.fab-access.org/books/awesome-fabinfra/page/glossar-begrifflichkeiten-und-abkurzungen#bkmrk-tls)-Zertifikat. Details, wie man ein TLS-Zertifikat generiert: [Server - Anleitung zum selber kompilieren](https://docs.fab-access.org/books/fabaccess-installation/page/server-anleitung-zum-selber-kompilieren#bkmrk-zertifikat-erzeugen--1 "Server - Anleitung zum selber kompilieren").

BFFH benötigt ein [PEM](https://docs.fab-access.org/books/awesome-fabinfra/page/glossar-begrifflichkeiten-und-abkurzungen#bkmrk-pem-%28privacy-enhance)-kodiertes Zertifikat und den zugehörigen Schlüssel als zwei separate Dateien. BFFH verwendet TLS standardmäßig und ausschließlich in Version [1.2 bzw 1.3](https://docs.rs/rustls/latest/rustls/struct.ConfigBuilder.html#method.with_safe_default_protocol_versions). Dabei implementiert es die Rust-Bibliothek [*rustls*](https://docs.rs/rustls/latest/rustls/) im [Code](https://gitlab.com/fabinfra/fabaccess/bffh/-/blob/development/bffhd/tls.rs?ref_type=heads).

**Beispiel für certfile und keyfile:**

```ini
certfile = "/etc/bffh/certs/bffh.crt"
```

```ini
keyfile = "/etc/bffh/certs/bffh.key"
```

<div class="document" id="bkmrk--3" itemscope="itemscope" itemtype="http://schema.org/Article" role="main"><div itemprop="articleBody"><div class="section"><div class="section"><div class="section" id="bkmrk--4"></div></div></div></div></div>#### `ciphers`::String (optional)

Es kann eine [Cipher Suite](https://docs.fab-access.org/books/awesome-fabinfra/page/glossar-begrifflichkeiten-und-abkurzungen#bkmrk-cipher-suite) vorgegeben werden, die genutzt werden soll.

<p class="callout info">Wir empfehlen diesen Wert nicht zu vergeben und beim Standard zu belassen (standardmäßig wird diese Option in bffh.dhall nicht gesetzt).</p>

<p class="callout warning">Die Definition erfolgt als String, nicht als List und kann deshalb aktuell nur eine einzelne Cipher Suite enthalten. Siehe [Issue 109](https://gitlab.com/fabinfra/fabaccess/bffh/-/issues/109).</p>

**Beispiel für ciphers:**

```ini
ciphers = "TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256"
```

[Mögliche Cipher Suites](https://gitlab.com/fabinfra/fabaccess/bffh/-/blob/development/bffhd/tls.rs?ref_type=heads#L18) sind:

- TLS v1.2 + TLS v1.3 
    - [`TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256`](https://ciphersuite.info/cs/TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256/)
    - [`TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384`](https://ciphersuite.info/cs/TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384/)
    - [`TLS_ECDHE_ECDSA_WITH_CHACHA20_POLY1305_SHA256`](https://ciphersuite.info/cs/TLS_ECDHE_ECDSA_WITH_CHACHA20_POLY1305_SHA256/)
    - [`TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256`](https://ciphersuite.info/cs/TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256/)
    - [`TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384`](https://ciphersuite.info/cs/TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384/)
    - [`TLS_ECDHE_RSA_WITH_CHACHA20_POLY1305_SHA256`](https://ciphersuite.info/cs/TLS_ECDHE_RSA_WITH_CHACHA20_POLY1305_SHA256/)
- TLS v.1.3 only 
    - [`TLS13_AES_128_GCM_SHA256`](https://ciphersuite.info/cs/TLS_AES_128_GCM_SHA256/)
    - [`TLS13_AES_256_GCM_SHA384`](https://ciphersuite.info/cs/TLS_AES_256_GCM_SHA384/)
    - [`TLS13_CHACHA20_POLY1305_SHA256`](https://ciphersuite.info/cs/TLS_CHACHA20_POLY1305_SHA256/)

#### `tls_min_version`::String (optional)

Die [TLS](https://docs.fab-access.org/books/awesome-fabinfra/page/glossar-begrifflichkeiten-und-abkurzungen#bkmrk-tls) Version von BFFH kann erzwungen werden.

<p class="callout info">Wir empfehlen diesen Wert nicht zu vergeben und beim Standard zu belassen (standardmäßig wird diese Option in bffh.dhall nicht gesetzt).</p>

Mögliche Werte:

- `tls12` für TLS v1.2
- `tls13` für TLS v1.3

**Beispiel für tls\_min\_version:**

```ini
tls_min_version = "tls12"
```

#### `<span class="pre">protocols</span>`::List (optional)

Gibt an, welche Protokolle durch BFFH genutzt werden dürfen.

<p class="callout danger">Diese Einstellung kann gesetzt werden, hat aber keine Auswirkungen und wird im Code aktuell nicht genutzt. Sie wird nur zur Vollständigkeit hier gelistet. Es ist nicht bekannt, welche Protokolle unterstützt werden sollen!</p>

**Beispiel für protocols:**

```ini
protocols = ["tcp"],
```

#### `<span class="pre">db_path</span>`::String


Enthält den Pfad für die [interne Datenbank auf LMDB-Basis](https://docs.fab-access.org/books/was-ist-fabaccess-grundkonzepte/page/datenbank-konzept-lmdb "Datenbank-Konzept (LMDB)"), die BFFH verwendet. BFFH wird beim Start zwei Dateien erstellen, falls nicht bereits existent: `/var/lib/bffh/bffh.db` und `/var/lib/bffh/bffh.db-lock`. BFFH erstellt selber keine fehlenden Verzeichnisse. Es sollte sichergestellt werden, dass BFFH Schreibzugriff auf das entsprechende Verzeichnis hat.

Die interne Datenbank wird im Produktivbetrieb nicht riesig (nur einige Kilobyte bis wenige Megabyte). In ihr werden die aktuellen Ressourcenzustände (states) gespeichert (welche Ressource ist z.B. gerade durch einen Nutzer `INUSE`) und welche Nutzer mit Rollen, Passwörtern und Cardkeys zugreifen dürfen. Diese interne Datenbank kann exportiert werden (Benutzerdaten können als `*.toml` Datei ausgegeben werden oder die ganze Datenbank inklusive Zuständen kann exportiert werden). Wir empfehlen die Ablage im Standardverzeichnis `/var/lib/bffh/`.

**Beispiel für db\_path:**

```ini
db_path = "/var/lib/bffh/bffh.db"
```

<div class="document" id="bkmrk--5" itemscope="itemscope" itemtype="http://schema.org/Article" role="main"><div itemprop="articleBody"><div class="section"><div class="section" id="bkmrk--6"><div class="section" id="bkmrk--7"></div></div></div></div></div><p class="callout warning">**BFFH Datenbank "Werkszustand" wiederherstellen:**  
  
Die Datenbankdatei und die Lock-Datei können prinizipiell nach Beenden des Dienstes gelöscht werden, jedoch gehen dabei die gespeicherten aktuellen Ressourcenzustände und Nutzer verloren. Die Nutzer können über eine **aktuelle** `<a href="https://docs.fab-access.org/books/fabaccess-konfiguration/page/benutzerkonfiguration-userstoml" title="Benutzerkonfiguration - users.toml">users.toml</a>` wieder importiert werden. Dass die Ressourcenzustände verloren gehen, ist je nach Werkstattsetup u.U. einfach zu verkraften. Entsprechend kann damit ein Reset durchgeführt werden. Ggf. sollten alte Audit-Einträge (siehe `auditlog_path`) ebenso bereinigt werden.  
</p>

<p class="callout warning">**Vor jedem Update / Recompile unbedingt beachten:** Die Datenbank speichert ihre Daten nicht im Klartext. Die als Datei erzeugte Datenbank `bffh.db` ist abhängig vom System, wo sie angelegt wurde. Jeder Recompile oder Umzug auf einen anderen Host bzw. Architektur macht die Datenbank unbrauchbar. Deshalb muss auch vor jedem Update eine Sicherung erstellt werden, die jedoch re-importiert werden kann.  
  
**Bei Nichtbeachtung droht Verlust der angelegten Benutzerdatenbank und den gespeicherten Ressourcenzuständen.**</p>

<p class="callout info">Die automatisch beim Start erstellte Lock-Datei `/var/lib/bffh/bffh.db-lock` wird nach dem Beenden von BFFH nicht automatisch gelöscht, kann aber manuell immer dann entfernt werden, so lange BFFH nicht läuft. Während des Betriebs sollte die Lock-Datei nicht gelöscht werden, da es sonst zu Korruption in Lese- und Schreibprozessen kommen kann.</p>

#### `auditlog_path`::String


Pfadangabe zur Auditdatei, die BFFH im laufenden Prozess schreibt. Die Ausgabe erfolgt im [JSON](https://docs.fab-access.org/books/awesome-fabinfra/page/glossar-begrifflichkeiten-und-abkurzungen#bkmrk-json-%28javascript-obj)-Format. Siehe [Audit Log (Revisionsprotokoll)](https://docs.fab-access.org/books/was-ist-fabaccess-grundkonzepte/page/audit-log-revisionsprotokoll "Audit Log (Revisionsprotokoll)") für Details zum Audit. Die Datei kann zum Beispiel mit Tools wie [Grafana Loki](https://docs.fab-access.org/books/schnittstellen-und-apis/page/monitoring-prometheus-loki-und-grafana "Monitoring: Prometheus, Loki und Grafana") ausgelesen werden. Wir empfehlen deshalb den Pfad so zu definieren, dass entsprechende Dienste korrekte Leseberechtigungen auf die Datei haben. Der bei Linux-Systemen verwendete Standardpfad for Log-Dateien ist per se `/var/log/`.

**Beispiel für auditlog\_path:**

```ini
auditlog_path = "/var/log/bffh/audit.json"
```

<p class="callout warning">Falls BFFH wegen einem Log-Berechtigungsfehler nicht startet, kann folgender Trick angewendet werden.  
</p>

```bash
Error:
  × audit log failed
  ╰─▶ Permission denied (os error 13)
```

Lösung: die fehlende Datei neu und leer erzeugen und manuell die passende Berechtigungen setzen:

```bash
sudo touch /var/log/bffh/audit.json
sudo chown bffh:root /var/log/bffh/audit.json
sudo chmod 750 /var/log/bffh/audit.json
```

Alternativ kann auch mit `setfacl` eine [ACL](https://docs.fab-access.org/books/awesome-fabinfra/page/glossar-begrifflichkeiten-und-abkurzungen#bkmrk-acl-%28access-control-) angelegt werden. Hierzu gibt es ein nettes Tool unter [https://techgeeks.io/unix/acl-generator](https://techgeeks.io/unix/acl-generator).

```bash
sudo setfacl -R -m u:bffh:rw-,d:u:bffh:rw- /var/log/bffh/audit.json
```

### Konfiguration von Rollen, Berechtigungen und Ressourcen  


FabAccess verwendet eine Role-Based Access Control (RBAC)-Struktur zur Verwaltung von Berechtigungen. Dabei werden Berechtigungen Ressourcenrollen zugewiesen, und diese Rollen werden dann den Benutzern zugewiesen. Auf diese Weise lässt sich ein komplexes Berechtigungssystem einfach, ufassend und flexibel abbilden. Details finden sich unter [RBAC (Benutzerrollen und Berechtigungen)](https://docs.fab-access.org/books/was-ist-fabaccess-grundkonzepte/page/rbac-benutzerrollen-und-berechtigungen "RBAC (Benutzerrollen und Berechtigungen)").

#### `<span class="pre">roles</span>`::Record  


Enthält die Einträge der definierten Rollen. Rollen haben eine Liste von Berechtigungen und können vererbt werden. Die Berechtigung kann ein Platzhalter in der Berechtigungsliste sein. Jede Rolle **muss** eine `Role-ID` haben. Unterhalb des Eintrags `roles` schachteln sich Listen vom Typ `parents`::List (optional) und vom Typ `permissions`::List (notwendig).

#### Standardberechtigungen

BFFH verfügt über einige Standardberechtigungen, die der Verwaltung und den **Admin**-Rechten zugewiesen werden können. Die lauten exakt:

- `bffh.users.info` - Nutzerliste bekommen und Infos über diese Accounts erhalten
- `bffh.users.manage` - Nutzerliste bekommen und Nutzer verwalten
- `bffh.users.admin` - Globale Administration: Nutzer hinzufügen, löschen, ändern (z.B. Passwort-Reset)

**Beispiel für eine Admin-Rolle mit Standardberechtigungen:**

```ini
roles = {
    Admin = {
       permissions =  [
               "bffh.users.manage",
               "bffh.users.info",
               "bffh.users.admin"
             ]
        }
    }
```

#### Modellieren von Berechtigungen für Ressourcen  


**Allgemeines Schema**  
`space.type.category.permission.model`

**Administrator**  
`space.machines.printers.*`

**Offene Berechtigung**  
`space.machines.printers.read.*`

**Allgemeine Erläuterungen zum Pfadformat und Platzhaltern (`*`, `+`)** BFFH verwendet eine pfadähnliche Zeichenkette als Erlaubnisformat, getrennt durch einen `.` Punkt. So besteht zum Beispiel `this.is.a.permission` aus den Teilen `this`, `is`, `a` und `permission`. Bei der Anforderung von Berechtigungen, z. B. in Ressourcen, muss immer eine genaue Berechtigung angegeben werden, also z. B. `test.write`.

Bei der Erteilung von Berechtigungen, z. B. in Rollen, können entweder eine genaue Berechtigung angegeben oder die beiden Platzhalter `*` und `+` verwendet werden. Diese [Wildcards](https://docs.fab-access.org/books/awesome-fabinfra/page/glossar-begrifflichkeiten-und-abkurzungen#bkmrk-wildcard) verhalten sich ähnlich wie Regex- oder Bash-Wildcards:

<div class="document" id="bkmrk-%2A-grants-all-permiss" itemscope="itemscope" itemtype="http://schema.org/Article" role="main"><div itemprop="articleBody"><div class="section"><div class="section">- `*` gewährt alle Berechtigungen in diesem Teilbaum. So wird `perms.read.*` für jedes von passen:  
    
    - `<span class="pre">perms.read</span>`
    - `<span class="pre">perms.read.machineA</span>`
    - `<span class="pre">perms.read.machineB</span>`
    - `<span class="pre">perms.read.machineC.manage</span>`
- `+` gewährt alle Berechtigungen unter des Wertes. So wird `perms.read.+` für jedes von passen:  
    
    - `<span class="pre">perms.read.machineA</span>`
    - `<span class="pre">perms.read.machineB</span>`
    - `<span class="pre">perms.read.machineC.manage</span>`
    - **aber nicht** `<span class="pre">perms.read</span>`

</div></div></div></div>Wildcards sind wahrscheinlich am nützlichsten, um Ressourcen zu gruppieren, z.B. 3D-Drucker und eine Bandsäge:

<div class="document" id="bkmrk-write-permissions-ma" itemscope="itemscope" itemtype="http://schema.org/Article" role="main"><div itemprop="articleBody"><div class="section"><div class="section">1. Write (schreiben) Berechtigungen  
    
    - `<span class="pre">machines.printers.write.prusa.sl1</span>`
    - `<span class="pre">machines.printers.write.prusa.i3</span>`
    - `<span class="pre">machines.printers.write.anycubic</span>`
    - `<span class="pre">machines.bandsaws.write.bandsaw1</span>`
2. Manage (verwalten) Berechtigungen 
    - `<span class="pre">machines.printers.manage.prusa.sl1</span>`
    - `<span class="pre">machines.printers.manage.prusa.i3</span>`
    - `<span class="pre">machines.printers.manage.anycubic</span>`
    - `<span class="pre">machines.bandsaws.manage.bandsaw1</span>`
3. Admin Berechtigungen  
    
    - `<span class="pre">machines.printers</span>`
        - Für alle Drucker
    - `<span class="pre">machines.bandsaws</span>`
        - Für alle Bandsägen

</div></div></div></div>Dann erteilen wir den Rollen die entsprechenden Rechte:

<div class="document" id="bkmrk-use-any-3d-printer%3A-" itemscope="itemscope" itemtype="http://schema.org/Article" role="main"><div itemprop="articleBody"><div class="section"><div class="section">- Nutze beliebige 3D-Drucker: 
    - `<span class="pre">machines.printers.write.+</span>`
- Erlaube nur die Nutzung "billiger" Drucker: 
    - `<span class="pre">machines.printers.write.anycubic.*</span>`
    - `<span class="pre">machines.printers.write.prusa.i3</span>`
- Erlaube das Verwalten der Drucker: 
    - `<span class="pre">machines.printers.+</span>`
- Erlaubte das Administrieren aller Drucker: 
    - `<span class="pre">machines.printers.*</span>`

</div></div></div></div>Auf diese Weise klappt es trotzdem mit der Aufteilung, wenn später ein weitere Anycubic Drucker gekauft wird:

<div class="document" id="bkmrk-machines.printers.wr" itemscope="itemscope" itemtype="http://schema.org/Article" role="main"><div itemprop="articleBody"><div class="section"><div class="section">- `<span class="pre">machines.printers.write.anycubic.i3</span>`
- `<span class="pre">machines.printers.write.anycubic.megax</span>`

</div></div></div></div>**Beispiel für verschiedene Rollen mit Berechtigungen:**

- **Wildcard-Rolle `testrole`**
- **"normale" Rolle `anotherrole`**
- **Rolle `somerole` mit vererbter Rolle `testparent`:**

```ini
roles = {
    testrole = {
        permissions = [ "lab.some.*" ]
        },
    somerole = { 
        parents = [ "testparent" ],
        permissions = [ "lab.some.admin" ]
    }, 
    testparent = {
        permissions = [
            "lab.some.write",
            "lab.some.read",
            "lab.some.disclose" ]
         },
    anotherrole = {
        permissions =  [
            "lab.some.disclose.*",
            "lab.some.read.*",
            "lab.some.write.*" ]
        }
    }
```

<div class="document" id="bkmrk--14" itemscope="itemscope" itemtype="http://schema.org/Article" role="main"><div itemprop="articleBody"><div class="section"><div class="section" id="bkmrk--15"><div class="section" id="bkmrk--16"></div></div></div></div></div>#### `<span class="pre">machines</span>`::Record

<p class="callout info">**Info:** Der Record `machines` wird in Zukunft `resources` heißen!</p>


Enthält die Einträge der definierten Ressourcen. Jede Ressource **muss** eine `Resource-ID` haben, um in anderen Teilen dieser Konfiguration oder über die API auf die Ressource verweisen zu können. Und jede Ressource **muss** einen Namen haben. In FabAccess ist die Ressource ein wichtiger Schlüsselbegriff und steht für Dinge wie Türen, Schließfächer, Geräte oder Maschine. Kurzum: Dinge, die sich ein- und ausschalten lassen sollen.

##### Allgemeine Ressourceninformationen

Um weitere Informationen über die Ressource bereitzustellen, können Namen, Kategorien, Beschreibungen oder ein externer Wiki-Link eingefügt werden:

- `name`::String (notwendig) - ein Klarname, zum Beispiel ein Spitzname für eine Maschine oder eine Modellbezeichnung (Unicode-Support)
- `description`::String (optional) - eine allgemeine, kurze Beschreibung der Ressource (Unicode-Support)
- `wiki`::String (optional) - Link zu einer Wiki- bzw. Dokumentationsseite
- `category`::String (optional) - eine beliebige Kategorie, z.B. "Holzwerkstatt" oder "Handgerät, elektrisch"(Unicode-Support)
- [`prodable`](https://docs.fab-access.org/books/was-ist-fabaccess-grundkonzepte/page/zustande-traits "Zustände (Traits)")::Boolean (optional) - definiert, ob die Ressource ein Türschloss ist - zum Beispiel an einem Werkzeugschrank, Schließfach ode Eingangstür (ab `v0.4.4`). Dieses Attribut schaltet im [Borepin Client](https://docs.fab-access.org/books/fabaccess-konfiguration/page/client-benutzen-und-typische-konfigurationsfehler-bei-server-und-clients#bkmrk-eine-ressource-bedie) zwei Buttons frei, die sonst nicht sichtbar sind:  
    
    - `UNLOCK` öffnet bzw. entsperrt die Ressource, ohne sie für andere zu blockieren und ohne sie zurückgeben zu müssen
    - `IDENTIFY` löst eine einfache Aktion aus wie z.B. das Aufleuchten einer LED an der Ressource, um das Fach bzw. die Ressource optisch leichter zu identifizieren

**Was heißt Unicode-Support?** Durch diese Eigenschaft können wir neben einfachen Bezeichnungen auch beliebige Sonderzeichen einfügen. Das erlaubt unter anderem die Verwendung von Emojis, die innerhalb der Client-Anwendung visuell unterstützen können. Dafür kann ein beliebiger Emoji-Picker genutzt werden, zum Beispiel [https://www.freetool.dev/emoji-picker.](https://www.freetool.dev/emoji-picker) D.h. wir können z.B.  
`description = "Saug dir Energie ;-) 🪫",` konfigurieren. Das sieht dann in Borepin so aus:

[![grafik.png](https://docs.fab-access.org/uploads/images/gallery/2025-01/scaled-1680-/6OU48ttMqxzUuJ9s-grafik.png)](https://docs.fab-access.org/uploads/images/gallery/2025-01/6OU48ttMqxzUuJ9s-grafik.png)

##### Zugewiesene Berechtigungen für Ressourcen  


Die Ressourcen haben verschiedene Berechtigungsstufen, mit denen interagiert werden kann und welche sich in den Records in `roles` wiederspiegeln:

<div class="document" id="bkmrk-disclose%3A%3Astring-%28no" itemscope="itemscope" itemtype="http://schema.org/Article" role="main"><div itemprop="articleBody"><div class="section"><div class="section"><div class="section">- `disclose`::String (notwendig) - Offenlegen: Der Benutzer kann die Ressource in der Übersichtsliste sehen (entdecken), jedoch keine Details zu ihr aufrufen (Detailansicht erfordert `read` Berechtigung)
- `read`::String (notwendig) - Lesen: Der Benutzer kann allgemeine Informationen über die Ressource und ihren Zustand lesen, sowie z.B. den Wiki Link anklicken
- `write`::String (notwendig) - Schreiben: Der Benutzer kann die Ressource bedienen und dabei folgende [Zustände](https://docs.fab-access.org/books/was-ist-fabaccess-grundkonzepte/page/zustande-traits "Zustände (Traits)") verändern: 
    - Benutzen (`InUse`) bzw. Zurückgeben (`Free`, auch als GIVEBACK in der Client App bezeichnet)
    - Reservieren (`Reserve`)
- `manage`::String (notwendig) - Verwalten: Der Benutzer kann als Manager sehen, wer die Maschine aktuell benutzt und wer sie zuletzt benutzt hat. Außerdem können Mananger mit dem System interagieren und dabei folgende [Zustände](https://docs.fab-access.org/books/was-ist-fabaccess-grundkonzepte/page/zustande-traits "Zustände (Traits)") verändern: 
    - Freigeben erzwingen (force `Free`)
    - Blockieren (`Blocked`)
    - Deaktivieren (`Disabled`)
    - Überprüfen (`ToCheck`)
    - Transferieren (`totakeover`)

</div></div></div></div></div><p class="callout info">**Tipp**: Wenn einer Ressource die `read` Berechtigung, aber nicht `disclose` Berechtigung gegeben wird, dann taucht die Ressource nicht in der Übersichtsliste auf. Sie kann auf diese Weise nur noch direkt angesprochen werden, indem ein QR-Code oder ein NFC-Tag gescannt wird. So lässt sich erzwingen, dass ein Nutzer zur Maschine lokal hingehen muss und die Ressource nicht von weiter weg bedienen kann (es sei denn der Benutzer klont den QR-Code oder NFC-Tag und nimmt ihn mit).</p>

**Bitte beachten:**

- Jeder Ressource **müssen alle** Berechtigungsstufen zugewiesen sein.
- Berechtigungsstufen sind nicht additiv, d.h. ein Benutzer mit der Berechtigung `manage` erhält nicht automatisch `read` oder `write` Berechtigung.
- `disclose` ist im Moment **nicht** vollständig implementiert. Benutzer, die keine `disclose` Berechtigung haben, werden in keiner Weise über diese Ressource informiert und sie wird vor ihnen im Client verborgen. Es ist deshalb am sinnvollsten, wenn `read` und `disclose` die gleiche Berechtigung zugewiesen bekommen, zum Beispiel `disclose = "lab.test.read"`.
- Benutzern ohne `read` wird eine Resource mit Namen, Beschreibung, Kategorie und Wiki angezeigt, aber nicht ihr aktueller Zustand. Der aktuelle Benutzer der Ressource wird nicht offengelegt.

**Beispiel einer Ressource mit allen Parametern:**

```ini
machines =  { 
    machine_123 =  { 
        name = "Testmachine",
        description = Some "A test machine",
        wiki = "https://someurl",
        category = "Testzone",
        prodable = True,
        disclose = "lab.some.read",
        read = "lab.some.read",
        write = "lab.some.write",
        manage = "lab.some.admin"
        }
    }
```

Im Beispiel heißt unser `Resource-ID` `machine_123`.

<div class="document" id="bkmrk--10" itemscope="itemscope" itemtype="http://schema.org/Article" role="main"><div itemprop="articleBody"><div class="section"><div class="section" id="bkmrk--11"><div class="section" id="bkmrk--12"><div class="section" id="bkmrk--13"></div></div></div></div></div></div>
### Konfiguration von [Aktoren](https://docs.fab-access.org/books/was-ist-fabaccess-grundkonzepte/page/aktoren-actors-und-initiatoren-initiators "Aktoren (Actors) und Initiatoren (Initiators)") (actors)  


#### `<span class="pre">actors</span>`::Record

Enthält eine Liste von Aktoren. Aktoren werden durch ein Modul `module`::String (notwendig) und einen oder mehrere Parameter `params`::Record definiert. Aktuell **von Haus aus unterstützte Aktoren** (ohne zusätzliche Plugins) sind [Dummy Actor](#bkmrk-dummy-initiator), [Shelly Actor](#bkmrk-shelly-actor-1) und [Process Actor](#bkmrk-process-actor).

Konkret nutzbare Aktoren-Beispiele finden sich [hier](https://docs.fab-access.org/books/plugins-aktoren-initiatoren).

Aktoren werden durch ein Modul und einen oder mehrere Parameter definiert. Die Liste kann bzw. **muss** leer sein, wenn keine Aktoren verwendet werden:

**Beispiel für leere actors:**

```ini
actors = {=}
```

Sonst kann die Liste einen oder mehrere Aktoren mit ihrem Name (`Actor-ID`) enthalten:

##### Dummy Actor

Für Testzwecke kann ein interner Dummy-Initiator genutzt werden. Der „Dummy“-Initiator versucht alle paar Sekunden, einen Rechner als den angegebenen Benutzer zu verwenden und zurückzugeben. Er ist gut geeignet, um das System zu testen, führt aber zu Spam im Log und ist daher standardmäßig deaktiviert.

**Beispiel für Dummy Actor:**

```ini
actors = { 
    Dummy_123 = { 
          module = "Dummy", 
          params = {=}
          } 
    }
```


Im Beispiel heißt unser `Actor-ID` `Dummy_123`.

##### Shelly Actor

Dieser Aktor verbindet BFFH über einen MQTT-Server mit einem Shelly Gerät (dafür wird intern die MQTT-Bibliothek [rumqttc](https://docs.rs/rumqttc/latest/rumqttc/) verwendet). Der Parameter `topic`::String (optional) des Shelly kann auf das Shelly-spezifische MQTT-Topic gesetzt werden. Wird kein `topic` definiert, dann verwendet der Actor automatisch die definierte `Actor-ID`.

[Anleitung zum Auffinden des Shelly Topic](https://shelly-api-docs.shelly.cloud/gen1/#shelly-plug-plugs-overview)

**Beispiel für Shelly Actor:**

```ini
actors = {
    Shelly_123 = { 
        module = "Shelly", 
        params = {
            topic = "shellyplug-s-123456"
            }
        }
    }
```

Im Beispiel heißt unser `Actor-ID` `Shelly_123`.

##### Process Actor

Dieser Aktor ermöglicht es, eigene Prozesse (z.B. Python, Bash, Perl, Java ...) mit dem BFFH Server zu verbinden.

`<span class="pre">cmd</span>`::String (notwendig) - Pfad der ausführbaren Datei  
`<span class="pre">args</span>`::String (optional) - Argumente der ausführbaren Datei. Hier übergebene Argumente werden durch Leerzeichen getrennt, so dass in unserem Beispiel 5 separate Argumente übergeben werden.

**Beispiel für Process Actor:**

```ini
actors = {
    Bash_123 = { 
        module = "Process", 
        params = { 
                cmd = "./examples/actor.sh",
                args = "your ad could be here"
                }
         }
    }
```

Im Beispiel heißt unser `Actor-ID` `Bash_123`.

<p class="callout info">**Wichtige Info:** BFFH baut aus den Argumenten `cmd` und `args` einen vollständigen Befehl, der ausgeführt wird und fügt automatisch zwei weitere Argumente am Ende hinzu - nämlich den zu erzielenden Status `state` (z.B. `INUSE` oder `GIVEBACK`) und den Benutzername `userid`. Der vollständige Befehl, der als Prozess ausgeführt wird, lautet folglich `$ ${cmd} ${args} ${state} ${userid}`.  
</p>

#### `<span class="pre">actor_connections</span>`::List  


Verknüpfung (Mapping) von Ressourcen mit Aktoren. Einer Ressource können mehrere Aktoren zugewiesen werden, aber ein Aktor kann nur einer Ressource zugewiesen werden.

Das Mapping `<span class="pre">actor_connections</span>` wird als Liste von Einträgen gespeichert. Die Parameter:

- `machine`::String (notwendig) - die `Resource-ID`
- `actor`::String (notwendig) - die `Actor-ID`

<p class="callout warning">**Achtung:** Die Reihenfolge ist wichtig. An erster Stelle kommt `machine`, dann `actor`!  
  
Außerdem darf die Definition `actor_connections`::List in `bffh.dhall` erst **nach** `actors`::Record und **nach** `machines`::Record kommen!</p>

**Beispiel für leere actor\_connections:**

```ini
actor_connections = [] : List { machine : Text, initiator : Text },
```

**Beispiel für init\_connections mit drei Mappings:**

```ini
actor_connections = [
    { machine = "Testmachine", actor = "Shelly_123" },
    { machine = "Another", actor = "Bash_123" },
    { machine = "Yetmore", actor = "Bash_234" } ]
```

### Konfiguration von [Initiatoren](https://docs.fab-access.org/books/was-ist-fabaccess-grundkonzepte/page/aktoren-actors-und-initiatoren-initiators "Aktoren (Actors) und Initiatoren (Initiators)") (initiators)

Initiatoren werden fast genauso konfiguriert wie Aktoren. Es gibt aktuell die beiden Initiatorentypen Dummy Initiator und Process Initiator. Konkret nutzbare Initiatoren-Beispiele finden sich [hier](https://docs.fab-access.org/books/plugins-aktoren-initiatoren).

#### `initiators`::Record


Enthält eine Liste von Initiatoren. Initiatoren werden durch ein Modul und einen oder mehrere Parameter definiert. Die Liste kann bzw. **muss** leer sein, wenn keine Initiatoren verwendet werden:

**Beispiel für leere initiators:**

```ini
initiators = {=}
```

Sonst kann die Liste einen oder mehrere Initiatoren mit ihrem Name (`Initiator-ID`) enthalten:

##### Dummy Initiator

**Für Testzwecke kann ein interner Dummy-Initiator genutzt werden:**

Der „Dummy“-Initiator versucht alle paar Sekunden, einen Rechner als den angegebenen Benutzer zu verwenden und zurückzugeben. Er ist gut geeignet, um das System zu testen, führt aber zu Spam im Log und ist daher standardmäßig deaktiviert.

Die Initiator-Parameter:

`<span class="pre">uid</span>`::String (notwendig) - Nutzername

**Beispiel für Dummy Initiator:**

```ini
initiators = { 
   Initiator_123 = { 
          module = "Dummy", 
          params = { 
              uid = "Testuser" 
              } 
          } 
        }
```

##### Process Initiator

Dieser Initiator vom `module`::String Typ **Process** ermöglicht es, eigene Prozesse (z.B. Python, Bash, Perl, Java ...) mit dem BFFH Server zu verbinden.

Das Mapping `<span class="pre">initiator_connections</span>` wird als Liste von Einträgen gespeichert. Die Parameter:

`<span class="pre">cmd</span>`::String (notwendig) - Pfad der ausführbaren Datei  
`<span class="pre">args</span>`::String (optional) - Argumente der ausführbaren Datei. Hier übergebene Argumente werden durch Leerzeichen getrennt, so dass in unserem Beispiel 5 separate Argumente übergeben werden.

**Beispiel für Process Initiator:**

```ini
initiators = {
    Bash_567 = { 
        module = "Process", 
        params = { 
                cmd = "./examples/init.py",
                args = "your ad could be here"
                }
         }
     }
```


Im Beispiel heißt unser `Initiator-ID` `Bash_567`.

<p class="callout info">**Wichtige Info:** BFFH baut aus den Argumenten `cmd` und `args` einen vollständigen Befehl, der ausgeführt wird und fügt automatisch zwei weitere Argumente am Ende hinzu - nämlich den zu erzielenden Status `state` (z.B. `INUSE` oder `GIVEBACK`) und den Benutzername `userid`. Der vollständige Befehl, der als Prozess ausgeführt wird, lautet folglich `$ ${cmd} ${args} ${state} ${userid}`.</p>

#### `init_connections`::List

Verknüpfung (Mapping) von Ressourcen mit Initiatoren. Einer Ressource können mehrere Initiatoren zugewiesen werden, aber ein Initiator kann nur einer Ressource zugewiesen werden.

Das Mapping `<span class="pre">init_connections</span>` wird als Liste von Einträgen gespeichert. Die Parameter:

- `initiator`::String (notwendig) - die `Initiator-ID`
- `actor`::String (notwendig) - die `Actor-ID`

<p class="callout warning">**Achtung:** Die Reihenfolge ist wichtig. An erster Stelle kommt `machine`, dann `initiator`!  
  
Außerdem darf die Definition `init_connections`::List in `bffh.dhall` erst **nach** `initiators`::Record und **nach** `machines`::Record kommen!  
</p>

**Beispiel für leere init\_connections:**

```ini
init_connections = [] : List { machine : Text, initiator : Text }
```

**Beispiel für init\_connections mit einzelnen Mapping:**

```ini
init_connections = [
    { machine = "Testmachine", initiator = "Initiator_123" }
    ]
```

### [FabFire](https://docs.fab-access.org/books/fabfire-und-nfc-tags "NFC Key Cards und Transponder (FabCard / FabFire)") und Föderation

#### `spacename`::String

Der Name des Spaces (die offene Werkstatt, das FabLab, der HackerSpace, etc.) wird im [URN](https://docs.fab-access.org/books/was-ist-fabaccess-grundkonzepte/page/url-und-urn "URL und URN")-Schema `urn:fabaccess:lab:{spacename}` verwendet. Wird er nicht definiert, wird der Wert "generic" vergeben. Diese Angaben benötigen wir für [QR-Codes](https://docs.fab-access.org/books/beschriftungen-und-sticker/page/fabaccess-sticker-aufkleber "FabAccess Sticker (Aufkleber)") von Ressourcen oder für DESFire Karten zur Nutzung von [FabFire](https://docs.fab-access.org/books/fabfire-und-nfc-tags "NFC Key Cards und Transponder (FabCard / FabFire)").

**Beispiel für spacename:**

```ini
spacename = "FabAccess DemoSpace"
```

#### `instanceurl`::String

Wird für eine allgemeine Space Info genutzt und als [URN](https://docs.fab-access.org/books/was-ist-fabaccess-grundkonzepte/page/url-und-urn) im Code genutzt: `urn:fabaccess:lab:{spacename}\x00{instanceurl}`. Dieser Wert wird aktuell nicht verwendet, muss jedoch ausgefüllt werden, damit die Konfiguration `bffh.dhall` valide ist! Es wird empfohlen die URL mit dem Protokoll vollständig anzugeben, also mit `http://` oder `https://`.

**Beispiel für instanceurl:**

```ini
instanceurl = "https://demo.fab-access.org"
```

### Hinweise zu unkonfigurierbaren Variablen

Folgende Variablen werden intern von BFFH gesetzt und können aktuell nicht über die bffh.dhall verändert werden. Wir führen sie nur zur Vollständigkeit auf:

- `verbosity`
- `filter`
- `format`

### Hinweise zur Vergabe von IDs

Wir verwenden in der Konfiguration IDs wie `Resource-ID`, `Actor-ID`, `Initiator-ID` oder `Role-ID`.

Diese IDs müssen folgendes Namensschema einhalten:

- ASCII Format
- Alphanumerisch
- muss mit einem Buchstaben beginnen

<p class="callout info">Für die Vergabe von IDs ist die Groß- und Kleinschreibung zu beachten! Wir empfehlen generell die Kleinschreibung. So ist zum Beispiel eine Rolle namens `RoleAdmin` ungleich `roleadmin`.  
Wir empfehlens außerdem ein konsisentes, leicht nachvollziehbares (logisches) Namenskonzept über alle ID-Typen, wo immer es möglich ist.  
</p>

<p class="callout danger">IDs müssen eindeutig bzw. einzigartig sein. IDs dürfen also nicht doppelt vergeben werden!</p>

### Minimal funktionierende Standardkonfiguration

Wie bereits eingangs erwähnt, werden [alle obigen Einstellungen](#bkmrk-%C3%9Cbersicht-%C3%BCber-alle-) für die Konfiguration benötigt. Für die absolut minimale Startfähigkeit eines BFFH Servers kann folgendes Konfigurationssample verwendet werden.

Vorraussetzungen für die Lauffähigkeit von BFFH:

- Dienst muss sich auf Interface:Port binden lassen
- MQTT-Server muss laufen und erreichbar sein (siehe [mqtt\_url::String](#bkmrk-mqtt_url)).
- Zertifikat und Keyfile müssen existieren
- Datenbankdatei und Auditlog müssen schreibbar sein

```ini
{
spacename = "fabaccess.sample.space",
instanceurl = "https://fabaccess.sample.space", 
listens = [{address = "127.0.0.1"}],
certfile = "/etc/bffh/certs/bffh.crt",
keyfile = "/etc/bffh/certs/bffh.key",
mqtt_url = "mqtt://127.0.0.1:1883",
db_path = "/var/lib/bffh/bffh.db",
auditlog_path = "/var/log/bffh/audit.json", 
roles = {=},
machines = {=},
actors = {=},
actor_connections = [] : List { machine : Text, initiator : Text },
initiators = {=},
init_connections = [] : List { machine : Text, initiator : Text }
}
```

Ein ebenso funktionales und umfangreicheres Standardsample kann auch per `bffhd --print-default` ausgegeben werden (siehe [Cheat Sheet](https://docs.fab-access.org/books/fabaccess-konfiguration/page/cheat-sheet-wichtigste-befehle-ubersicht "Cheat Sheet - Wichtigste Befehle (Übersicht)")).

### Konfiguration per Config Generator

Ein Großteil der Konfiguration (Ressourcen, Berechtigungen, Aktoren, Aktorenverbindungen, etc.) kann mit einem generischen Arbeitswerkzeug effizient und übersichtlich erzeugt und verwaltet werden. Siehe [Einfache Konfiguration mit dem FabAccess Config Generator](https://docs.fab-access.org/books/fabaccess-konfiguration/page/einfache-konfiguration-mit-dem-fabaccess-config-generator "Einfache Konfiguration mit dem FabAccess Config Generator").

### Konfiguration von BFFH auf Synax und Inhalt prüfen

Konfiguration erstellt, aber unsicher, ob sie vollständig und syntaktisch korrekt ist?

Wir können das per `/usr/bin/bffhd --check --config /etc/bffh/bffh.dhall` überprüfen. Siehe [hier](https://docs.fab-access.org/books/fabaccess-konfiguration/page/cheat-sheet-wichtigste-befehle-ubersicht#bkmrk-konfigurationsdatei-). Das Kommando kann mit dem `--check` Parameter unabhängig und vor dem Neustart von BFFH ausgeführt werden und verhindert so die Unverfügbarkeit des Service bei Fehlkonfiguration (alternativ kann auch ein Staging-System für derartige Tests angelegt werden). Etwaige Fehlkonfigurationen werden auch erkannt, da geprüft wird, ob wichtige Konfigurationschlüssel fehlen, unvollständig oder falsch sind.

<p class="callout info">Siehe auch [Dhall-Dateien parsen, prüfen und formatieren](#bkmrk-dhall-dateien-parsen) für die reine Überprüfung des Syntax und das automatische Umformatieren (Prettyprint).</p>

Ein letzter Blick in die von BFFH geladene Config kann auch über unsere systemd Journaleinträge gemacht werden, falls wir [BFFH als Service installiert](https://docs.fab-access.org/books/fabaccess-installation/page/server-anleitung-zum-selber-kompilieren#bkmrk-systemd-service-anle) haben, oder aber über über die Log-Umgebungsvariable `BFFH_LOG`. Wir sehen damit, wie BFFH die Dhall nach dem Parsen vollständig auflöst und dass Log-Variablen beispielsweise auch gesetzt werden, welche jedoch nicht über `bffh.dhall` konfigurierbar sind, sondern über [Umgebungsvariablen](https://docs.fab-access.org/books/fabaccess-konfiguration/page/server-logs-konfigurieren-und-debugging "Server Logs konfigurieren").

```bash
sudo systemctl restart bffh.service; sudo journalctl -n2000 -e -u bffh.service
```

```bash
Jan 02 22:31:07 fabaccess systemd[1]: Starting bffh.service - FabAccess BFFH Service...
Jan 02 22:31:07 fabaccess bffhd[34844]: Config {
Jan 02 22:31:07 fabaccess bffhd[34844]:     listens: [
Jan 02 22:31:07 fabaccess bffhd[34844]:         Listen {
Jan 02 22:31:07 fabaccess bffhd[34844]:             address: "0.0.0.0",
Jan 02 22:31:07 fabaccess bffhd[34844]:             port: Some(
Jan 02 22:31:07 fabaccess bffhd[34844]:                 59661,
Jan 02 22:31:07 fabaccess bffhd[34844]:             ),
Jan 02 22:31:07 fabaccess bffhd[34844]:         },
Jan 02 22:31:07 fabaccess bffhd[34844]:     ],
Jan 02 22:31:07 fabaccess bffhd[34844]:     machines: {},
Jan 02 22:31:07 fabaccess bffhd[34844]:     actors: {},
Jan 02 22:31:07 fabaccess bffhd[34844]:     initiators: {},
Jan 02 22:31:07 fabaccess bffhd[34844]:     mqtt_url: "mqtt://fabinfra101:fablocal@0.0.0.0:1883",
Jan 02 22:31:07 fabaccess bffhd[34844]:     actor_connections: [],
Jan 02 22:31:07 fabaccess bffhd[34844]:     init_connections: [],
Jan 02 22:31:07 fabaccess bffhd[34844]:     db_path: "/var/lib/bffh/bffh.db",
Jan 02 22:31:07 fabaccess bffhd[34844]:     auditlog_path: "/var/log/bffh/audit.json",
Jan 02 22:31:07 fabaccess bffhd[34844]:     roles: {},
Jan 02 22:31:07 fabaccess bffhd[34844]:     tlsconfig: TlsListen {
Jan 02 22:31:07 fabaccess bffhd[34844]:         certfile: "/etc/bffh/certs/bffh.crt",
Jan 02 22:31:07 fabaccess bffhd[34844]:         keyfile: "/etc/bffh/certs/bffh.key",
Jan 02 22:31:07 fabaccess bffhd[34844]:         ciphers: None,
Jan 02 22:31:07 fabaccess bffhd[34844]:         tls_min_version: None,
Jan 02 22:31:07 fabaccess bffhd[34844]:         protocols: [],
Jan 02 22:31:07 fabaccess bffhd[34844]:     },
Jan 02 22:31:07 fabaccess bffhd[34844]:     tlskeylog: None,
Jan 02 22:31:07 fabaccess bffhd[34844]:     verbosity: 0,
Jan 02 22:31:07 fabaccess bffhd[34844]:     logging: LogConfig {
Jan 02 22:31:07 fabaccess bffhd[34844]:         filter: None,
Jan 02 22:31:07 fabaccess bffhd[34844]:         format: "full",
Jan 02 22:31:07 fabaccess bffhd[34844]:     },
Jan 02 22:31:07 fabaccess bffhd[34844]:     spacename: "FabAccess Demo Setup",
Jan 02 22:31:07 fabaccess bffhd[34844]:     instanceurl: "https://docs.fab-access.org",
Jan 02 22:31:07 fabaccess bffhd[34844]: }
Jan 02 22:31:07 fabaccess systemd[1]: Started bffh.service - FabAccess BFFH Service.
```