
# OpenTofu- und Terraform-Provider

Der Provider `keenauth/keenauth` verwaltet die Konfiguration einer KeenAuth-Umgebung als Code. Er ruft die Management-API auf, spricht Plugin-Protokoll 6 und funktioniert mit OpenTofu und Terraform. Er ist noch nicht in einer Provider-Registry veröffentlicht.

## Authentifizierung und Ziel

Der Provider verwaltet die Umgebung, zu der sein Berechtigungsnachweis gehört. Um mehrere Umgebungen zu verwalten, konfigurieren Sie je Umgebung einen eigenen Provider-Alias. Er authentifiziert sich auf genau eine von zwei Arten: mit einem Management-API-Schlüssel oder schlüssellos als `management`-Anwendung mit `private_key_jwt`. Beides gleichzeitig zu setzen ist ein Fehler.

| Einstellung | Umgebungsvariable | Beschreibung |
|---|---|---|
| `api_key` | `KEENAUTH_API_KEY` | Management-API-Schlüssel. Verwenden Sie bevorzugt die Umgebungsvariable. Der Schlüssel wird nie in Zustands- oder Plandateien geschrieben. |
| `client_id` | `KEENAUTH_CLIENT_ID` | ID (`app_…`) einer `management`-Anwendung, anstelle von `api_key`. Benötigt `private_key` und `issuer`. |
| `private_key` | `KEENAUTH_PRIVATE_KEY` | PEM-PKCS#8-Privatschlüssel, dessen öffentlicher Schlüssel bei der Anwendung registriert ist: EC P-256, EC P-384, Ed25519 oder RSA mit mindestens 2048 Bit. Verwenden Sie bevorzugt die Umgebungsvariable. Wird nie im Zustand gespeichert. |
| `private_key_algorithm` | | `PS256` (Standard) oder `RS256`, nur für einen RSA-Schlüssel. |
| `issuer` | `KEENAUTH_ISSUER` | Der Standard-Host der Umgebung, `https://<environment>.<region>.keenauth.app`. Der Provider holt sein Token von `<issuer>/oauth2/token`. |
| `scopes` | | Berechtigungen, die mit `client_id` angefordert werden. Wenn nicht angegeben, gelten die Standard-Scopes der Freigabe. |
| `region` | `KEENAUTH_REGION` | `eu` (Standard) oder `us`. Die API-Adresse lautet `https://api.eu.keenauth.com/v1` bzw. `https://api.us.keenauth.com/v1`. |
| `base_url` | `KEENAUTH_BASE_URL` | Explizite API-Adresse. Akzeptiert wird nur `https://<host>.keenauth.com/v1`, zusätzlich Loopback-Adressen für lokale Tests. |

```terraform
terraform {
  required_providers {
    keenauth = { source = "keenauth/keenauth" }
  }
}

provider "keenauth" {
  region = "eu"
}
```

### Schlüssellose Authentifizierung mit `private_key_jwt`

1. Erstellen Sie eine Anwendung mit `app_type = "management"` und einem Datensatz `keenauth_management_client` mit den Berechtigungen, die die Konfiguration benötigt.
2. Registrieren Sie den öffentlichen Schlüssel eines Schlüsselpaars bei der Anwendung (`POST /v1/applications/{application_id}/credentials` mit `type: public_key`, über die CLI oder das Dashboard).
3. Übergeben Sie dem Provider die Anwendungs-ID, den Privatschlüssel und den Issuer:

```shell
export KEENAUTH_CLIENT_ID="app_..."
export KEENAUTH_PRIVATE_KEY="$(cat ops-automation.pk8.pem)"
export KEENAUTH_ISSUER="https://acme.eu.keenauth.app"
tofu plan
```

