Autenticação sem segredos no AKS com o Azure AD Workload Identity

This post has been republished via RSS; it originally appeared at: New blog articles in Microsoft Community Hub.

Os ambientes em nuvem oferecem diversos recursos que aceleram o desenvolvimento de soluções distribuídas complexas. Mas o aumento da complexidade pode criar, ou intensificar, vários desafios. Por exemplo, a manutenção das credenciais necessárias para aumentar a segurança na comunicação entre os componentes pode se tornar um pesadelo. A expiração de uma única credencial mal gerenciada pode causar a queda de serviços críticos com consequências potencialmente catastróficas.

Nesse artigo veremos como uma funcionalidade do Azure AD e AKS pode nos ajudar a resolver esse desafio.

 

Autenticação sem senhas

Nos últimos anos, Microsoft, Apple e Google vêm trabalhando em tecnologias para permitir a autenticação de seus usuários sem senhas. Além de aumentar a segurança, essa nova forma de autenticação é mais conveniente para os usuários, pois eles não precisam mais memorizar e gerenciar senhas.

Voltando para o desafio de autenticação de aplicações, a Microsoft deu um passo importante com o lançamento do projeto de código aberto Azure AD Workload Identity para o AKS. Com essa tecnologia, suas aplicações Kubernetes podem acessar recursos protegidos sem a necessidade de compartilhar segredos. Para isso, basta que o seu cluster Kubernetes disponibilize um emissor OpenID Connect (OIDC).

 

Como funciona

Nesse modelo de autenticação, o cluster AKS emite um token confiado pelo Azure AD. Após validar esse token, é feita a troca do token emitido pelo AKS por um emitido pelo Azure AD, o que permite que sua aplicação acesse os recursos protegidos.

sequence-1.png

 

 

Como utilizar

Para utilizar o Workload Identity no AKS, precisamos criar um cluster com as funcionalidades de emissor OIDC e Workload Identity habilitadas.

 

  • Os exemplos nesse artigo estão escritos em PowerShell com Azure CLI e C#.
$rg = "<Nome do grupo de recursos criado previamente>"
$aks = "<Nome do cluster AKS>"

az aks create `
    -g $rg `
    -n $aks `
    --tier free `
    --enable-oidc-issuer `
    --enable-workload-identity

# O comando abaixo armazena a URL de configuração do emissor OIDC do AKS na
# variável $oidcConfigURL

$oidcConfigURL = (az aks show `
    -g $rg `
    -n $aks `
    --query "oidcIssuerProfile.issuerUrl" `
    -o tsv)
$oidcConfigURL

Caso o cluster AKS já exista, você pode usar o comando az aks update com as opções enable-oidc-issuer e enable-workload-identity para habilitar essas funcionalidades.

Com o cluster criado, precisamos registrar a aplicação no Azure AD que irá proteger o acesso aos recursos, e associá-la a um service principal:

 

$nomeApp = "<Nome da aplicação>"

az ad app create --display-name $nomeApp
$clientID = (az ad app list --display-name $nomeApp --query [].appId -o tsv)
az ad sp create --id $clientID

O próximo passo é criar a conta de serviço do Kubernetes que será confiada pela aplicação do Azure AD que acabamos de criar.

 

  • A conta de serviço precisa definir a anotação azure.workload.identity/client-id com o client id da aplicação registrada no Azure AD.
  • Os exemplos PowerShell utilizam here-strings para definir strings de múltiplas linhas.
$contaServicoK8s = "<Nome da conta de serviço do Kubernetes>"
$namespaceK8s = "<Nome do namespace do Kubernetes>"

az aks get-credentials -g $rg -n $aks

@"
apiVersion: v1
kind: ServiceAccount
metadata:
  annotations:
    azure.workload.identity/client-id: "$clientID"
  name: "$contaServicoK8s"
  namespace: "$namespaceK8s"
"@ | kubectl apply -f -

# Confirme se a conta de serviço foi criada:
kubectl describe serviceaccounts -n $namespaceK8s $contaServicoK8s

Com as duas identidades criadas, podemos federá-las:

 

@"
{
    "name": "WorkloadIdentityDemo",
    "issuer": "$oidcConfigURL",
    "subject": "system:serviceaccount:$namespaceK8S`:$contaServicoK8s",
    "description": "Workload identity demo",
    "audiences": [
        "api://AzureADTokenExchange"
    ]
}
"@ > parametros.json

