Présentation des règles d'autorisation

Contrairement à une application monolithique pouvant être exécutée au même endroit, les applications de microservices distribuées à l'échelle mondiale effectuent des appels au-delà des limites du réseau. Cela signifie qu'elles présentent un plus grand nombre de points d'entrée dans vos applications et davantage de possibilités pour les attaques malveillantes. De plus, étant donné que les pods Kubernetes ont des adresses IP temporaires, les règles de pare-feu basées sur l'adresse IP traditionnelles ne permettent pas de sécuriser l'accès entre les charges de travail. Dans une architecture de microservices, une nouvelle approche de la sécurité est nécessaire. S'appuyant sur des fonctionnalités de sécurité telles que les comptes de service Kubernetes et les règles de sécurité d'Istio, Cloud Service Mesh offre encore plus de fonctionnalités pour sécuriser vos applications.

Cette page offre aux opérateurs d'applications une présentation de la ressource personnalisée (CR, custom resource) AuthorizationPolicy. Les règles d'autorisation vous permettent d'activer le contrôle d'accès sur les charges de travail au niveau des couches d'application (L7) et de transport (L3/4). On configure des règles d'autorisation pour spécifier des autorisations, c'est-à-dire ce qu'un service ou un utilisateur a le droit de faire.

Règles d'autorisation

Les requêtes entre les services de votre maillage (et entre les utilisateurs finaux et les services) sont autorisées par défaut. Utilisez la CR AuthorizationPolicy pour définir des règles précises pour vos charges de travail. Une fois les règles d'autorisation appliquées, Cloud Service Mesh les distribue aux proxys side-car. Lorsque des requêtes arrivent dans une charge de travail, le proxy side-car vérifie les règles d'autorisation pour déterminer si la requête doit être autorisée ou refusée.

Champ d'application des règles

Vous pouvez appliquer une règle à l'ensemble du maillage de services, à un espace de noms ou à une charge de travail individuelle.

  • Pour appliquer une règle à l'échelle du maillage, spécifiez l'espace de noms racine, istio-system, dans le champ metadata:namespace :

    apiVersion: "security.istio.io/v1beta1"
    kind: "AuthorizationPolicy"
    metadata:
      name: "mesh-wide"
      namespace: istio-system
    spec:
    ...
    
  • Pour appliquer une règle à un espace de noms, spécifiez l'espace de noms dans le champ metadata:namespace :

    apiVersion: "security.istio.io/v1beta1"
    kind: "AuthorizationPolicy"
    metadata:
      name: "currencyservice"
      namespace: currencyservice
    spec:
    ...
    
  • Pour limiter une règle à une charge de travail spécifique, incluez un champ selector.

    apiVersion: "security.istio.io/v1beta1"
    kind: "AuthorizationPolicy"
    metadata:
      name: "frontend"
      namespace: demo
    spec:
      selector:
        matchLabels:
          app: frontend
       ...
    

Structure de base

Une règle d'autorisation comprend le champ d'application de la règle, une action (action) et une liste de règles (rules) :

  • Comme décrit dans la section précédente, le champ d'application de la règle peut être l'ensemble du maillage, un espace de noms ou une charge de travail spécifique. Si vous l'incluez, le champ selector spécifie la cible de la règle.

  • Le champ action indique si la requête doit être définie sur ALLOW ou DENY. Si vous ne spécifiez aucune action, celle-ci est définie par défaut sur ALLOW. Par souci de clarté, nous vous recommandons de toujours spécifier l'action (Autorisation sont également compatibles avec AUDIT et CUSTOM actions.)

  • Les règles (rules) spécifient le moment auquel déclencher l'action.

    • Le champ from des règles (rules) spécifie les sources de la requête.

    • Le champ to du fichier rules spécifie opérations de la demande.

    • Le champ when indique conditions nécessaires pour appliquer la règle.

Dans l'exemple suivant :

  • la règle est appliquée aux requêtes adressées au service frontend dans l'espace de noms demo ;

  • les requêtes sont autorisées lorsque "hello:world" figure dans l'en-tête de la requête. Sinon, elles sont refusées.

apiVersion: "security.istio.io/v1beta1"
kind: "AuthorizationPolicy"
metadata:
  name: "hello-world"
  namespace: demo
spec:
  selector:
    matchLabels:
      app: frontend
  action: ALLOW
  rules:
  - when:
    - key: request.headers[hello]
      values: ["world"]

Contrôle des accès lors des opérations de requête

Vous pouvez contrôler l'accès à des opérations de requête spécifiques, telles que des méthodes HTTP ou des ports TCP en ajoutant une section to sous rules. Dans l'exemple suivant, seules les méthodes HTTP GET et POST sont autorisées pour currencyservice dans l'espace de noms demo.

apiVersion: security.istio.io/v1beta1
kind: AuthorizationPolicy
metadata:
 name: currencyservice
 namespace: demo
spec:
 selector:
   matchLabels:
     app: currencyservice
 action: ALLOW
 rules:
 - to:
   - operation:
       methods: ["GET", "POST"]

Contrôle des accès avec une identité authentifiée

Dans les exemples précédents, les règles autorisent les requêtes provenant de charges de travail non authentifiées. Si le protocole TLS mutuel (mTLS) STRICT est activé, vous pouvez limiter l'accès en fonction de l'identité de la charge de travail ou de l'espace de noms dont provient la requête dans la section source.

  • Utilisez le champ principals ou notPrincipal pour contrôler les accès au niveau de la charge de travail.

  • Utilisez le champ namespaces ou notNamespaces pour contrôler les accès au niveau de l'espace de noms.

Tous les champs ci-dessus nécessitent l'activation du protocole mTLS STRICT. Si vous ne pouvez pas définir le protocole mTLS STRICT, reportez-vous à la section Refuser les requêtes en texte brut pour trouver une autre solution.

Charge de travail identifiée

Dans l'exemple suivant, les requêtes adressées à currencyservice ne sont autorisées qu'à partir du service frontend. Les requêtes adressées à currencyservice depuis d'autres charges de travail sont refusées.

apiVersion: "security.istio.io/v1beta1"
kind: "AuthorizationPolicy"
metadata:
  name: "currencyservice"
  namespace: demo
spec:
  selector:
    matchLabels:
      app: currencyservice
  action: ALLOW
  rules:
  - from:
    - source:
        principals: ["example-project-1234.svc.id.goog/ns/demo/sa/frontend-sa"]

Pour spécifier un compte de service, les comptes principaux (principals) de l'autorité de certification Cloud Service Mesh (Mesh CA) et du service d'autorité de certification (CA Service) doivent être au format suivant :

principals: ["PROJECT_ID.svc.id.goog/ns/NAMESPACE/sa/SERVICE_ACCOUNT_NAME"]

PROJECT_ID.svc.id.goog est le domaine de confiance pour Mesh CA. Si vous utilisez Istio CA (anciennement appelé Citadel), le domaine approuvé par défaut est cluster.local.

Espace de noms identifié

L'exemple suivant illustre une règle qui refuse les requêtes si la source n'est pas l'espace de noms foo :

apiVersion: security.istio.io/v1beta1
kind: AuthorizationPolicy
metadata:
 name: httpbin-deny
 namespace: foo
spec:
 selector:
   matchLabels:
     app: httpbin
     version: v1
 action: DENY
 rules:
 - from:
   - source:
       notNamespaces: ["foo"]

Mise en correspondance des valeurs

La plupart des champs des règles d'autorisation sont compatibles avec tous les schémas correspondants suivants :

  • Correspondance exacte : correspondance de chaîne exacte.
  • Correspondance générique avec le caractère générique "*" :
    • Correspondance de préfixe : chaîne qui se termine par le caractère "*". Par exemple, "test.example.*" correspond à "test.example.com" ou "test.example.com.cn".
    • Correspondance de suffixe : chaîne qui commence par le caractère "*". Par exemple, "*.example.com" correspond à "eng.example.com" ou "test.eng.example.com".
  • Correspondance de présence : pour spécifier qu'un champ doit être présent et non vide, utilisez le format fieldname: ["*"]. Cela diffère de laisser un champ non spécifié, ce qui signifie qu'il correspond à tout, y compris à une valeur vide.

Il existe quelques exceptions. Par exemple, les champs suivants ne sont compatibles qu'avec une correspondance exacte :

  • Le champ key de la section when
  • ipBlocks dans la section source
  • Le champ ports de la section to

L'exemple de règle suivant autorise l'accès aux chemins comportant le préfixe /test/* ou le suffixe */info :

apiVersion: security.istio.io/v1beta1
kind: AuthorizationPolicy
metadata:
  name: tester
  namespace: default
spec:
  selector:
    matchLabels:
      app: products
  action: ALLOW
  rules:
  - to:
    - operation:
        paths: ["/test/*", "*/info"]

Correspondance d'exclusion

Pour faire correspondre des conditions à exclure comme notValues dans le champ when, notIpBlocks dans le champ source ou notPorts dans le champ to, Cloud Service Mesh est compatible avec la correspondance d'exclusion. L'exemple suivant nécessite une requête principals valide, dérivée de l'authentification JWT, si le chemin de la requête n'est pas /healthz. Par conséquent, la règle exclut les requêtes adressées au chemin /healthz depuis l'authentification JWT :

apiVersion: security.istio.io/v1beta1
kind: AuthorizationPolicy
metadata:
  name: disable-jwt-for-healthz
  namespace: default
spec:
  selector:
    matchLabels:
      app: products
  action: ALLOW
  rules:
  - to:
    - operation:
        notPaths: ["/healthz"]
    from:
    - source:
        requestPrincipals: ["*"]

Refuser des requêtes en texte brut

Dans Cloud Service Mesh 1.5 et versions ultérieures, le protocole mTLS automatique est activé par défaut. Le protocole mTLS automatique permet à un proxy side-car client de détecter automatiquement si le serveur possède un side-car. Le side-car client envoie le protocole mTLS aux charges de travail avec des side-cars, et envoie du texte brut aux charges de travail sans side-car. Pour une sécurité optimale, nous vous recommandons d'activer mTLS STRICT.

