Visão geral da política de autorização

Ao contrário de um aplicativo monolítico que pode estar em execução em um só lugar, os aplicativos de microsserviços distribuídos globalmente fazem chamadas além dos limites da rede. Isso significa mais pontos de entrada nos seus aplicativos e mais oportunidades de ataques mal-intencionados. Como os pods do Kubernetes têm IPs temporários, as regras de firewall tradicionais baseadas em IP não são adequadas para proteger o acesso entre as cargas de trabalho. Em uma arquitetura de microsserviços, é necessária uma nova abordagem de segurança. O Cloud Service Mesh oferece ainda mais recursos para proteger seus aplicativos, com base em recursos de segurança, como contas de serviço do Kubernetes e políticas de segurança do Istio.

Nesta página, os operadores do aplicativo têm uma visão geral do recurso personalizado (CR, da sigla em inglês) AuthorizationPolicy. As políticas de autorização permitem ativar o controle de acesso nas cargas de trabalho nas camadas de aplicativo (L7) e transporte (L3/4). Você configura políticas de autorização para especificar permissões: o que esse serviço ou usuário pode fazer?

Políticas de autorização

As solicitações entre serviços na sua malha (e entre usuários finais e serviços) são permitidas por padrão. Use o recurso personalizado AuthorizationPolicy para definir políticas granulares para as cargas de trabalho. Depois que você aplica as políticas de autorização, o Cloud Service Mesh as distribui para os proxies sidecar. À medida que as solicitações entram em uma carga de trabalho, o proxy sidecar verifica as políticas de autorização para determinar se a solicitação precisa ser permitida ou negada.

Consulte Recursos compatíveis para saber quais campos do CR AuthorizationPolicy são aceitos pela plataforma.

Escopo da política

É possível aplicar uma política a toda a malha de serviço, a um namespace ou a uma carga de trabalho individual.

  • Para aplicar uma política em toda a malha, especifique o namespace raiz, istio-system, no campo metadata:namespace:

    apiVersion: "security.istio.io/v1beta1"
    kind: "AuthorizationPolicy"
    metadata:
      name: "mesh-wide"
      namespace: istio-system
    spec:
    ...
    
  • Para aplicar uma política a um namespace, especifique-o no campo metadata:namespace:

    apiVersion: "security.istio.io/v1beta1"
    kind: "AuthorizationPolicy"
    metadata:
      name: "currencyservice"
      namespace: currencyservice
    spec:
    ...
    
  • Para restringir uma política a uma carga de trabalho específica, inclua um campo selector.

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

Estrutura básica

Uma política de autorização inclui o escopo da política, um action e uma lista de rules:

  • Conforme descrito na seção anterior, o escopo da política pode ser toda a malha, um namespace ou uma carga de trabalho específica. Se você incluí-la, o campo selector especificará o destino da política.

  • O campo action especifica se irá ALLOW ou DENY a solicitação. Se você não especificar uma ação, por padrão, ela será definida como ALLOW. Para maior clareza, recomendamos que você sempre especifique a ação. As políticas de autorização também são compatíveis com ações AUDIT e CUSTOM. A ação AUDIT só tem suporte em algumas plataformas. Consulte Recursos compatíveis para mais detalhes.

  • O rules especifica quando acionar a ação.

    • O campo from nas rules especifica as fontes da solicitação.

    • O campo to nas rules especifica as operações da solicitação.

    • O campo when especifica outras condições necessárias para aplicar a regra.

No exemplo a seguir:

  • A política é aplicada às solicitações para o serviço frontend no namespace demo.

  • As solicitações serão permitidas quando "hello:world" estiver no cabeçalho da solicitação. Caso contrário, as solicitações serão negadas.

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"]

Controle de acesso na operação de solicitação

Controle o acesso a operações de solicitações específicas, como métodos HTTP ou portas TCP, adicionando uma seção to em rules. No exemplo a seguir, apenas os métodos HTTP GET e POST são permitidos para o currencyservice no namespace 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"]

Controle de acesso na identidade autenticada

Nos exemplos anteriores, as políticas permitem solicitações de cargas de trabalho não autenticadas. Se você tiver TLS mútuo STRICT (mTLS) ativado, será possível restringir o acesso com base na identidade da carga de trabalho ou do namespace de origem da solicitação na seção source.

  • Use o campo principals ou notPrincipal para controlar o acesso no nível da carga de trabalho.

  • Use o campo namespaces ou notNamespaces para controlar o acesso no nível do namespace.

Todos os campos anteriores exigem que você tenha o mTLS STRICT ativado. Se não for possível definir o mTLS STRICT, consulte Rejeitar solicitações de texto simples para uma solução alternativa.

Carga de trabalho identificada

No exemplo a seguir, as solicitações para currencyservice são permitidas somente a partir do serviço frontend. As solicitações para currencyservice de outras cargas de trabalho são negadas.

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"]

Para especificar uma conta de serviço, o principals precisa estar no seguinte formato:

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

Se você estiver usando o Cloud Service Mesh no cluster com a AC do Citadel, cluster.local será o domínio de confiança. Em todos os outros casos, PROJECT_ID.svc.id.goog é o domínio de confiança da malha.

Namespace identificado

O exemplo a seguir mostra uma política que nega solicitações se a origem não for o namespace 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"]