Für jedes Management-Token signiert der Provider eine Client-Assertion (RFC 7523), die 60 Sekunden gültig ist: `iss` und `sub` sind die Client-ID, `aud` ist der Issuer, `jti` ist zufällig und `kid` ist der RFC-7638-Thumbprint des Schlüssels. Die Assertion wird mit der Freigabe `client_credentials` gegen ein Token mit 10 Minuten Gültigkeit getauscht, und eine Minute vor Ablauf des alten Tokens wird ein neues geholt. Das Token kann nie mehr Berechtigungen haben als der Datensatz `keenauth_management_client` der Anwendung. Endpunkte, die nur einen API-Schlüssel akzeptieren, etwa Management-Clients, benötigen einen Provider-Alias, der mit `api_key` konfiguriert ist.

## Ressourcen

| Name | Art | Was verwaltet wird |
|---|---|---|
| `keenauth_application` | Ressource | Eine Anwendung (OAuth-2.0- / OpenID-Connect-Client). |
| `keenauth_connection` | Ressource | Eine Anmeldeverbindung: Datenbank, passwortlos, Passkey, Social oder Enterprise. |
| [`keenauth_connection_oidc_config`](/docs/terraform/connection-oidc-config) | Ressource | Die Relying-Party-Konfiguration einer Enterprise-OIDC-Verbindung mit einem nur schreibbaren Client-Secret (OpenTofu oder Terraform 1.11+). Import mit der Verbindungs-ID. Das Zerstören entfernt sie nur aus dem Zustand. |
| [`keenauth_environment_settings`](/docs/terraform/environment-settings) | Ressource | Umgebungseinstellungen: Sprachen, Sitzungen, Registrierung, Benachrichtigungen, Wiederherstellung, MFA, Erstfaktoren. Eine pro Umgebung. |
| [`keenauth_attack_protection`](/docs/terraform/attack-protection) | Ressource | Angriffsschutz: Brute Force, IP-Drosselung, Credential Stuffing, Bots, kompromittierte Passwörter, Registrierung, SMS-Betrug, Risikorichtlinie. Eine pro Umgebung. |
| [`keenauth_branding`](/docs/terraform/branding) | Ressource | Das Umgebungsdesign des Branding-Entwurfs. Eines pro Umgebung. |
| [`keenauth_custom_domain`](/docs/terraform/custom-domain) | Ressource | Eine eigene Anmeldedomain. |
| [`keenauth_api_key`](/docs/terraform/api-key) | Ressource | Ein Management-API-Schlüssel: nur Import; Zerstören widerruft ihn. |
| `keenauth_organization` | Ressource | Eine B2B-Organisation: Name, Slug, externe ID, Metadaten, Markenfarbe und Mitgliedergrenze. Zerstören löscht sie sofort; Statusaktionen (deaktivieren, aktivieren, Löschung abbrechen) bleiben in der CLI und im Dashboard. |
| `keenauth_organization_role` | Ressource | Eine organisationsspezifische Rolle und ihr Berechtigungssatz (Business-Tarif). Import mit `<org_id>/<key>`. |
| [`keenauth_permission`](/docs/terraform/permission) | Ressource | Eine Berechtigung (OAuth-Scope) einer API mit ihren Texten auf dem Zustimmungsbildschirm. Import mit `<api_id>/<value>`. |
| [`keenauth_role`](/docs/terraform/role) | Ressource | Eine Umgebungsrolle und ihr vollständiger Berechtigungssatz. Benutzer- und Mitgliedszuweisungen sind keine Ressourcen. |
| [`keenauth_organization_domain`](/docs/terraform/organization-domain) | Ressource | Eine Domain einer Organisation für Domain-Capture und SSO-Routing. Die Verifizierung bleibt eine Aktion. |
| [`keenauth_session_policy`](/docs/terraform/organization-policies) | Ressource | Die Sitzungslaufzeiten einer Organisation; nur strenger als die Umgebung (Enterprise-Tarif). |
| [`keenauth_mfa_policy`](/docs/terraform/organization-policies) | Ressource | Die MFA-Regeln einer Organisation; nur strenger als die Umgebung. |
| [`keenauth_email_template`](/docs/terraform/email-template) | Ressource | Der veröffentlichte Inhalt einer E-Mail-Vorlage (Familie und Sprache); Startup-Tarif. Import mit `<family>/<locale>`. Das Zerstören entfernt sie nur aus dem Zustand. |
| [`keenauth_management_client`](/docs/terraform/management-client) | Ressource | Die Management-API-Berechtigungen und IP-Allowlist einer `management`-Anwendung. Import mit der Anwendungs-ID. |
| [`keenauth_directory`](/docs/terraform/directory) | Ressource | Ein SCIM-Verzeichnis einer Organisation und seine Provisionierungseinstellungen; `name` und Einstellungen werden direkt geändert, `organization_id`, `scim_host` und `type` ersetzen es. Import mit der Verzeichnis-ID. |
| [`keenauth_directory_role_mapping`](/docs/terraform/directory-role-mapping) | Ressource | Ordnet eine SCIM-Verzeichnisgruppe einer Rolle zu; jede Änderung ersetzt sie. Import mit `<directory_id>/<mapping_id>`. |
| [`keenauth_directory_token`](/docs/terraform/directory-token) | Ressource | Ein SCIM-Token eines Verzeichnisses, im Zustand nur verschlüsselt mit Ihrem öffentlichen RSA-Schlüssel gespeichert; jede Änderung erzeugt ein neues Token, Zerstören widerruft es. Nicht importierbar. |
| [`keenauth_webhook_endpoint`](/docs/terraform/webhook-endpoint) | Ressource | Ein Webhook-Endpunkt; jedes Argument wird direkt geändert. Das Signiergeheimnis wird im Zustand nur verschlüsselt mit Ihrem öffentlichen RSA-Schlüssel gespeichert; Änderung des Schlüssels oder von `rotation_trigger` rotiert es. Import mit der Endpunkt-ID oder dem Key. |
| `keenauth_application` | Datenquelle | Liest eine Anwendung über `id` oder `key`. |
| `keenauth_connection` | Datenquelle | Liest eine Verbindung über `id` oder `key`. |
| `keenauth_organization` | Datenquelle | Liest eine Organisation über `id` oder `slug`. |
| [`keenauth_role`](/docs/terraform/role) | Datenquelle | Liest eine Umgebungsrolle über `id` oder `key`. |
| `keenauth_environment` | Datenquelle | Liest die Umgebung des API-Schlüssels: ID, Typ, Region, Cell, Status und Tarif. |

