# Salt API

### API installieren

```
yum install salt-api      # RedHat,CentOS
apt-get install salt-api  # Debian, Ubuntu
```

#### Konfiguration

{% hint style="warning" %}
Die nachfolgend verwendete PAM-Autentifizierung verlangt, dass der Salt-Master Leserechte für die Dateien`/etc/shadow` und `/etc/gshadow` besitzt.

Seit Version 3006 wird der Salt-Master nicht mehr mit Root-User ausgeführt.&#x20;

Auf Debian und Ubuntu fügen Sie den `salt` User zur Gruppe `shadow` hinzu, um die Leseberechtigung zu erreichen.

`usermod -a -G shadow salt`
{% endhint %}

Um die API zu aktivieren, fügen Sie die folgenden Zeilen in eine neue Datei `/etc/salt/master.d/api.conf` ein:

{% code title="/etc/salt/master.d/api.conf" %}

```yaml
external_auth:
  pam:
    salt-api:
      - .*
      - '@wheel'
      - '@runner'

rest_cherrypy:
  host: 127.0.0.1 # omit to listen on all IPs
  port: 8000
  disable_ssl: true
  debug: true
  
netapi_enable_clients: [local]
```

{% endcode %}

Starten Sie nach der Änderung der Konfiguration den Salt-Master und die API neu.

```
service salt-master restart
service salt-api restart
```