Correspondência de valor

A maioria dos campos nas políticas de autorização aceita todos os seguintes esquemas de correspondência:

  • Correspondência exata: correspondência de string exata.
  • Correspondência de caracteres curinga com o caractere curinga "*":
    • Correspondência de prefixo: uma string com um "*" no final. Por exemplo, "test.example.*" corresponde a "test.example.com" ou "test.example.com.cn".
    • Correspondência de sufixo: uma string com um "*" no início. Por exemplo, "*.example.com" corresponde a "eng.example.com" ou "test.eng.example.com".
  • Correspondência de presença: para especificar que um campo precisa estar presente e não vazio, use o formato fieldname: ["*"]. Isso é diferente de deixar um campo não especificado, o que significa corresponder a qualquer coisa, incluindo vazio.

Existem algumas exceções. Por exemplo, os campos a seguir são compatíveis apenas com correspondência exata:

  • O campo key na seção when
  • O ipBlocks na seção source
  • O campo ports na seção to

A política de exemplo a seguir permite acesso em caminhos com o prefixo /test/* ou o sufixo */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"]

Correspondência de exclusão

Para corresponder a condições negativas, como notValues no campo when, notIpBlocks no campo source, notPorts no campo to, o Cloud Service Mesh é compatível com a correspondência de exclusão. O exemplo a seguir requer um principals de solicitação válido, que é derivado da autenticação JWT, se o caminho da solicitação não for /healthz. Assim, a política exclui solicitações para o caminho /healthz da autenticação 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: ["*"]

Rejeitar solicitações de texto simples

No Cloud Service Mesh, o mTLS automático é ativado por padrão. Com o mTLS automático, um proxy sidecar do cliente detecta automaticamente se o servidor tem um sidecar. O sidecar do cliente envia o mTLS para cargas de trabalho com sidecars e envia texto simples para cargas de trabalho sem sidecars. Para ter a melhor segurança, recomendamos ativar o mTLS STRICT.

Se não for possível ativar mTLS com o modo STRICT para uma carga de trabalho ou namespace, você pode:

  • criar uma política de autorização para permitir explicitamente o tráfego com namespaces não vazio ou principals não vazio ou
  • rejeitar tráfego com namespaces ou principals vazios;

Como namespaces e principals só podem ser extraídos com uma solicitação mTLS, essas políticas rejeitam efetivamente qualquer tráfego de texto simples.

A política a seguir negará a solicitação se o principal dela estiver vazio, como é o caso das solicitações de texto simples. A política permitirá solicitações se o principal não estiver vazio. O ["*"] significa uma correspondência não vazia e, quando usado com notPrincipals, significa correspondência no principal vazio.

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

Precedência da política de autorização

É possível configurar políticas de autorização ALLOW e DENY separadas, mas você precisa entender a precedência da política e o comportamento padrão para garantir que elas façam o que você quer. O diagrama a seguir descreve a precedência da política.

precedência da política de autorização

As políticas de exemplo nas seções a seguir ilustram alguns dos comportamentos e situações padrão em que você pode considerá-las úteis.

Não permitir nada

O exemplo a seguir mostra uma política ALLOW que não corresponde a nada. Por padrão, se não houver outras políticas ALLOW, as solicitações serão sempre negadas.

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

É uma boa prática de segurança começar com a política de não permitir nada e adicionar gradualmente outras políticas ALLOW para abrir mais acesso a uma carga de trabalho.

Negar todo o acesso

O exemplo a seguir mostra uma política DENY que corresponde a tudo. Como as políticas DENY são avaliadas antes das políticas ALLOW, todas as solicitações são negadas, mesmo que haja uma política ALLOW que corresponda à solicitação.

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

Esse tipo de política é útil se você quiser desativar temporariamente todo o acesso a uma carga de trabalho.

Permitir todo o acesso

O exemplo a seguir mostra uma política ALLOW que corresponde a tudo e permite acesso total a uma carga de trabalho. A política de permissão total torna outras políticas ALLOW inúteis, porque sempre permite a solicitação.

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

Esse tipo de política é útil se você quiser expor temporariamente o acesso total a uma carga de trabalho. Se houver alguma política DENY, as solicitações ainda poderão ser negadas porque as políticas DENY são avaliadas antes das políticas ALLOW.

Práticas recomendadas

  1. Crie uma conta de serviço do Kubernetes para cada serviço e especifique-a na implantação. Exemplo:

    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. Comece com uma política de não permitir nada e adicione progressivamente outras políticas ALLOW para abrir mais acesso às cargas de trabalho.

  3. Se você estiver usando JWTs para o serviço:

    1. Crie uma política DENY para bloquear solicitações não autenticadas, por exemplo:

      apiVersion: security.istio.io/v1beta1
      kind: AuthorizationPolicy
      metadata:
        name: requireJWT
        namespace: admin
      spec:
        action: DENY
        rules:
        -  from:
          - source:
              notRequestPrincipals: ["*"]
      
    2. Aplique uma política de não permitir nada.

    3. Defina políticas ALLOW para cada carga de trabalho. Para exemplos, consulte Token JWT.

A seguir

Saiba mais sobre os recursos de segurança do Cloud Service Mesh:

Saiba mais sobre as políticas de autorização na documentação do Istio: