Migração do OpenShift para o GKE Enterprise: como migrar as restrições de contexto de segurança do OpenShift para o GKE Enterprise

Last reviewed 2022-01-24 UTC

Este documento ajuda você a planejar a migração de políticas de segurança das restrições de contexto de segurança (SCCs, na sigla em inglês) do OpenShift definidas em um cluster do OpenShift de origem para um cluster de destino do GKE. A implementação usa restrições do Controlador de Políticas para definir as políticas migradas no cluster de destino.

Para seguir este documento, é necessário ter familiaridade com a página Como migrar contêineres para o Google Cloud: como migrar do OpenShift para o GKE Enterprise. Ele pressupõe que você esteja familiarizado com o OpenShift e as restrições de contexto de segurança, e tenha acesso a um cluster de origem do OpenShift e a um cluster de destino do GKE.

Este documento faz parte de uma série sobre a migração para o Google Cloud. Para uma visão geral da série, consulte Migração para o Google Cloud: como escolher o caminho de migração.

Este documento faz parte de uma série que discute a migração de contêineres para o Google Cloud:

Este documento é útil se você planeja migrar as SCCs do OpenShift para o GKE Enterprise. É útil, além disso, se estiver considerando a oportunidade de migrar e quiser saber como funciona esse processo.

Este documento depende dos conceitos abordados em Migração para o Google Cloud: primeiros passos, em Como migrar contêineres para o Google Cloud: como migrar o Kubernetes para o GKE, em Como migrar contêineres para o Google Cloud: como migrar do OpenShift para o GKE Enterprise e em Práticas recomendadas para a rede do GKE. Eles incluem links para esses documentos quando necessário.

SCCs do OpenShift

As SCCs são recursos específicos do OpenShift usados para definir políticas para pods que especificam as ações que um pod pode realizar e quais recursos ele pode acessar em nós. Quando você faz uma solicitação de API para criar um pod, as SCCs avaliam as solicitações de acordo com os privilégios de processo em relação a um conjunto de políticas definidas por meio do SCC. As SCCs avaliam as solicitações para permitir ou proibir a execução de pods de acordo com as políticas configuradas. Para mais informações sobre as SCCs do OpenShift, consulte Como gerenciar restrições de contexto de segurança.

SCCs padrão do OpenShift

Os clusters do OpenShift 4.x contêm um conjunto de SCCs padrão descritos na postagem do blog Como gerenciar SCCs no OpenShift da Red Hat.

Config Sync e Policy Controller.

Nesta seção, descrevemos o Config Sync e o Controlador de Políticas. Nesta seção, você encontra links para a documentação e as orientações relevantes para configurar o Controlador de Políticas para realizar as tarefas de migração descritas mais adiante neste documento.

Config Sync

O Config Sync permite usar um repositório comum compatível com Git para definir de forma centralizada a configuração de qualquer recurso que se aplique a qualquer cluster do Kubernetes gerenciado pelo GKE Enterprise. Aplique essa configuração a vários clusters.

Controlador de Políticas

O Controlador de Políticas é um controlador de admissão dinâmico do Kubernetes que verifica, audita e aplica a conformidade dos clusters em relação às políticas definidas centralmente. O Policy Controller é baseado no projeto de código aberto Open Policy Agent (OPA) Gatekeeper.

Configuração do Config Sync e do Controlador de Políticas

Para se preparar para implementar políticas de segurança que espelham as SCCs do OpenShift, ative o Config Sync e o Controlador de Políticas para cada um dos clusters de destino. Esta seção descreve como configurar esses componentes. A seção Migrar SCCs do OpenShift mais adiante neste documento descreve como usar modelos de restrição do Controlador de Políticas para implementar as políticas de segurança.

Ao configurar o Policy Controller, é recomendável colocar namespaces relacionados ao sistema que não executam pods de aplicativos no campo Namespaces isentos. A isenção de namespaces relacionados ao sistema ajuda a evitar o risco de bloquear qualquer pod do sistema que exija privilégios elevados. Os namespaces relacionados ao sistema em um cluster do GKE podem incluir o seguinte:

  • kube-system
  • kube-public
  • gke-connect
  • gke-system
  • config-management-system
  • config-management-monitoring
  • gatekeeper-system
  • istio-system
  • cnrm-system
  • knative-serving
  • monitoring-system

Depois de configurar o Policy Controller com as exceções anteriores, exclua os namespaces do aplicativo de restrições adicionando o rótulo admission.gatekeeper.sh/ignore=true a cada um deles. Se você não adicionar o rótulo a cada namespace, os pods do sistema (e, portanto, todo o cluster) poderão ser afetados por políticas restritivas.