```terraform
resource "keenauth_connection" "google" {
  key      = "google"
  type     = "social"
  strategy = "google"
  name     = "google"
  status   = "active"
  settings = jsonencode({ scopes = ["openid", "email", "profile"] })
}

resource "keenauth_application" "storefront" {
  key            = "storefront"
  name           = "Storefront"
  app_type       = "web"
  party          = "first_party"
  redirect_uris  = ["https://shop.example.com/callback"]
  connection_ids = [keenauth_connection.google.id]
}
```

## Import

Anwendungen und Verbindungen können über ihren `key` oder ihre ID importiert werden, eine eigene Domain über ihren Hostnamen oder ihre ID und ein API-Schlüssel über seine ID:

```shell
tofu import keenauth_application.storefront storefront
tofu import keenauth_connection.google conn_01j9zq3v8c5m2x7k4t6r1n0b3d
tofu import keenauth_custom_domain.login login.example.com
```

Die Umgebungseinstellungen, der Angriffsschutz und der Branding-Entwurf existieren je Umgebung einmal; importieren Sie sie mit den festen IDs `environment-settings`, `attack-protection` und `branding`. Das Zerstören eines davon entfernt es nur aus dem Zustand.

## Sichere Änderungen

- Ein Create sendet einen `Idempotency-Key`, sodass ein wiederholtes Create nie ein zweites Objekt erzeugt.
- Ein Update oder Delete sendet `If-Match` mit dem zuletzt gelesenen ETag. Hat jemand das Objekt geändert, nachdem der Plan erstellt wurde, antwortet die API mit `412` und nichts ändert sich. Führen Sie `plan` erneut aus.
- Eine Änderung im Dashboard erscheint beim nächsten `plan` als Drift, und `apply` setzt sie zurück. Ein außerhalb des Providers gelöschtes Objekt wird aus dem Zustand entfernt und neu erstellt.
- Ein Update sendet nur die geänderten Felder als JSON Merge Patch (RFC 7396).

## Geheimnisse

Kein Datenobjekt speichert ein Geheimnis im Klartext im Zustand. Geheimnisse, die Sie KeenAuth übergeben, sind nur schreibbare Argumente (`*_wo`): Der Provider sendet sie, schreibt sie aber nie in Zustands- oder Plandateien, und sendet sie nur erneut, wenn sich ihre `*_wo_version` ändert. Sie benötigen OpenTofu oder Terraform 1.11 oder neuer. Derzeit betrifft das das Client-Secret einer Enterprise-OIDC-Verbindung (`keenauth_connection_oidc_config`). Client-Secrets von Anwendungen und Signierschlüssel werden von dieser Version des Providers nicht verwaltet; erstellen und rotieren Sie sie im Dashboard oder mit der CLI. Von KeenAuth erzeugte Geheimnisse können nicht nur schreibbar sein, weil ein nur schreibbares Argument einen Wert nur aus der Konfiguration an den Provider weitergibt. Der Provider erstellt nie API-Schlüssel, weil der Klartextschlüssel im Zustand landen würde: Erstellen Sie einen Schlüssel mit der CLI, speichern Sie ihn in Ihrem Secret-Manager und importieren Sie ihn über seine ID in `keenauth_api_key`. Das SCIM-Token eines Verzeichnisses wird von der API nur einmal angezeigt. Deshalb widerruft der Provider das Token, das das Erstellen eines Verzeichnisses zurückgibt, und behält es nie; `keenauth_directory_token` erstellt das Token für Ihren Identitätsanbieter und speichert es im Zustand nur verschlüsselt mit Ihrem öffentlichen RSA-Schlüssel. `keenauth_webhook_endpoint` behandelt das Webhook-Signiergeheimnis auf dieselbe Weise, nur verschlüsselt mit seinem `public_key`, und verwirft es, wenn kein Schlüssel angegeben ist. Die `settings` einer Verbindung dürfen keine Geheimnisse enthalten; die API lehnt geheimnisartige Einstellungen ab.

## Grenzen dieser Version

- Anwendungen, Verbindungen und deren OIDC-Konfiguration, Umgebungseinstellungen, Angriffsschutz, das Umgebungsdesign des Branding-Entwurfs, eigene Domains, API-Schlüssel (nur Import), Organisationen, Rollen und Berechtigungen, Organisationsdomains, Sitzungs- und MFA-Richtlinien der Organisation, E-Mail-Vorlagen, Management-Clients, SCIM-Verzeichnisse, deren Gruppen-zu-Rolle-Zuordnungen, SCIM-Token (verschlüsselt mit Ihrem öffentlichen Schlüssel) und Webhook-Endpunkte werden verwaltet. Hooks, Log-Streams und SMS-Vorlagen folgen in späteren Versionen.
- Der Provider veröffentlicht kein Branding; veröffentlichen Sie den Entwurf im Dashboard oder mit `keenauth branding publish`.
- Optionale Felder mit einem serverseitigen Standardwert (zum Beispiel `grant_types`) behalten ihren letzten Wert, wenn Sie sie aus der Konfiguration entfernen.
- Schemabeschreibungen und Fehlermeldungen sind auf Englisch.