az ad app federated-credential create `
    --id $clientID `
    --parameters parametros.json

Remove-Item parametros.json

Com tudo configurado, podemos subir um pod no nosso cluster para verificar se o token da conta de serviço está sendo apresentado corretamente.

 

  • O pod precisa ser configurado para executar na conta de serviço federada e definir o label azure.workload.identity/use com valor true.
@"
apiVersion: v1
kind: Pod
metadata:
  name: nginx
  namespace: $namespaceK8s
  labels:
    azure.workload.identity/use: "true"
spec:
  serviceAccountName: $contaServicoK8s
  containers:
  - name: nginx
    image: nginx:1.14.2
    ports:
    - containerPort: 80
"@ | kubectl apply -f -

kubectl get pod nginx -n $namespaceK8s -o=jsonpath='{.spec.containers[0].env}'

Se tudo deu certo, o último comando retornará as variáveis de ambiente injetadas pelo Azure AD Workload Identity:

 

[
  {
    "name": "AZURE_CLIENT_ID",
    "value": "<guid>"
  },
  {
    "name": "AZURE_TENANT_ID",
    "value": "<guid>"
  },
  {
    "name": "AZURE_FEDERATED_TOKEN_FILE",
    "value": "/var/run/secrets/azure/tokens/azure-identity-token"
  },
  {
    "name": "AZURE_AUTHORITY_HOST",
    "value":"https://login.microsoftonline.com/"
  }
]

 

Como requisitar um token de acesso

Para requisitar um token de acesso, podemos utilizar a biblioteca Azure Identity, que disponibiliza a classe DefaultAzureCredential. Com as informações injetadas pelo Azure AD Workload Identity, essa classe consegue requisitar um token de acesso do Azure AD, como ilustrado no próximo exemplo. Com o token em mãos, basta injetá-lo no cabeçalho Authorization das suas requisições HTTP para ter acesso às APIs protegidas.

 

using Azure.Core;
using Azure.Identity;

var credential = new DefaultAzureCredential();
var context = new TokenRequestContext(new string[] {
        "<Escopo>",
    });
var token = await credential.GetTokenAsync(context);
var jwt = token.Token;

Para consumir um serviço protegido do Azure que o nosso service principal tenha acesso, é possível usar a mesma classe. Isso porque ela é derivada da classe TokenCredential, e grande parte dos clientes disponibilizados pelos SDKs do Azure a aceitam para se autenticar nos serviços.

Por exemplo, se você precisar ler uma configuração do Azure App Configuration, crie o cliente ConfigurationClient com o construtor que aceita o TokenCredential como parâmetro.

 

using Azure.Data.AppConfiguration;
using Azure.Identity;

var credential = new DefaultAzureCredential();
var client = new ConfigurationClient(
new Uri("<Endpoint do App Configuration>"), credential);
var setting = await client.GetConfigurationSettingAsync("chave");
  • Note que em nenhum momento foi necessário compartilhar segredos ou chaves de acesso para ter acesso aos recursos protegidos.

 

Conclusão

Nesse artigo vimos como o Azure AD Workload Identity permite a autenticação de aplicações no seu cluster Kubernetes sem a necessidade de compartilhar segredos. Assim, eliminamos os riscos e custos de manter uma operação para gerenciá-los.

No repositório https://github.com/Azure/azure-workload-identity/tree/main/examples/azure-identity tem exemplos para várias plataformas de desenvolvimento caso tenha interesse em testar essa funcionalidade.

Leave a Reply

Your email address will not be published. Required fields are marked *

*

This site uses Akismet to reduce spam. Learn how your comment data is processed.