Migrar SCCs do OpenShift para restrições do Controlador de Políticas

Nesta seção, descrevemos como exportar SCCs do cluster do OpenShift e configurar as restrições do GKE Enterprise Policy Controller de destino para corresponder às políticas necessárias. Nesta seção, também descrevemos algumas diferenças entre as restrições de SCCs e do Controlador de Políticas para poder planejar a migração.

Avaliar SCCs do OpenShift

Para exportar uma lista e a configuração das SCCs instaladas no cluster do OpenShift, use os seguintes comandos:

  1. Veja uma lista de todas as SCCs:

    oc get scc
    
  2. Exporte a configuração de cada SCC:

    oc get scc SCC_NAME > SCC_NAME.yaml
    

    Substitua SCC_NAME pelo nome do SCC para o qual você quer exportar a configuração.

Depois de exportar a configuração, é possível analisá-la e usar a tabela na seção Mapear SCCs do OpenShift para configurar as restrições do Policy Controller que correspondem à segurança do seu aplicativo requisitos.

Mapear as SCCs do OpenShift para os modelos de restrições do Policy Controller

A tabela a seguir fornece as restrições e as configurações do Policy Controller que correspondem aos campos do SCC do OpenShift e os valores possíveis. Use a tabela para ajudar a configurar as restrições do Policy Controller de destino que correspondem aos requisitos de segurança do aplicativo que foram implementados por meio das SCCs do OpenShift no ambiente de origem. A seção Exemplo de migração completa mais adiante neste documento fornece um exemplo de como usar as informações na tabela.

Campo "SCC" do OpenShift Tipo / valores possíveis Modelo de restrição do Controlador de Políticas Especificação de restrição do Controlador de Políticas
allowPrivilegedContainer: Booleano K8sPSPPrivilegedContainer Impede contêineres privilegiados, se aplicados.
allowHostIPC: Booleano K8sPSPHostNamespace Impede o acesso ao namespace do host pid e ipc, se aplicado.
allowHostPID: Booleano K8sPSPHostNamespace Impede o acesso ao namespace do host pid e ipc, se aplicado.
allowHostNetwork: Booleano K8sPSPHostNetworkingPorts Tem um parâmetro booleano para impedir o acesso à rede do host e pode definir um intervalo para portas de host acessíveis.
allowHostPorts: Booleano K8sPSPHostNetworkingPorts Tem um parâmetro booleano para impedir o acesso à rede do host e pode definir um intervalo para portas de host acessíveis.
readOnlyRootFilesystem: Booleano K8sPSPReadOnlyRootFilesystem Permite ativar o sistema de arquivos raiz do contêiner somente como leitura, se aplicado.
allowPrivilegeEscalation: true Booleano K8sPSPAllowPrivilegeEscalationContainer Impede que os pods com contexto de segurança AllowPrivilegeEscalation definido como verdadeiro, se aplicado.
allowHostDirVolumePlugin: Booleano K8sPSPVolumeTypes Tem um parâmetro para definir a lista de tipos de volume permitidos (como no SCC), incluindo o diretório de host.
volumes: Lista de matrizes com os tipos de volumes permitidos K8sPSPVolumeTypes Tem um parâmetro para definir a lista de tipos de volume permitidos (como no SCC), incluindo o diretório de host.
allowedCapabilities: Lista de matrizes de recursos do Linux que podem ser solicitados. K8sPSPCapabilities Tem parâmetros para definir os recursos do Linux que podem ser solicitados (allowedCapabilities) e que são proibidos (requiredDropCapabilites).

Não pode ser usado para adicionar ou remover diretamente os recursos listados, como pode ser feito em defaultAddCapabilities: e requiredDropCapabilities: em SCCs do OpenShift.

defaultAddCapabilities: Lista de matrizes de recursos do Linux que precisam ser adicionados a cada contêiner. K8sPSPCapabilities Tem parâmetros para definir os recursos do Linux que podem ser solicitados (allowedCapabilities) e que são proibidos (requiredDropCapabilites).

Não pode ser usado para adicionar ou remover diretamente os recursos listados, como pode ser feito em defaultAddCapabilities: e requiredDropCapabilities: em SCCs do OpenShift.

requiredDropCapabilities: Lista de matrizes de recursos do Linux que são descartados automaticamente do pod ou do contêiner. K8sPSPCapabilities Tem parâmetros para definir os recursos do Linux que podem ser solicitados (allowedCapabilities) e que são proibidos (requiredDropCapabilites).