Si vous ne parvenez pas à activer l'authentification mTLS en mode STRICT pour une charge de travail ou un espace de noms, vous pouvez :

  • créer une règle d'autorisation pour autoriser explicitement le trafic avec une valeur namespaces non vide ou une valeur principals non vide, ou ;
  • refuser le trafic avec les valeurs namespaces ou principals vides.

Étant donné que namespaces et principals ne peuvent être extraits que par une requête mTLS, ces règles rejettent dans les faits tout trafic en texte brut.

La règle suivante refuse la requête si le compte principal de la requête est vide (ce qui est le cas des requêtes en texte brut). La règle autorise les requêtes si le "principal" n'est pas vide. ["*"] indique une correspondance non vide, tandis que l'utilisation de notPrincipals indique une correspondance avec un "principal" vide.

apiVersion: security.istio.io/v1beta1
kind: AuthorizationPolicy
metadata:
  name: require-mtls
  namespace: NAMESPACE
spec:
  action: DENY
  rules:
  - from:
    - source:
        notPrincipals: ["*"]

Priorité des règles d'autorisation

Vous pouvez configurer des règles d'autorisation ALLOW et DENY distinctes, mais vous devez comprendre la priorité des règles et le comportement par défaut pour vous assurer qu'elles fonctionnent comme vous le souhaitez. Le schéma suivant décrit la priorité des règles.

Priorité des règles d'autorisation

Les exemples de règles présentés dans les sections suivantes illustrent certains comportements par défaut et les situations dans lesquelles ils peuvent vous être utiles.

Ne rien autoriser

L'exemple suivant montre une règle ALLOW qui ne correspond à rien. Par défaut, s'il n'existe aucune autre règle ALLOW, les requêtes sont toujours refusées.

apiVersion: security.istio.io/v1beta1
kind: AuthorizationPolicy
metadata:
  name: allow-nothing
spec:
  action: ALLOW

Une bonne pratique de sécurité consiste à commencer par la règle qui n'autorise rien ("allow-nothing") et à ajouter de manière incrémentielle des règles ALLOW pour ouvrir davantage d'accès à une charge de travail.

Refuser tous les accès

L'exemple suivant montre une règle DENY qui correspond à tout. Étant donné que les règles DENY sont évaluées avant les règles ALLOW, toutes les requêtes sont refusées, même si une règle ALLOW correspond à la requête.

apiVersion: security.istio.io/v1beta1
kind: AuthorizationPolicy
metadata:
  name: deny-all
spec:
  action: DENY
  rules:
  - {}

Une règle qui refuse tous les accès ("deny-all") est utile si vous souhaitez désactiver temporairement tout accès à une charge de travail.

Autoriser tous les accès

L'exemple suivant montre une règle ALLOW qui correspond à tout et autorise un accès complet à une charge de travail. La règle "allow-all" rend les autres règles ALLOW inutiles, car elle autorise toujours la requête.

apiVersion: security.istio.io/v1beta1
kind: AuthorizationPolicy
metadata:
  name: allow-all
spec:
  action: ALLOW
  rules:
  - {}

Une règle qui autorise tous les accès ("allow-all") est utile si vous souhaitez exposer temporairement un accès complet à une charge de travail. S'il existe des règles DENY, les requêtes peuvent toujours être refusées puisque les règles DENY sont évaluées avant les règles ALLOW.

Bonnes pratiques

  1. Créez un compte de service Kubernetes pour chaque service et spécifiez le compte de service dans le déploiement. Exemple :

    apiVersion: v1
    kind: ServiceAccount
    metadata:
      name: frontend-sa
      namespace: demo
    ---
    apiVersion: apps/v1
    kind: Deployment
    metadata:
      name: frontend
      namespace:demo
    spec:
      selector:
        matchLabels:
          app: frontend
      template:
        metadata:
          labels:
            app: frontend
        spec:
          serviceAccountName: frontend-sa
        ...
    
  2. Commencez par une règle "allow-nothing", puis ajoutez progressivement des règles ALLOW pour permettre davantage d'accès aux charges de travail.

  3. Si vous utilisez des jetons JWT pour votre service, procédez comme suit :

    1. Créez une règle DENY pour bloquer les requêtes non authentifiées, par exemple :

      apiVersion: security.istio.io/v1beta1
      kind: AuthorizationPolicy
      metadata:
        name: requireJWT
        namespace: admin
      spec:
        action: DENY
        rules:
        -  from:
          - source:
              notRequestPrincipals: ["*"]
      
    2. Appliquer une règle 'allow-nothing".

    3. Définissez des règles ALLOW pour chaque charge de travail. Pour obtenir des exemples, consultez la page Jeton JWT.

Étape suivante

Découvrez les fonctionnalités de sécurité de Cloud Service Mesh :

Pour en savoir plus sur les règles d'autorisation, consultez la documentation d'Istio :