O requisito de segurança é muito comum em arquiteturas corporativas, mas é difícil determinar se uma aplicação está segura ou qual é o mínimo necessário. É mais uma jornada do que uma ação específica. Para começar a nossa jornada, vamos criar nosso AKS e ACR totalmente privados dentro de uma rede virtual do Azure.
Escrevi um artigo sobre o AKS, no qual eu falo sobre os conceitos principais e mostro como criar um cluster com um node pool Windows. A ideia foi explorar um cenário comum para aplicações legadas. Se você é novo no AKS, vale a pena conferir.
É muito comum utilizar redes virtuais privadas (VNET) restringindo o acesso à internet. Esse tipo de arquitetura é muito mais segura e desejado pela maioria dos projetos. Porém, para isso, precisamos entender claramente quais redes/sub-redes precisamos e onde cada recurso será criado.
Vamos entender a arquitetura, olhando para o desenho abaixo:
Temos duas VNETs, uma que o próprio AKS criou quando escolhemos o modo de rede kubernet e a outra VNET que criamos manualmente para colocar a VM. Na VNET do AKS, criei uma subnet nova para o “private endpoint” do ACR.
Existem dois pontos de atenção:
Para criar um cluster AKS pelo portal do Azure, no primeiro passo não é necessário selecionar nenhuma configuração especial para proteger o cluster. A configuração especial necessária para isso está na etapa quatro, na aba Network. Nesta seção, podemos escolher a opção de rede “Kubenet” ou “CNI”, conforme mencionado acima. Além disso, existe a opção “Enable private cluster” que deve ser marcada se desejarmos criar um cluster privado.
Um cluster privado usa um endereço IP interno para garantir que o tráfego de rede entre o servidor API e os node pools permaneça apenas em uma rede privada. Saiba mais
Apenas para facilitar o processo, vamos até a aba “Integrations” e provisionamos o ACR, o único detalhe está na camada que precisa ser Premium para posteriormente configurarmos o acesso privado.
Criação do ACR no momento da criação do AKS
Agora temos o AKS com a VNET criada, podemos confirmar no menu network e também podemos verificar que o cluster está privado.
Após o ACR ser provisionado vamos no menu network e desabilitaremos o acesso público ao ACR conforme a imagem abaixo. Deixaremos os serviços do Azure liberados.
Em seguida, na aba “Private Endpoint”, vamos criar um “Private Endpoint” para a subnet do ACR na VNET do AKS. Vale lembrar que estamos utilizando a VNET criada pelo AKS no RG MC_AKS_PRIVADO_AKSPRV01_eastus. Antes de prosseguir, é necessário criar a subnet manualmente na VNET.
Para criar a subnet, acesse a VNET no RG MC_AKS_PRIVADO_AKSPRV01_eastus e clique no menu Subnets para criar uma nova
Utilize os pontos de extremidade privados para se conectar de forma privada a um serviço ou recurso. É importante lembrar que o ponto de extremidade privado deve estar na mesma região da sua rede virtual, mas pode estar em uma região diferente do recurso ao qual você está se conectando por meio do link privado. Saiba mais
Dê uma olhada no Resource Group criado pelo AKS MC_AKS_PRIVADO_AKSPRV01_eastus nele temos a VNET e vários outros recursos importantes como NSGs, DNS etc.
"08e2c034-1768-463f-8444-1122ee88c2ff","Public IP address","East US"
"aks-agentpool-17649214-nsg","Network security group","East US"
"aks-agentpool-17649214-routetable","Route table","East US"
"aks-agentpool-45541675-vmss","Virtual machine scale set","East US"
"aks-VNET-17649214","Virtual network","East US"
"AKSPRV01-agentpool","Managed Identity","East US"
"d6ce2cd6-9633-40f1-b530-9e27554dde80.privatelink.eastus.azmk8s.io","Private DNS zone","Global"
"kube-apiserver","Private endpoint","East US"
"kube-apiserver.nic.a93724b9-006b-4f14-8bbd-a0bb576abfd6","Network Interface","East US"
"kubernetes","Load balancer","East US"
"kubernetes-aafae011874a74f61a036d25d76ed247","Public IP address","East US"
"omsagent-aksprv01","Managed Identity","East US"
"privatelink.azurecr.io","Private DNS zone","Global"
Para testar a conectividade com o AKS e o ACR, vamos precisar de uma máquina JUMP, que é uma VM criada para acessar recursos protegidos por VNETs.
É importante escolher o tipo correto de VM, pois ela será utilizada para processos de conteinerização e é provável que seja necessário usar o Docker. Por isso, é recomendado escolher a família correta de máquinas virtuais. No meu caso, utilizei a máquina Standard D2s v3, com 2 vCPUs e 8 GiB de memória
Para entender melhor essa questão de nested virtualization dê uma olhada nesse artigo Saiba mais
Devemos instalar uma distribuição Linux no WSL. Para isto podemos utilizar os seguintes comandos:
Comando | Descrição |
---|---|
wsl -l -v | Lista as distribuições instaladas no WSL |
wsl –list –online | Lista as distribuições disponíveis para instalação |
wsl –install -d Ubuntu | Instala uma distribuição no WSL |
wsl –set-default-version 2 | Define a versão padrão do WSL |
OBS: Ao criar uma máquina virtual no Portal do Azure, é importante estar atento ao campo ‘Security Type’. O modo ‘Trusted’ pode gerar restrições de segurança que podem impedir a instalação do Docker Desktop. Recomenda-se avaliar cuidadosamente as configurações de segurança antes de prosseguir com a criação da VM, a fim de garantir uma instalação sem problemas.
Primeiro instale a CLI do Azure clicando Instalar a CLI do Azure para Windows | Microsoft Learn
Utilizarei diversos comandos da CLI do Azure, inclusive para instalar a CLI do AKS e para efetuar logon no Azure. Para isto utilize os seguintes comandos:
Fazer login na conta do Azure
az login
Para instalar a CLI do AKS usamos o comando
az aks install-cli
Voce também pode baixar o exe diretamente dessa url Baixar apenas kubectl
Como vamos realizar nossos testes a partir de uma VM que está em uma VNET diferente da VNET do AKS, é necessário configurar o Peering. Essa configuração permitirá que as sub-redes da VNET A, existentes antes do Peering, possam se comunicar com as sub-redes da VNET B. Saiba mais
"acrprv01","Container registry","East US"
"AKS_PRIVADO-VNET","Virtual network","East US"
"AKSPRV01","Kubernetes service","East US"
"jumpprv01","Virtual machine","East US"
"jumpprv01-ip","Public IP address","East US"
"jumpprv01-nsg","Network security group","East US"
"jumpprv01950_z1","Network Interface","East US"
"jumpprv01_OsDisk_1_7e010fb8246a4ea596830d75eb08f346","Disk","East US"
"pe_aks_VNET","Private endpoint","East US"
"pe_aks_VNET-nic","Network Interface","East US"
Para realizar nossos testes, usaremos DNS em vez de IPs. Por isso, é necessário associar as Zonas de DNS Privado criadas para resolver os nomes de domínio azurecr.io e azmk8s.io em IPs na VNET da VM.
Esses recursos foram criados automaticamente e já estão associados à VNET do AKS.
Para realizar a associação, basta acessar a Zona DNS Privada, selecionar o menu ‘Link de rede virtual’ e clicar em ‘Adicionar’. Em seguida, selecione a VNET da VM.
Tela do Azure Private Dns Zone azmk8s.io
Para realizar a associação, basta acessar a Zona DNS Privada, selecionar o menu ‘Link de rede virtual’ e clicar em ‘Adicionar’. Em seguida, selecione a VNET da VM.
Tela do Azure Associação do azmk8s.io com VNET do AKS e da VM
Depois disso estamos com o Ambiente pronto e nosso próximo passo é fazer um deploy no AKS.
Conectando no AKS
az aks get-credentials --resource-group AKS_PRIVADO --name AKSPRV01
Precisamos conseguir listar os nodes do AKS para saber que a comunicação com o AKS funcionou corretamente
kubectl get nodes
Vou subir uma aplicação .net core então será necessário ter o SDK do .net core instalada na máquina também essa aplicação tem esse dockerFile
# Stage 1
FROM mcr.microsoft.com/dotnet/core/sdk:3.1 AS build
WORKDIR /build
COPY . .
RUN dotnet restore
RUN dotnet publish -c Release -o /app
# Stage 2
FROM mcr.microsoft.com/dotnet/core/aspnet:3.1 AS final
WORKDIR /app
COPY --from=build /app .
ENTRYPOINT ["dotnet", "Sample.Api.dll"]
Tem uma cópia da API nesse git, clone esse projeto vá até a pasta dele e rode o comando abaixo para gerar uma imagem
docker build -t sampleapi:dev01 .
Depois vamos gerar uma tag
docker tag sampleapi:dev01 acrprv01.azurecr.io/sampleapi:latest
Precisamos fazer o Login no ACR
az acr login -n acrprv01.azurecr.io
E agora podemos subir a imagem no ACR
docker push acrprv01.azurecr.io/sampleapi:latest
Feito isso já podemos gerar nossos arquivos de manifestos para fazer o deploy no AKS vou usar um comando que gerar o arquivo pronto apontando para a imagem.
kubectl create deploy sampleapi --image=acrprv01.azurecr.io/sampleapi:latest --dry-run=client -o yaml > sampleapi.yaml
Aplica o Deploy
kubectl create -f .\\sampleapi.yaml
Gerar arquivo de manifesto para o serviço por enquanto vou usar um ip público mas isso não é o final
kubectl expose -f sampleapi.yaml --name=sampleapisvc --type=LoadBalancer --port=80 --target-port=80 --dry-run=client -o yaml > svcsampleapi.yaml
aplica o Deploy
kubectl create -f .\\svcsampleapi.yaml
Se tudo deu certo você precisa ver os pods rodando e o serviço criado com o IP externo que você vai usar para acessar a aplicação
ao rodar o comando baixo
kubectl get pods
precisamos ver algo com isso
NAME READY STATUS RESTARTS AGE
sampleapi-b87d78d46-wdts5 1/1 Running 0 30m
e para descobrir o IP público usamos
kubectl get services
e precisamos de algo como isso
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE
kubernetes ClusterIP 10.0.0.1 <none> 443/TCP 18h
sampleapisvc LoadBalancer 10.0.68.139 20.232.252.49 80:32246/TCP 26m
Por fim, conseguimos acessar a aplicação pelo IP público. No entanto, é importante lembrar que isso não é ideal. O recomendado é criar uma camada adicional de segurança em frente ao AKS e mantê-lo sem acesso público. Para isso, podemos utilizar, por exemplo, o Application Gateway. Ele terá um IP público, mas também estará em uma VNET que pode se comunicar com a VNET do AKS, mantendo tudo seguro.
Caso você não queira instalar o Docker em sua máquina de JUMP, é possível usar o próprio ACR para compilar suas imagens. Para isso, será necessário configurar um agente e utilizá-lo para a compilação das imagens.
Começamos pegando o id da subnet
$subnetId= az network vnet subnet list --resource-group AKS_PRIVADO --vnet-name AKS_PRIVADO-VNET --query "[0].id" --output tsv
Depois criando o agent
az acr agentpool create --registry acrprv01 --name myagentpool --tier S1 --subnet-id "/subscriptions/60701f8d-0759-4bb3-8d6b-1f1810aef353/resourceGroups/AKS_PRIVADO/providers/Microsoft.Network/virtualNetworks/AKS_PRIVADO-VNET/subnets/default"
E agora rodando ACR buid com o agent criado
az acr build -t sampleapiacr --agent-pool myagentpool --registry acrprv01 .
Podemos ver o agentes criados pelo portal do Azure
Podemos listar as imagens do ACR
az acr repository list -n acrprv01
[
"sampleapi",
"sampleapiacr"
]
Fiz uma alteração interessante: ao invés de utilizar o LoadBalancer e expor um IP público para acessar a aplicação no AKS, criei um Ingress Controller para o Application Gateway, deixando tudo privado de ponta a ponta e ganhando todas as funcionalidades de um Gateway de camada 7 como roteamento com base em atributos adicionais de uma solicitação HTTP, por exemplo, caminho de URI ou cabeçalhos de host. Dessa forma, podemos remover o serviço sampleapisvc usando o comando abaixo.
kubectl delete service sampleapisvc
Deletado o serviço vamos começar as configurações no AKS em Settings/network habilitando o Application gateway:
Para fazer um deploy de ingress privado devemos logo depois de integrar o AKS com o APGW criar um IP em Frontend IP configurations.
Ao clicar nesse item será necessário atribuir um IP manualmente marcando a opção Choose a specific private IP address.
Basicamente eu escolhi um IP da subnet do gateway que no meu caso foi essa rede 10.225.0.0/16 então botei o 10.225.0.10.
Para criar um ingress, é necessário associá-lo a um serviço do tipo ClusterIP. Essa associação pode ser realizada por meio da linha de comando (CLI)
kubectl expose deployment sampleapi --type=ClusterIP --port=80 --target-port=80
Vale ressaltar que ‘sample api’ refere-se ao deployment da aplicação que se deseja acessar.
kubectl get services
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE
kubernetes ClusterIP 10.0.0.1 <none> 443/TCP 3h1m
sampleapi ClusterIP 10.0.135.190 <none> 80/TCP 18m
Em seguida, criei o manifesto ‘deploymentingress.yaml’, apontando-o para o serviço do tipo ClusterIP ‘sampleapi’.
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
name: sampleapi
annotations:
kubernetes.io/ingress.class: azure/application-gateway
appgw.ingress.kubernetes.io/use-private-ip: "true"
spec:
rules:
- http:
paths:
- path: /
backend:
service:
name: sampleapi
port:
number: 80
pathType: Exact
aplicar o deploy
kubectl apply -f .\\deploymentingress.yaml
Observe que agora o ingress ficou atrelado ao ip privado do gateway
kubectl get ingress
NAME CLASS HOSTS ADDRESS PORTS AGE
aspnetappv2 <none> \* 10.225.0.15 80 42m
O serviço pode ser acessado de dentro da VNET ou de outras VNETs que possuam peering com a VNET do AKS. Para expor o serviço de forma segura, uma boa opção é utilizar um Azure API Management em uma VNET com peering na VNET do AKS, mantendo assim o AKS totalmente privado e protegido.
O uso de containers e orquestradores como o AKS pode melhorar significativamente a disponibilidade e a resiliência de nossas aplicações. No entanto, é fundamental considerar os requisitos de segurança desde o início do projeto. É importante notar que, para atingir nossos objetivos, novos componentes do Azure são necessários, como VNETs, SUBNETS, Application Gateway, Private DNS Zones, entre outros, como o APIM. É essencial compreender que dificilmente um único recurso do Azure atenderá a todos os requisitos de nosso negócio. Portanto, é imprescindível entender como diferentes componentes podem nos ajudar a projetar arquiteturas corporativas mais robustas e seguras.
You must be a registered user to add a comment. If you've already registered, sign in. Otherwise, register and sign in.