Não pode ser usado para adicionar ou remover diretamente os recursos listados, como pode ser feito em defaultAddCapabilities: e requiredDropCapabilities: em SCCs do OpenShift.

fsGroup: Tem um type: key que pode ser um dos seguintes:
  • MustRunAs: requer pelo menos um intervalo a ser especificado se não estiver usando valores pré-alocados.
  • RunAsAny: permite que qualquer ID fsGroup seja especificado.
K8sPSPAllowedUsers Permite definir regras que têm uma função semelhante para type: key nos intervalos SCC e id para runAsUser, runAsGroup, supplementalGroups e Parâmetros fsGroup.

Pode ser usado para definir intervalos permitidos para grupos de usuários, grupos complementares ou FS, mas não para definir o ID do usuário diretamente no pod como pode ser feito em SCCs do OpenShift.

runAsUser: Tem um type: key que pode ser um dos seguintes:
  • MustRunAs: requer a execução de um runAsUser.
  • MustRunAsRange: requer a definição dos valores mínimo e máximo se não estiver usando valores pré-alocados do namespace.
  • MustRunAsNonRoot: exige que o pod seja enviado com um runAsUser diferente de zero ou que a diretiva USER esteja definida na imagem.
  • RunAsAny: permite que qualquer runAsUser seja especificado.
K8sPSPAllowedUsers Permite definir regras que têm uma função semelhante para type: key nos intervalos SCC e id para runAsUser, runAsGroup, supplementalGroups e Parâmetros fsGroup.

Pode ser usado para definir intervalos permitidos para grupos de usuários, grupos complementares ou FS, mas não para definir o ID do usuário diretamente no pod como pode ser feito em SCCs do OpenShift.

supplementalGroups: Tem um type: key que pode ser um dos seguintes:
  • MustRunAs: exige pelo menos um intervalo a ser especificado se não estiver usando valores pré-alocados do namespace
  • RunAsAny: permite que qualquer supplementalGroups seja especificado.
K8sPSPAllowedUsers Permite definir regras que têm uma função semelhante para type: key nos intervalos SCC e id para runAsUser, runAsGroup, supplementalGroups e Parâmetros fsGroup.

Pode ser usado para definir intervalos permitidos para grupos de usuários, grupos complementares ou FS, mas não para definir o ID do usuário diretamente no pod como pode ser feito em SCCs do OpenShift.

seLinuxContext: Tem um type: key que pode ser um dos seguintes:
  • MustRunAs: requer que seLinuxOptions seja configurado se não estiver usando valores pré-alocados do namespace.
  • RunAsAny: permite que qualquer seLinuxOptions seja especificado.
K8sPSPSELinuxV2 Tem um parâmetro allowedSELinuxOptions em que você pode definir o nível, papel, tipo e usuário seLinuxOptions permitidos.

Diferenças entre as SCCs do OpenShift e as restrições do Policy Controller

Esta seção descreve algumas diferenças entre as restrições do Policy Controller e as SCCs do OpenShift. Considere essas diferenças antes de usar a tabela anterior para implantar restrições no ambiente de destino.

Como as restrições são aplicadas aos recursos

É possível atribuir SCCs do OpenShift a usuários e grupos usando a especificação users: ou group: presente no objeto SCC. Com o OpenShift 4.x e versões mais recentes, também é possível atribuir SCCs a usuários ou grupos usando controle de acesso baseado em papéis (RBAC, na sigla em inglês). As SCCs também têm um campo priority: que é usado para ordenar as SCCs aplicadas a um pod.

As restrições do Controlador de Políticas são aplicadas a clusters de destino, namespaces ou pods usando seletores de recursos específicos na restrição, em vez de segmentar o usuário ou a conta de serviço. Para mais informações, consulte a documentação do Policy Controller. Usar os seletores de recursos específicos ajuda a garantir que o pod se comporte da mesma forma com um usuário de baixo privilégio usando uma ferramenta de implantação ou um administrador de cluster o inicia na linha de comando.

As restrições do Policy Controller também são compatíveis com o modo de simulação, que permite testar políticas e auditar violações antes da aplicação real. O uso desse modo ajuda a evitar o impacto nas cargas de trabalho atuais, enquanto as SCCs são sempre aplicadas, se aplicáveis ao usuário.

Mutação do pod SCC usando valores pré-alocados em namespaces do OpenShift

Nas SCCs do OpenShift, é possível alterar o contexto de segurança relacionado de cada pod em que o SCC é aplicado com um ID específico de um intervalo pré-alocado fornecido por anotações em namespaces. Para isso, use os campos RunAsUser, fsGroup, supplementalGroups e seLinuxContext com o tipo de estratégia MustRunAs ou MustRunAsRange.

Por exemplo, considere uma SCC restricted que tenha um campo RunAsUser com um tipo de estratégia MustRunAsRange sem intervalo definido no SCC. Nesse cenário, cada pod a que o SCC se aplica recebe um ID RunAsUser do intervalo especificado na anotação openshift.io/sa.scc.uid-range no namespace do pod.

As restrições do Controlador de Políticas e os recursos de mutação fornecem validação e mutação do pod. No entanto, as restrições não usam anotações em namespaces para fornecer valores para contextos de segurança do pod. Na próxima seção, Exemplo de migração completa, fornecemos um exemplo de como as equipes de entrega de aplicativos precisam configurar explicitamente os contextos de segurança nos pods para obedecer restrições que implementam restrições semelhantes às listadas anteriormente.

Exemplo de migração de ponta a ponta

Esta seção contém um exemplo de arquivo de manifesto de destino que inclui todas as restrições e mutadores do Controlador de Políticas necessários para mapear as seguintes SCCs padrão do OpenShift no cluster de destino do GKE:

  • privileged
  • anyuid
  • nonroot
  • restricted

Dependendo do namespace em que um pod é executado, o pod recebe restrições de controlador de políticas diferentes ao mapear as políticas de SCC definidas em um ambiente de código aberto do OpenShift:

  • As cargas de trabalho que precisam do acesso mais privilegiado, como a capacidade de executar no modo privilegiado ou acessar qualquer recurso host, precisam ser executadas em um dos namespaces isentos definidos na configuração do Policy Controller.

    Nenhuma restrição é aplicada aos namespaces isentos. As cargas de trabalho com esse acesso privilegiado são os componentes do sistema ou qualquer carga de trabalho em que o SCC privilegiado foi aplicado ao ambiente de origem do OpenShift.

  • Todos os pods criados em um namespace não isento recebem as restrições mais restritivas. Essas restrições negam o acesso a todos os recursos do host e exigem que os pods sejam executados com um UID que faça parte de um intervalo específico. Essa configuração corresponde às políticas aplicadas pelo SCC restricted do OpenShift. As exceções a essa configuração incluem:

    • Os pods criados em um namespace que têm o rótulo security=anyuid recebem as restrições restritivas anteriores, mas podem ser executados com qualquer UID e qualquer GID. Isso corresponde às restrições do SCC anyuid no OpenShift.
    • Os pods criados em um namespace com o rótulo security=nonroot recebem as restrições restritivas anteriores. No entanto, os pods podem ser executados com qualquer UID não raiz. Isso corresponde às restrições do SCC nonroot no OpenShift.

Exemplo de manifesto de destino

Veja a seguir um exemplo de um manifesto único que inclui um conjunto de restrições e mutações do controlador de políticas que correspondem ao comportamento descrito no exemplo anterior de migração de ponta a ponta. Recomendamos que você analise e ajuste as restrições ou o escopo delas neste exemplo com base nas necessidades da sua organização.

apiVersion: constraints.gatekeeper.sh/v1beta1
kind: K8sPSPHostNamespace
metadata:
  name: psp-host-namespace
spec:
  match:
    kinds:
      - apiGroups: [""]
        kinds: ["Pod"]
---
apiVersion: constraints.gatekeeper.sh/v1beta1
kind: K8sPSPHostNetworkingPorts
metadata:
  name: psp-host-network-ports
spec:
  match:
    kinds:
      - apiGroups: [""]
        kinds: ["Pod"]
  parameters:
    hostNetwork: false
---
apiVersion: constraints.gatekeeper.sh/v1beta1
kind: K8sPSPPrivilegedContainer
metadata:
  name: psp-privileged-container
spec:
  match:
    kinds:
      - apiGroups: [""]
        kinds: ["Pod"]
---
apiVersion: mutations.gatekeeper.sh/v1alpha1
kind: Assign
metadata:
  name: restricted-capabilities
spec:
  applyTo:
  - groups: [""]
    kinds: ["Pod"]
    versions: ["v1"]
  match:
    scope: Namespaced
    kinds:
    - apiGroups: ["*"]
      kinds: ["Pod"]
    namespaceSelector:
      matchExpressions:
        - operator: NotIn
          key: security
          values: ["anyuid"]
  location: "spec.containers[name:*].securityContext.capabilities.drop"
  parameters:
    assign:
      value: ["KILL","MKNOD","SYS_CHROOT"]
---
apiVersion: constraints.gatekeeper.sh/v1beta1
kind: K8sPSPCapabilities
metadata:
  name: restricted-capabilities
spec:
  match:
    kinds:
      - apiGroups: [""]
        kinds: ["Pod"]
    namespaceSelector:
      matchExpressions:
        - operator: NotIn
          key: security
          values: ["anyuid"]
  parameters:
    requiredDropCapabilities: ["KILL","MKNOD","SYS_CHROOT"]
---
apiVersion: mutations.gatekeeper.sh/v1alpha1
kind: Assign
metadata:
  name: anyuid-capabilities
spec:
  applyTo:
  - groups: [""]
    kinds: ["Pod"]
    versions: ["v1"]
  match:
    scope: Namespaced
    kinds:
    - apiGroups: ["*"]
      kinds: ["Pod"]
    namespaceSelector:
      matchExpressions:
        - operator: In
          key: security
          values: ["anyuid"]
  location: "spec.containers[name:*].securityContext.capabilities.drop"
  parameters:
    assign:
      value: ["MKNOD"]
---
apiVersion: constraints.gatekeeper.sh/v1beta1
kind: K8sPSPCapabilities
metadata:
  name: anyuid-capabilities
spec:
  match:
    kinds:
      - apiGroups: [""]
        kinds: ["Pod"]
    namespaceSelector:
      matchExpressions:
        - operator: In
          key: security
          values: ["anyuid"]
  parameters:
    requiredDropCapabilities: ["MKNOD"]
---
apiVersion: constraints.gatekeeper.sh/v1beta1
kind: K8sPSPAllowedUsers
metadata:
  name: restricted-users-and-groups
spec:
  match:
    kinds:
      - apiGroups: [""]
        kinds: ["Pod"]
    namespaceSelector:
      matchExpressions:
        - operator: NotIn
          key: security
          values: ["anyuid","nonroot"]
  parameters:
    runAsUser:
      rule: MustRunAs # MustRunAsNonRoot # RunAsAny
      ranges:
        - min: 1000
          max: 2000
    fsGroup:
      rule: MustRunAs # MayRunAs # RunAsAny
      ranges:
        - min: 1000
          max: 2000
---
apiVersion: constraints.gatekeeper.sh/v1beta1
kind: K8sPSPAllowedUsers
metadata:
  name: nonroot-users-and-groups
spec:
  match:
    kinds:
      - apiGroups: [""]
        kinds: ["Pod"]
    namespaceSelector:
      matchExpressions:
        - operator: In
          key: security
          values: ["nonroot"]
  parameters:
    runAsUser:
      rule: MustRunAsNonRoot
    fsGroup:
      rule: MustRunAsNonRoot
---
apiVersion: constraints.gatekeeper.sh/v1beta1
kind: K8sPSPVolumeTypes
metadata:
  name: psp-volume-types
spec:
  match:
    kinds:
      - apiGroups: [""]
        kinds: ["Pod"]
  parameters:
    volumes:
      - configMap
      - downwardAPI
      - emptyDir
      - nfs
      - persistentVolumeClaim
      - projected
      - secret

A restrição restricted-users-and-groups no manifesto de exemplo usa o modelo K8sPSPAllowedUsers para definir explicitamente um intervalo de exemplo de 1.000 a 2.000 para os parâmetros runAsUser: e fsGroup:. Qualquer pod que não esteja definido para usar um ID nesse intervalo para runAsUser: e fsGroup: é bloqueado.

O GKE e o Kubernetes não usam anotações de namespace para transformar automaticamente os pods com um usuário específico ou um ID de grupo. Portanto, para limitar o intervalo do UID, como no exemplo anterior, suas equipes de entrega de aplicativos precisam definir explicitamente um UID compatível no pod criado, ou você precisa remover completamente a restrição para permitir qualquer ID de dados.

Veja a seguir um exemplo de um manifesto de pod que está em conformidade com as restrições anteriores em qualquer namespace criado (o manifesto é compatível com o SCC restricted):

apiVersion: v1
kind: Pod
metadata:
  name: restricted-pod-example
spec:
  securityContext:
    runAsUser: 1000
    fsGroup: 1100
  volumes:
  - name: sec-ctx-vol
    emptyDir: {}
  containers:
  - name: sec-ctx-demo
    image: busybox
    command: [ "sh", "-c", "sleep 1h" ]
    volumeMounts:
    - name: sec-ctx-vol
      mountPath: /data/demo

A seguir