Service Mesh (ASM) s'intègre au plugin Open Policy Agent (OPA), ce qui permet d'appliquer un contrôle d'accès granulaire à vos applications via des politiques OPA. ASM vous permet de définir ces politiques sur le plan de contrôle et de les pousser vers les clusters du plan de données. Cette rubrique explique comment utiliser cette fonctionnalité pour contrôler l'accès en fonction de critères tels que l'URL de la requête et les jetons présents dans l'en-tête de la requête.
Prérequis
Une instance ASM de version 1.9.7 ou ultérieure. Pour plus d'informations, consultez la section Créer une instance ASM.
L'injection automatique de sidecar est activée pour le namespace par défaut. Pour plus d'informations, consultez la section Activer l'injection automatique.
Contexte
Hébergé par la CNCF en tant que projet en incubation, Open Policy Agent (OPA) est un moteur de politiques permettant de mettre en œuvre un contrôle d'accès granulaire pour vos applications. En tant que moteur de politiques polyvalent, OPA peut être déployé en tant que service autonome aux côtés des microservices. Pour protéger les applications, chaque requête adressée à un microservice doit être autorisée avant son traitement. Pour vérifier cette autorisation, le microservice effectue un appel API vers OPA afin de déterminer si la requête est légitime.
Étape 1 : Activer le plugin OPA et le contrôle de portée
Connectez-vous à la console ASM. Dans le volet de navigation de gauche, sélectionnez .
Sur la page Mesh Management , cliquez sur le nom de l'instance ASM. Dans le volet de navigation de gauche, sélectionnez .
Sur la page OPA Policy , activez les options Enable Open Policy Agent (OPA) Plugin et Enable OPA Injection Scope Control , puis cliquez sur Enable OPA . Dans la boîte de dialogue Note qui s'affiche, cliquez sur OK .
Étape 2 : Créer une politique OPA
Vous créez une ressource ASMOPAPolicy sur le plan de contrôle ASM. ASM pousse ensuite cette ressource vers le cluster du plan de données, où le moteur OPA présent dans chaque pod concerné l'utilise pour appliquer un contrôle d'accès granulaire.
Option 1 : Utiliser la console ASM
Connectez-vous à la console ASM. Dans le volet de navigation de gauche, sélectionnez .
Sur la page Mesh Management , cliquez sur le nom de l'instance ASM. Dans le volet de navigation de gauche, sélectionnez .
-
Sur la page OPA Policy , cliquez sur Create . Sélectionnez le namespace default , définissez le Name de la politique OPA sur bookinfo-opa , puis cliquez sur Add Matching Label . Définissez le Name sur version et la Value sur v1 . Copiez les règles Rego suivantes dans la zone de texte, puis cliquez sur Create .
Option 2 : Utiliser kubectl
-
Créez un fichier nommé opa.yaml contenant le code suivant.
RemarqueLorsque vous définissez une politique OPA pour un pod, vous ne pouvez inclure qu'un seul champ
default allow. Si plusieurs politiques OPA s'appliquent à un même pod et que chacune définit un champdefault allow, la présence de multiples champsdefault allowentraîne l'échec des mises à jour dynamiques.Définissez la portée des politiques à l'aide de libellés. Une règle Rego invalide peut rendre un service inaccessible.
Le moteur d'exécution OPA et le conteneur d'application s'exécutent dans le même pod et occupent les ports 15081 et 9191.
Par défaut, les politiques OPA appliquent la règle
allow = false. Ne redéfinissez pasdefault allowafin d'éviter les conflits.
Paramètre
Description
specLes règles de la politique, rédigées dans le langage Rego. Pour plus d'informations sur la syntaxe Rego, consultez la documentation Rego .
workloadSelectorSpécifie la portée de la politique au sein du namespace. Si ce paramètre est omis, la politique s'applique à tous les pods du namespace. S'il est spécifié, elle ne s'applique qu'aux pods dont les libellés correspondent.
user_rolesAccorde des permissions de rôle aux utilisateurs. Dans cet exemple, l'utilisateur
guest1reçoit le rôleguest, et l'utilisateuradmin1reçoit le rôleadmin.role_permsDéfinit les permissions associées à chaque rôle. Dans cet exemple, le rôle
guestpeut accéder à /productpage , tandis que le rôleadminpeut accéder à /productpage et à /api/v1/products . -
Exécutez la commande suivante pour créer la politique OPA.
Pour savoir comment se connecter à une instance ASM à l'aide de kubectl, consultez la section Utiliser kubectl sur le plan de contrôle pour accéder aux ressources Istio .
kubectl apply -f opa.yaml
Étape 3 : Injecter le proxy OPA
Déployez l'application exemple Bookinfo sur l'instance ASM et vérifiez qu'ASM a injecté le proxy OPA dans chaque pod.
Déployez l'application exemple Bookinfo sur l'instance ASM. Pour plus d'informations, consultez la section Déployer une application dans un cluster associé à une instance ASM .
Créez une passerelle d'entrée, une passerelle Istio et un service virtuel. Pour plus d'informations, consultez la section Utiliser les ressources Istio pour router le trafic en fonction des versions .
-
Vérifiez si le proxy OPA est injecté dans chaque pod d'application.
Connectez-vous à la console ACK . Dans le volet de navigation de gauche, cliquez sur Clusters .
Sur la page Clusters , cliquez sur le nom de votre cluster. Dans le volet de navigation de gauche, cliquez sur .
-
Sur la page Pods , sélectionnez default dans la liste déroulante Namespace , puis cliquez sur le nom du pod d'application cible.
Dans l'onglet Containers , vérifiez que le pod contient à la fois les conteneurs istio-proxy (le proxy sidecar) et opa-istio (le proxy OPA).
Étape 4 : Vérifier la politique de contrôle d'accès OPA
-
Exécutez la commande suivante pour accéder à /productpage .
curl -X GET http://<INGRESS_GATEWAY_IP>/productpage --user guest1:password -IRésultat attendu :
HTTP/1.1 200 OK -
Exécutez la commande suivante pour accéder à
/api/v1/products.curl -X GET http://<INGRESS_GATEWAY_IP>/api/v1/products --user guest1:password -IRésultat attendu :
HTTP/1.1 403 ForbiddenCes résultats confirment que l'utilisateur guest1, doté du rôle guest, peut accéder à
/productpagemais se voit refuser l'accès à/api/v1/products. -
Exécutez la commande suivante pour accéder à
/productpage.curl -X GET http://<INGRESS_GATEWAY_IP>/productpage --user admin1:password -IRésultat attendu :
HTTP/1.1 200 OK -
Exécutez la commande suivante pour accéder à
/api/v1/products.curl -X GET http://<INGRESS_GATEWAY_IP>/api/v1/products --user admin1:password -IRésultat attendu :
HTTP/1.1 200 OKLes résultats indiquent que
admin1dispose du rôleadmin. L'utilisateuradmin1peut accéder à la fois à/productpageet à/api/v1/products. Cela confirme que la politique de contrôle d'accès OPA fonctionne comme prévu.
Étape 5 : Mettre à jour dynamiquement une politique OPA
Exécutez la commande suivante pour modifier la politique OPA.
kubectl edit asmopapolicy bookinfo-opa -n default
Dans la sortie, modifiez la politique OPA pour accorder à guest1 les rôles guest et admin .
apiVersion: istio.alibabacloud.com/v1beta1
kind: ASMOPAPolicy
metadata:
name: bookinfo-opa
namespace: default
spec:
policy: |
package istio.authz
import input.attributes.request.http as http_request
allow {
roles_for_user[r]
required_roles[r]
}
roles_for_user[r] {
r := user_roles[user_name][_]
}
required_roles[r] {
perm := role_perms[r][_]
perm.method = http_request.method
perm.path = http_request.path
}
user_name = parsed {
[_, encoded] := split(http_request.headers.authorization, " ")
[parsed, _] := split(base64url.decode(encoded), ":")
}
user_roles = {
"guest1": ["guest", "admin"],
"admin1": ["admin"]
}
role_perms = {
"guest": [
{"method": "GET", "path": "/productpage"},
],
"admin": [
{"method": "GET", "path": "/productpage"},
{"method": "GET", "path": "/api/v1/products"},
],
}
user_roles : Accorde des permissions de rôle aux utilisateurs. Dans cet exemple, l'utilisateur
guest1reçoit les rôlesguestetadmin, tandis que l'utilisateuradmin1reçoit le rôleadmin.role_perms : Définit les permissions associées à chaque rôle. Dans cet exemple, le rôle
guestpeut accéder à /productpage , tandis que le rôleadminpeut accéder à la fois à /productpage et à /api/v1/products .
Étape 6 : Vérifier la mise à jour dynamique
-
Exécutez la commande suivante pour accéder à /productpage .
curl -X GET http://<INGRESS_GATEWAY_IP>/productpage --user guest1:password -IRésultat attendu :
HTTP/1.1 200 OK -
Exécutez la commande suivante pour accéder à /api/v1/products .
curl -X GET http://<INGRESS_GATEWAY_IP>/api/v1/products --user guest1:password -IRésultat attendu :
HTTP/1.1 200 OKAuparavant,
guest1ne pouvait accéder qu'à/productpage. Après la mise à jour,guest1peut également accéder à/api/v1/products, ce qui confirme le succès de la mise à jour dynamique de la politique.
Scénarios
Scénario 1 : Autoriser les requêtes en fonction des revendications JWT
Ce scénario illustre la procédure d'autorisation des requêtes basée sur les revendications contenues dans un jeton Web JSON (JWT). La politique vérifie le JWT présent dans l'en-tête de la requête, afin de n'autoriser que les requêtes fiables à accéder à l'application.
La stratégie ASMOPAPolicy ci-dessous autorise l'accès à l'application Productpage uniquement si la requête utilise la méthode GET, si la revendication Role du JWT est définie sur guest et si la revendication userGroup est définie sur visitor.
apiVersion: istio.alibabacloud.com/v1beta1
kind: ASMOPAPolicy
metadata:
name: policy-jwt
namespace: default
spec:
policy: |
package istio.authz
allow {
input.attributes.request.http.method == "GET"
input.parsed_path[0] == "productpage"
# set certificate 'B41BD5F462719C6D6118E673A2389'
io.jwt.verify_hs256(bearer_token, "B41BD5F462719C6D6118E673A2389")
claims.Role == "guest"
claims.userGroup == "visitor"
}
claims := payload {
[_, payload, _] := io.jwt.decode(bearer_token)
}
bearer_token := t {
v := input.attributes.request.http.headers.authorization
startswith(v, "Bearer ")
t := substring(v, count("Bearer "), -1)
}
input.attributes.request.http.method : Méthode de la requête. Dans cet exemple, la valeur est
GET.input.parsed_path[0] : Application ciblée par l'accès.
claims.Role : Restreint le JWT. Dans cet exemple, la valeur
Roledoit êtreguest.claims.userGroup : Restreint le JWT. Dans cet exemple, la valeur
userGroupdoit êtrevisitor.
Utilisez un outil JWT pour encoder les informations de la requête, telles que Role et userGroup, dans une chaîne JWT. Dans la section Payload de l'outil d'encodage JWT, outre Role et userGroup, vous devez également définir name sur guest1, configurer la clé de signature sur B41BD5F462719C6D6118 et sélectionner l'algorithme HS256. Après l'encodage, vous obtenez la chaîne JWT nécessaire à l'autorisation de la requête.
Exécutez la commande suivante pour accéder à l'application Productpage.
curl --location --request GET 'http://<INGRESS_GATEWAY_IP>/productpage' \
--header 'Authorization: Bearer
eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJuYW1lIjoiZ3Vlc3QxIiwiUm9sZSI6Imd1ZXN0IiwidXNlckdyb3VwIjoidmlzaXRvciJ9.44OnUFZwOzSWzC7hyVfcle-uYk8byv7q_BBxS10AEWc'
Résultat attendu :
HTTP/1.1 200 OK
Une réponse 200 indique que la requête GET adressée à l'application Productpage a abouti. Ce résultat s'observe lorsque la requête inclut un jeton JWT dont la revendication Role est définie sur guest et la revendication userGroup sur visitor. Si un jeton JWT incorrect est utilisé, ou si la requête ne contient aucun jeton JWT, une réponse 403 est renvoyée, signalant l'échec de l'accès à l'application Productpage.
Scénario 2 : Restreindre le corps de la requête HTTP
Ce scénario montre comment autoriser les requêtes en validant les champs du corps de la requête HTTP par rapport aux revendications du JWT.
La stratégie ASMOPAPolicy ci-dessous autorise l'accès à l'application Productpage uniquement si la requête utilise la méthode GET, si le champ username du corps de la requête correspond à la revendication Role du JWT, et si la revendication userGroup est définie sur manager.
apiVersion: istio.alibabacloud.com/v1beta1
kind: ASMOPAPolicy
metadata:
name: policy-body
namespace: default
spec:
policy: |
package istio.authz
allow {
input.attributes.request.http.method == "GET"
input.parsed_path[0] == "productpage"
io.jwt.verify_hs256(bearer_token, "B41BD5F462719C6D6118E673A2389")
claims.Role == input.parsed_body.username
claims.userGroup == "manager"
}
claims := payload {
[_, payload, _] := io.jwt.decode(bearer_token)
}
bearer_token := t {
v := input.attributes.request.http.headers.authorization
startswith(v, "Bearer ")
t := substring(v, count("Bearer "), -1)
}
input.attributes.request.http.method : Méthode de la requête. Dans cet exemple, la valeur est
GET.input.parsed_path[0] : Application ciblée par l'accès.
claims.Role : Restreint le JWT. Dans cet exemple, la valeur est définie sur
input.parsed_body.username, ce qui impose que le champusernamedu corps de la requête corresponde à la revendicationRoledu JWT.claims.userGroup : Restreint le JWT. Dans cet exemple, la valeur
userGroupdoit êtremanager.
Utilisez un outil JWT pour encoder les informations de la requête, telles que Role et userGroup, dans une chaîne JWT.
Exécutez la commande suivante pour accéder à l'application Productpage.
curl --location --request GET 'http://<INGRESS_GATEWAY_IP>/productpage' \
--header 'Authorization: Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJuYW1lIjoiZ3Vlc3QxIiwiUm9sZSI6ImFkbWluIiwidXNlckdyb3VwIjoibWFuYWdlciJ9.pAUvTeONHF-i5Ps-EUYYXk-hnaz-j-ZgP_wXJZMBiR0' \
--header 'Content-Type: application/json' \
--header 'Cookie: session=eyJ1c2VyIjoiYWRtaW4ifQ.YRz90g.GT34_5BqlFTwGqabZk_qGZzxYQ0' \
--data-raw '{
"username":"admin",
"password":"12****"
}'
Résultat attendu :
HTTP/1.1 200 OK
Une réponse 200 OK indique qu'une requête GET peut accéder à l'application Productpage si le champ username du corps de la requête correspond à la revendication Role du JWT et si la revendication userGroup du JWT est définie sur manager. Des jetons JWT invalides ou absents entraînent une réponse 403 Forbidden.
Scénario 3 : Restreindre davantage d'informations contextuelles
En vous basant sur le scénario 2, vous pouvez restreindre davantage d'informations contextuelles. Par exemple, vous pouvez exiger que la revendication username du JWT figure dans la liste bookinfo_managers.
La stratégie ASMOPAPolicy ci-dessous autorise l'accès à l'application Productpage uniquement si la requête utilise la méthode GET, si le champ username du corps de la requête correspond à la revendication Role du JWT, si la revendication username du JWT figure dans la liste bookinfo_managers et si la revendication userGroup est définie sur manager.
apiVersion: istio.alibabacloud.com/v1beta1
kind: ASMOPAPolicy
metadata:
name: policy-range
namespace: default
spec:
policy: |
package istio.authz
bookinfo_managers = [{"name": "user1"}, {"name": "user2"}, {"name": "user3"}]
allow {
input.attributes.request.http.method == "GET"
input.parsed_path[0] == "productpage"
io.jwt.verify_hs256(bearer_token, "B41BD5F462719C6D6118E673A2389")
claims.Role == input.parsed_body.username
claims.userGroup == "manager"
claims.username == bookinfo_managers[_].name
}
claims := payload {
[_, payload, _] := io.jwt.decode(bearer_token)
}
bearer_token := t {
v := input.attributes.request.http.headers.authorization
startswith(v, "Bearer ")
t := substring(v, count("Bearer "), -1)
}
input.attributes.request.http.method : Méthode de la requête. Dans cet exemple, la valeur est
GET.input.parsed_path[0] : Application ciblée par l'accès.
claims.Role : Restreint le JWT. Dans cet exemple, la valeur est définie sur
input.parsed_body.username, ce qui impose que le nom d'utilisateur du corps de la requête corresponde à la revendication Role du JWT.claims.userGroup : Restreint le JWT. Dans cet exemple, la valeur
userGroupdoit êtremanager.claims.username : Restreint le JWT. Dans cet exemple, la valeur est définie sur
bookinfo_managers[_].name, ce qui impose que la revendicationusernamedu JWT figure dans la listebookinfo_managers.
Utilisez un outil JWT pour encoder les informations de la requête dans une chaîne JWT.
Exécutez la commande suivante pour accéder à l'application Productpage.
curl --location --request GET 'http://<INGRESS_GATEWAY_IP>/productpage' \
--header 'Authorization: Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ1c2VybmFtZSI6InVzZXIxIiwiUm9sZSI6ImFkbWluIiwidXNlckdyb3VwIjoibWFuYWdlciJ9.2X0Fmb96jBexLcVm_55t8ZY6XveSxUAsQ1j3ar5dI_g' \
--header 'Content-Type: application/json' \
--header 'Cookie: session=eyJ1c2VyIjoiYWRtaW4ifQ.YRz90g.GT34_5BqlFTwGqabZk_qGZzxYQ0' \
--data-raw '{
"username":"admin",
"password":"12****"
}'
Résultat attendu :
HTTP/1.1 200 OK
Une réponse 200 OK indique qu'une requête GET peut accéder à l'application Productpage si le champ username du corps de la requête correspond à la revendication Role du JWT, si la revendication username du JWT figure dans la liste bookinfo_managers et si la revendication userGroup du JWT est définie sur manager. Des jetons JWT invalides ou absents entraînent une réponse 403 Forbidden.
FAQ
Comment vérifier les politiques OPA sur un pod ?
Le moteur OPA s'exécute en tant que sidecar dans le pod de l'application. Pour afficher toutes les politiques OPA appliquées à un pod, connectez-vous au pod et exécutez la commande suivante :
curl 127.0.0.1:15081/v1/policies
Comment tester la syntaxe Rego ?
OPA met à disposition un outil de test en ligne permettant de valider les politiques Rego.
Références
Si vous utilisiez auparavant des ConfigMaps pour configurer les politiques OPA, consultez les rubriques suivantes :