RBAC with API Gateway and Open Policy Agent (OPA)
May 15, 2023
Mit verschiedenen Zugriffskontrollmodellen und Implementierungsmethoden, die zur Verfügung stehen, kann der Aufbau eines Autorisierungssystems für Backend-Service-APIs immer noch eine Herausforderung darstellen. Das ultimative Ziel ist jedoch sicherzustellen, dass die richtige Person den entsprechenden Zugriff auf die relevanten Ressourcen hat. In diesem Artikel werden wir diskutieren, wie Sie das rollenbasierte Zugriffskontrollmodell (RBAC) für Ihre API mit dem Open-Source-API-Gateway Apache APISIX und Open Policy Agent (OPA) aktivieren können.
Lernziele
Sie werden im Laufe des Artikels Folgendes lernen:
- Was ist RBAC und wie funktioniert es?
- Was ist OPA und wie funktioniert es?
- Wie implementiert man RBAC mit OPA und Apache APISIX?
- Wie definiert und registriert man die Richtlinie in OPA.
- Wie erstellt man ein Upstream, eine Route und aktiviert das OPA-Plugin.
- Wie die Rolle und Berechtigung des Benutzers aus dem JWT-Token-Payload oder den Consumer-Daten extrahiert wird.
Was ist RBAC?
Rollenbasierte Zugriffskontrolle (RBAC) und Attributbasierte Zugriffskontrolle (ABAC) sind zwei häufig verwendete Zugriffskontrollmodelle, die verwendet werden, um Berechtigungen zu verwalten und den Zugriff auf Ressourcen in Computersystemen zu steuern. RBAC weist Benutzern Berechtigungen basierend auf ihrer Rolle innerhalb einer Organisation zu. In RBAC werden Rollen basierend auf den Funktionen oder Verantwortlichkeiten der Benutzer definiert, und Berechtigungen werden diesen Rollen zugewiesen. Benutzer werden dann einer oder mehreren Rollen zugewiesen und erben die mit diesen Rollen verbundenen Berechtigungen. Im API-Kontext könnte beispielsweise eine Entwicklerrolle die Berechtigung haben, API-Ressourcen zu erstellen und zu aktualisieren, während eine Endbenutzerrolle möglicherweise nur die Berechtigung hat, API-Ressourcen zu lesen oder auszuführen.
Grundsätzlich weist RBAC Berechtigungen basierend auf Benutzerrollen zu, während ABAC Berechtigungen basierend auf Attributen zuweist, die mit Benutzern und Ressourcen verbunden sind.
In RBAC wird eine Richtlinie durch die Kombination der zugewiesenen Rolle eines Benutzers, der Aktionen, die er ausführen darf, und der Ressourcen, auf denen er diese Aktionen ausführen kann, definiert.
Was ist OPA?
OPA (Open Policy Agent) ist eine Policy-Engine und eine Reihe von Tools, die einen einheitlichen Ansatz zur Durchsetzung von Richtlinien in einem gesamten verteilten System bieten. Es ermöglicht Ihnen, Richtlinien zentral von einem einzigen Punkt aus zu definieren, zu verwalten und durchzusetzen. Durch die Definition von Richtlinien als Code ermöglicht OPA eine einfache Überprüfung, Bearbeitung und Rücknahme von Richtlinien, was ein effizientes Richtlinienmanagement erleichtert.
OPA bietet eine deklarative Sprache namens Rego, mit der Sie Richtlinien in Ihrem gesamten Stack erstellen und durchsetzen können. Wenn Sie eine Richtlinienentscheidung von OPA anfordern, verwendet es die Regeln und Daten, die Sie in einer .rego
-Datei bereitgestellt haben, um die Abfrage zu bewerten und eine Antwort zu erzeugen. Das Abfrageergebnis wird dann als Richtlinienentscheidung an Sie zurückgesendet. OPA speichert alle Richtlinien und die benötigten Daten in seinem In-Memory-Cache. Dadurch gibt OPA Ergebnisse schnell zurück. Hier ist ein Beispiel für eine einfache OPA-Rego-Datei:
package example
default allow = false
allow {
input.method == "GET"
input.path =="/api/resource"
input.user.role == "admin"
}
In diesem Beispiel haben wir ein Paket namens "example", das eine Regel namens "allow" definiert. Die "allow"-Regel gibt an, dass die Anfrage erlaubt ist, wenn die Eingabemethode "GET" ist, der angeforderte Pfad /api/resource
ist und die Rolle des Benutzers "admin" ist. Wenn diese Bedingungen erfüllt sind, wird die "allow"-Regel als "true" bewertet, wodurch die Anfrage fortgesetzt werden kann.
Warum OPA und API-Gateway für RBAC verwenden?
API-Gateways bieten einen zentralen Ort, um APIs und API-Consumer zu konfigurieren und zu verwalten. Es kann als zentrales Authentifizierungsgateway verwendet werden, indem verhindert wird, dass jeder einzelne Dienst die Authentifizierungslogik im Dienst selbst implementiert. Andererseits fügt OPA eine Autorisierungsschicht hinzu und entkoppelt die Richtlinie vom Code, wodurch ein deutlicher Vorteil für die Autorisierung entsteht. Mit dieser Kombination können Sie Berechtigungen für eine API-Ressource einer Rolle hinzufügen. Benutzer können einer oder mehreren Benutzerrollen zugeordnet sein. Jede Benutzerrolle definiert eine Reihe von Berechtigungen (GET, PUT, DELETE) für RBAC-Ressourcen (definiert durch URI-Pfade). Im nächsten Abschnitt lernen wir, wie man RBAC mit diesen beiden erreicht.
Wie implementiert man RBAC mit OPA und Apache APISIX
In Apache APISIX können Sie Routen und Plugins konfigurieren, um das Verhalten Ihrer API zu definieren. Sie können das APISIX opa-Plugin verwenden, um RBAC-Richtlinien durchzusetzen, indem Anfragen an OPA zur Entscheidungsfindung weitergeleitet werden. Dann trifft OPA eine Autorisierungsentscheidung basierend auf den Rollen und Berechtigungen der Benutzer in Echtzeit.
Angenommen, wir haben eine Conference API, über die Sie Veranstaltungssitzungen, Themen und Sprecherinformationen abrufen/bearbeiten können. Ein Sprecher kann nur seine eigenen Sitzungen und Themen lesen, während der Administrator weitere Sitzungen und Themen hinzufügen/bearbeiten kann. Oder Teilnehmer können ihr Feedback zur Sitzung des Sprechers über eine POST-Anfrage an /speaker/speakerId/session/feedback
hinterlassen, und der Sprecher kann dies nur sehen, indem er die GET-Methode derselben URI anfordert. Das folgende Diagramm veranschaulicht das gesamte Szenario:
- Der API-Consumer fordert eine Route auf dem API-Gateway mit seinen Anmeldeinformationen wie einem JWT-Token im Autorisierungsheader an.
- Das API-Gateway sendet die Consumer-Daten mit einem JWT-Header an die OPA-Engine.
- OPA bewertet, ob der Consumer das Recht hat, auf die Ressource zuzugreifen, indem es die Richtlinien (Rollen und Berechtigungen) verwendet, die wir in der .rego-Datei angegeben haben.
- Wenn die OPA-Entscheidung erlaubt ist, wird die Anfrage an den Upstream-Conference-Dienst weitergeleitet.
Als Nächstes installieren und konfigurieren wir APISIX und definieren Richtlinien in OPA.
Voraussetzungen
- Docker wird verwendet, um den containerisierten etcd und APISIX zu installieren.
- curl wird verwendet, um Anfragen an die APISIX-Admin-API zu senden. Sie können auch Tools wie Postman verwenden, um mit der API zu interagieren.
Schritt 1: Apache APISIX installieren
APISIX kann einfach mit dem folgenden Quickstart-Skript installiert und gestartet werden:
curl -sL https://run.api7.ai/apisix/quickstart | sh
Schritt 2: Den Backend-Dienst (Upstream) konfigurieren
Um Anfragen an den Backend-Dienst für die Conference API weiterzuleiten, müssen Sie diesen konfigurieren, indem Sie einen Upstream-Server in Apache APISIX über die Admin-API hinzufügen.
curl http://127.0.0.1:9180/apisix/admin/upstreams/1 -X PUT -d '
{
"name":"Conferences API upstream",
"desc":"Register Conferences API as the upstream",
"type":"roundrobin",
"scheme":"https",
"nodes":{
"conferenceapi.azurewebsites.net:443":1
}
}'
Schritt 3: Einen API-Consumer erstellen
Als Nächstes erstellen wir einen Consumer (einen neuen Sprecher) mit dem Benutzernamen jack
in Apache APISIX. Es richtet das jwt-auth-Plugin für den Consumer mit dem angegebenen Schlüssel und Geheimnis ein. Dies ermöglicht es dem Consumer, sich mit einem JSON Web Token (JWT) zu authentifizieren.
curl http://127.0.0.1:9180/apisix/admin/consumers -X PUT -d '
{
"username": "jack",
"plugins": {
"jwt-auth": {
"key": "user-key",
"secret": "my-secret-key"
}
}
}'
Schritt 4: Einen öffentlichen Endpunkt zum Generieren eines JWT-Tokens erstellen
Sie müssen auch eine neue Route einrichten, die das Token mit dem public-api-Plugin generiert und signiert. In diesem Szenario fungiert das API-Gateway als Identitätsanbieter-Server, um das Token mit dem Schlüssel unseres Consumers Jack zu erstellen und zu überprüfen. Der Identitätsanbieter kann auch ein anderer Drittanbieterdienst wie Google, Okta, Keycloak oder Ory Hydra sein.
curl http://127.0.0.1:9180/apisix/admin/routes/jas -X PUT -d '
{
"uri": "/apisix/plugin/jwt/sign",
"plugins": {
"public-api": {}
}
}'
Schritt 5: Ein neues JWT-Token für den API-Consumer beanspruchen
Jetzt können wir ein neues Token für unseren Sprecher Jack vom API-Gateway über den von uns erstellten öffentlichen Endpunkt erhalten. Der folgende curl-Befehl generiert ein neues Token mit den Anmeldeinformationen von Jack und weist die Rolle und Berechtigung im Payload zu.
curl -G --data-urlencode 'payload={"role":"speaker","permission":"read"}' http://127.0.0.1:9080/apisix/plugin/jwt/sign?key=user-key -i
Nachdem Sie den obigen Befehl ausgeführt haben, erhalten Sie ein Token als Antwort. Speichern Sie dieses Token an einem sicheren Ort, da wir es später verwenden werden, um auf unseren neuen API-Gateway-Endpunkt zuzugreifen.
Schritt 6: Eine neue Plugin-Konfiguration erstellen
Dieser Schritt beinhaltet die Konfiguration von 3 Plugins von APISIX: proxy-rewrite, jwt-auth und opa.
curl "http://127.0.0.1:9180/apisix/admin/plugin_configs/1" -X PUT -d '
{
"plugins":{
"jwt-auth":{
},
"proxy-rewrite":{
"host":"conferenceapi.azurewebsites.net"
}
}
}'
- Das
proxy-rewrite
-Plugin ist so konfiguriert, dass Anfragen an den Hostconferenceapi.azurewebsites.net
weitergeleitet werden. - Das OPA-Authentifizierungs-Plugin ist so konfiguriert, dass es die OPA-Policy-Engine verwendet, die unter http://localhost:8181/v1/data/rbacExample läuft. Außerdem sendet APISIX alle Consumer-bezogenen Informationen an OPA. Wir werden diese Richtlinien-
.rego
-Datei im OPA-Konfigurationsabschnitt hinzufügen.
Schritt 7: Eine Route für Conference-Sitzungen erstellen
Der letzte Schritt besteht darin, eine neue Route für die Conference-API-Sprechersitzungen zu erstellen:
curl "http://127.0.0.1:9180/apisix/admin/routes/1" -X PUT -d '
{
"name":"Conferences API speaker sessions route",
"desc":"Create a new route in APISIX for the Conferences API speaker sessions",
"methods": ["GET", "POST"],
"uris": ["/speaker/*/topics","/speaker/*/sessions"],
"upstream_id":"1",
"plugin_config_id":1
}'
Die Payload enthält Informationen über die Route, wie ihren Namen, Beschreibung, Methoden, URIs, Upstream-ID und Plugin-Konfigurations-ID. In diesem Fall ist die Route so konfiguriert, dass sie GET- und POST-Anfragen für zwei verschiedene URIs, /speaker/topics
und /speaker/sessions
, verarbeitet. Das Feld "upstream_id" gibt die ID des Upstream-Dienstes an, der eingehende Anfragen für diese Route verarbeitet, während das Feld "plugin_config_id" die ID der Plugin-Konfiguration angibt, die für diese Route verwendet werden soll.
Schritt 8: Das Setup ohne OPA testen
Bisher haben wir alle notwendigen Konfigurationen für APISIX eingerichtet, um eingehende Anfragen an die Conference-API-Endpoints weiterzuleiten, wobei nur autorisierte API-Consumer zugelassen sind. Jedes Mal, wenn ein API-Consumer auf einen Endpunkt zugreifen möchte, muss er ein JWT-Token bereitstellen, um Daten vom Conference-Backend-Dienst abzurufen. Sie können dies überprüfen, indem Sie den Endpunkt aufrufen, und die Domain-Adresse, die wir jetzt anfordern, ist unser benutzerdefiniertes API-Gateway, nicht der eigentliche Conference-Dienst:
curl -i http://127.0.0.1:9080/speaker/1/topics -H 'Authorization: {API_CONSUMER_TOKEN}'
Schritt 9: Den OPA-Dienst ausführen
Die anderen beiden Schritte bestehen darin, den OPA-Dienst mit Docker auszuführen und unsere Richtliniendefinition über seine API hochzuladen, die verwendet werden kann, um Autorisierungsrichtlinien für eingehende Anfragen zu bewerten.
docker run -d --network=apisix-quickstart-net --name opa -p 8181:8181 openpolicyagent/opa:latest run -s
Dieser Docker-Befehl führt einen Container des OPA-Images mit der neuesten Version aus. Es erstellt einen neuen Container im bestehenden APISIX-Netzwerk apisix-quickstart-net
mit dem Namen opa
und macht Port 8181
verfügbar. So kann APISIX Richtlinienprüfanfragen direkt an OPA unter der Adresse [http://opa:8181](http://opa:8181)
senden. Beachten Sie, dass OPA und APISIX im selben Docker-Netzwerk laufen sollten.
Schritt 10: Die Richtlinie definieren und registrieren
Der zweite Schritt auf der OPA-Seite besteht darin, die Richtlinien zu definieren, die verwendet werden, um den Zugriff auf API-Ressourcen zu steuern. Diese Richtlinien sollten die für den Zugriff erforderlichen Attribute definieren (Welche Benutzer haben welche Rollen) und die Berechtigungen (Welche Rollen haben welche Berechtigungen), die basierend auf diesen Attributen erlaubt oder verweigert werden. In der folgenden Konfiguration sagen wir OPA beispielsweise, dass es die user_roles
-Tabelle überprüfen soll, um die Rolle für jack
zu ermitteln. Diese Informationen werden von APISIX innerhalb von input.consumer.username
gesendet. Außerdem überprüfen wir die Berechtigung des Consumers, indem wir den JWT-Payload lesen und token.payload.permission
daraus extrahieren. Die Kommentare beschreiben die Schritte klar.
curl -X PUT '127.0.0.1:8181/v1/policies/rbacExample' \
-H 'Content-Type: text/plain' \
-d 'package rbacExample
# Zuweisung von Benutzerrollen
user_roles := {
"jack": ["speaker"],
"bobur":["admin"]
}
# Rollenberechtigungszuweisungen
role_permissions := {
"speaker": [{"permission": "read"}],
"admin": [{"permission": "read"}, {"permission": "write"}]
}
# Hilfsfunktionen für JWT
bearer_token := t {
t := input.request.headers.authorization
}
# Dekodieren des Autorisierungstokens, um eine Rolle und Berechtigung zu erhalten
token = {"payload": payload} {
[_, payload, _] := io.jwt.decode(bearer_token)
}
# Logik, die RBAC implementiert
default allow = false
allow {
# Nachschlagen der Liste der Rollen für den Benutzer
roles := user_roles[input.consumer.username]
# Für jede Rolle in dieser Liste
r := roles[_]
# Nachschlagen der Berechtigungsliste für die Rolle r
permissions := role_permissions[r]
# Für jede Berechtigung
p := permissions[_]
# Überprüfen, ob die für r gewährte Berechtigung der Benutzeranfrage entspricht
p == {"permission": token.payload.permission}
}'
Schritt 11: Die bestehende Plugin-Konfiguration mit dem OPA-Plugin aktualisieren
Sobald wir die Richtlinien auf dem OPA-Dienst definiert haben, müssen wir die bestehende Plugin-Konfiguration für die Route aktualisieren, um das OPA-Plugin zu verwenden. Wir geben dies im policy
-Attribut des OPA-Plugins an.
curl "http://127.0.0.1:9180/apisix/admin/plugin_configs/1" -X PATCH -d '
{
"plugins":{
"opa":{
"host":"http://opa:8181",
"policy":"rbacExample",
"with_consumer":true
}
}
}'
Schritt 12: Das Setup mit OPA testen
Jetzt können wir alle Setups, die wir mit OPA-Richtlinien durchgeführt haben, testen. Wenn Sie versuchen, denselben curl-Befehl auszuführen, um auf den API-Gateway-Endpunkt zuzugreifen, überprüft es zuerst das JWT-Token als Teil des Authentifizierungsprozesses und sendet die Consumer- und JWT-Token-Daten an OPA, um die Rolle und Berechtigung als Teil des Autorisierungsprozesses zu überprüfen. Jede Anfrage ohne ein JWT-Token oder ohne die erlaubten Rollen wird abgelehnt.
curl -i http://127.0.0.1:9080/speaker/1/topics -H 'Authorization: {API_CONSUMER_TOKEN}'
Fazit
In diesem Artikel haben wir gelernt, wie man RBAC mit OPA und Apache APISIX implementiert. Wir haben eine einfache benutzerdefinierte Richtlinienlogik definiert, um den Zugriff auf API-Ressourcen basierend auf der Rolle und den Berechtigungen unseres API-Consumers zu erlauben/zu verweigern. Außerdem hat dieses Tutorial gezeigt, wie wir API-Consumer-bezogene Informationen in der Richtliniendatei aus dem JWT-Token-Payload oder dem Consumer-Objekt, das von APISIX gesendet wird, extrahieren können.
Verwandte Ressourcen
- Apache APISIX Autorisierungsrichtlinie: Schützen Sie Ihre APIs
- Zentralisierte Authentifizierung mit Apache APISIX-Plugins
- API-Consumer mit Apache APISIX verwalten