Es können weitreichende Einschränkungen pro User konfiguriert werden, um nicht alle Funktionen und alle Minions über die API verfügbar zu machen. [Siehe offizielle Dokumentation](https://docs.saltstack.com/en/latest/topics/eauth/index.html).

{% hint style="danger" %}
Dieses einfache Beispiel sollten Sie nicht in den produktiven Betrieb übernehmen. \
Die API verwendet kein SSL (HTTPS) und der Benutzer hat uneingeschränkte Rechte.
{% endhint %}

#### Einen Benutzer anlegen

```
useradd -m -d /var/lib/salt-api -r -s /usr/sbin/nologin salt-api
passwd salt-api # 123ab
```

#### Zugriffe auf Key-Verwaltung beschränken

```yaml
external_auth:
  pam:
    salt-api:
      - '@wheel':
        - keys*
```

#### API Zugriffe auf Minions und Funktionen beschränken

```yaml
external_auth:
  pam:
    salt-api:
      - 'ubuntu*':        # Limit to Minions
        - test.ping       # Limit to a function
```

### Testen <a href="#testen" id="testen"></a>

#### Erster Test

```bash
curl -s http://salt:8000/login \
    -H 'Accept: application/x-yaml' \
    -d username=salt-api \
    -d password=123ab \
    -d eauth=pam
```

Anmelden und API Token holen

```bash
curl -s http://salt:8000/login \
    -H 'Accept: application/x-yaml' \
    -d username=salt-api \
    -d password=123ab \
    -d eauth=pam|grep token|awk '{print $2}'>/tmp/token
```

Eine Anfrage stellen, z.B. `salt '*' test.ping` über die API auslösen.

```bash
curl -s http://salt:8000 \
    -H 'Accept: application/x-yaml' \
    -H "X-Auth-Token: $(cat /tmp/token)"\
    -d client=local \
    -d tgt='*' \
    -d fun=test.ping
```

Als Rückgabeformat kann auch JSON gewählt werden.

```bash
$ curl -s http://salt:8000 \
    -H 'Accept: application/json' \
    -H "X-Auth-Token: $(cat /tmp/token)"\
    -d client=local \
    -d tgt='*' \
    -d fun=test.ping|jq
{
  "return": [
    {
      "rachel": true,
      "sara": true,
      "loadbalancer": true,
      "susan": true,
      "ruby": true
    }
  ]
}
```

API Anfragen können auch ohne Token an den `/run` Endpunkt gesendet werden. Benutzername, Password und Authentifizierungsmethode müssen dann im Body enthalten sein.

```bash
curl -s http://salt:8000/run \
    -H 'Accept: application/x-yaml'\
    -d username=salt-api \
    -d password=123ab \
    -d eauth=pam \
    -d client=local\
    -d tgt='*' \
    -d fun="test.ping"
```

Ein simples Python-Beispiel

```python
#!/usr/bin/env python3

#
# a simple request to the salt API
#
import requests

headers = {"Accept": "application/json"}

payload = {
        "client": "local",
        "tgt": '*',
        "username": 'salt-api',
        "password": '123ab',
        "eauth": "pam",
        "fun": "test.ping" 
        }
r = requests.post('http://127.0.0.1:8000/run', headers=headers, json=payload)
print(r.text)
```

### State.apply per API durchführen <a href="#stateapply-per-api-durchfuehren" id="stateapply-per-api-durchfuehren"></a>

```bash
curl -sSk http://salt:8000 \
    -H 'Accept: application/x-yaml'\
    -H "X-Auth-Token: $(cat /tmp/token)"\
    -d client=local\
    -d tgt='*' \
    -d fun="state.apply" \
    -d arg="test" \
    -d arg="timeout=20"
```

{% hint style="warning" %}
Beding durch einen [Fehler](https://github.com/saltstack/salt/issues/62624), erwartet die API `arg` immer als Liste. Sie müssen mindestens zwei Argumente `arg="X" angeben,` wenn die Funktion mit Argumenten ergänzt werden soll. Geben Sie beispielsweise den Timeout an, obwohl dies nicht zwingend notwendig ist.

Alternativ formatieren Sie `arg` als Liste, z. B. `-d '["arg=test"]'.`
{% endhint %}

### Asynchrone Requests durchführen

Egal, ob Sie einen Salt »Befehl« über die Kommandozeile oder die API durchführen, ja nach Anzahl der adressierten Minions und der verwendeten Module oder States kann der Lauf sehr lange dauern. Wenn Sie eigene Applikationen auf Basis der API entwickeln, müssen HTTP Clients u.U. sehr lange auf eine Antwort warten. Ein asynchrones Ausführen ist oft ratsamer. Die API beendet die HTTP Anfrage sofort und gibt eine Job-ID zurück. Die Jobs laufen dann im Hintergrund. Anschließend kann man periodisch im Job-Cache nachschauen, welcher Minion den Job bereits abgearbeitet hat und mit welchem Ergebnis.

```bash
curl -sSk http://salt:8000 \
    -H "Accept: application/x-yaml" \
    -H "X-Auth-Token: $(cat /tmp/token)"\
    -d tgt='*' \
    -d fun=test.ping \
    -d client=local_async
```

```bash
curl -sSk http://salt:8000/jobs/<JOBID>\
    -H "Accept: application/x-yaml" \
    -H "X-Auth-Token: $(cat /tmp/token)"
```

Wenn Sie einen [MySQL-Jobcache](https://thorstenkramm.gitbook.io/saltstack/returner#mysql-master-returner) aktiviert haben, können Sie das Ergebnis eines asynchronen Jobs auch aus der Datenbank lesen.

```
mysql> select `id`,`return` from salt_returns where jid="20190826163228330773";
+----+--------+
| id | return |
+----+--------+
| u1 | true   |
| u2 | true   |
| u3 | true   |
| u4 | true   |
+----+--------+
4 rows in set (0.00 sec)
```

### Pillars per API schreiben

```bash
curl -sS http://salt:8000 \
  -H "Accept: application/x-yaml" \
  -H "X-Auth-Token: $(cat /tmp/token)" \
  -d fun=pillar_roots.write \
  -d client=wheel \
  -d path=new_file.sls -d data='
stuff:
   goes:
     here: True
'
```

{% hint style="danger" %}
Wenn ein API-User uneingeschränkte `@wheel` Rechte hat, kann er die **vollständige Kontrolle über das Betriebssystem** übernehmen.

Die Funktionen `pillar_roots.read` und `pillar_roots.write`können auf das **komplette Dateisystem zugreifen. Lesend und schreibend!**

`curl -sS http://salt:8000 -H "Accept: application/x-yaml" -H "X-Auth-Token: $(cat /tmp/token)" -d fun=pillar_roots.read -d client=wheel -d path=../../etc/passwd`
{% endhint %}

### Einen neuen Minion registrieren <a href="#einen-neuen-minion-registrieren" id="einen-neuen-minion-registrieren"></a>

Prüfen, ob für einen Minion schon Zertifikate generiert wurden:

```bash
curl -sSk http://salt:8000/keys \
    -H 'Accept: application/x-yaml' \
    -H "X-Auth-Token: $(cat /tmp/token)"
```

Wenn kein Zertifikat vorhanden, ein neues generieren und downloaden. Der Download besteht aus einem Tar-File, in welchem minion-Key und Minion-Zerifikat enthalten sind.

```bash
curl -sSk http://salt:8000/keys \
        -d mid=$(cat /etc/salt/minion_id) \
        -d username=salt-api \
        -d password=123ab \
        -d eauth=pam \
        | tar -C /etc/salt/pki/minion -xmf -
```

### Beispiel Systeme beim Hochfahren automatisch registrieren <a href="#beispiel-systeme-beim-hochfahren-registrieren" id="beispiel-systeme-beim-hochfahren-registrieren"></a>

{% code lineNumbers="true" %}

```bash
lxc launch images:debian/11 doreen
lxc exec doreen bash<<"EOF"
set -e
apt-get -y install curl
curl -LSs https://bootstrap.saltproject.io/ -o install_salt.sh
sh install_salt.sh -x python3 -X
service salt-minion stop
echo "10.27.119.1 salt">>/etc/hosts
curl -fs http://salt:8000/keys \
  -d mid=$(cat /etc/salt/minion_id) \
  -d username=salt-api \
  -d password=123ab \
  -d eauth=pam \
  | tar -vC /etc/salt/pki/minion -xmf -
cat /etc/salt/pki/minion/minion.pem
cat /etc/salt/pki/minion/minion.pub
service salt-minion start
service salt-minion status
EOF
```

{% endcode %}

{% hint style="info" %}
Achten Sie darauf, dass die Salt-API im Netzwerk lauscht und nicht nur auf `localhost`.

Passen Sie ggf. die Datei `/etc/salt/master.d/api.conf` an und starten Sie die API mit `service salt-api restart` neu.
{% endhint %}

Link zur [offiziellen Dokumentation](https://docs.saltproject.io/en/latest/ref/netapi/all/salt.netapi.rest_cherrypy.html) der Salt-API.
