Nota
O acesso a esta página requer autorização. Podes tentar iniciar sessão ou mudar de diretório.
O acesso a esta página requer autorização. Podes tentar mudar de diretório.
Neste artigo, você implementa a aplicação Yelb no cluster do Azure Kubernetes Service (AKS) que criou no artigo anterior.
Verifique o ambiente
Antes de implementar a aplicação, certifique-se de que o seu cluster AKS está devidamente configurado utilizando os seguintes comandos:
Liste os namespaces no seu cluster usando o comando
kubectl get namespace.kubectl get namespaceSe instalou o controlador de ingress NGINX usando o complemento de encaminhamento de aplicações, deverá ver o namespace
app-routing-systemno resultado:NAME STATUS AGE app-routing-system Active 4h28m cert-manager Active 109s dapr-system Active 4h18m default Active 4h29m gatekeeper-system Active 4h28m kube-node-lease Active 4h29m kube-public Active 4h29m kube-system Active 4h29mIf you installed the NGINX ingress controller via Helm, you should see the
ingress-basicnamespace in the output:NAME STATUS AGE cert-manager Active 7m42s dapr-system Active 11m default Active 21m gatekeeper-system Active 20m ingress-basic Active 7m19s kube-node-lease Active 21m kube-public Active 21m kube-system Active 21m prometheus Active 8m9sGet the service details of the
app-routing-systemor theingress-basicnamespace using thekubectl get service command.kubectl get service --namespace <namespace-name> -o wideIf you used the application routing add-on, you should see the
EXTERNAL-IPof thenginxservice is a private IP address. Este endereço é o IP privado de uma configuração de IP de frontend no balanceador de carga privadokubernetes-internaldo seu cluster AKS.NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE SELECTOR nginx LoadBalancer 172.16.55.104 10.240.0.7 80:31447/TCP,443:31772/TCP,10254:30459/TCP 4h28m app=nginxSe utilizou o Helm, deverá ver que o
EXTERNAL-IPdo serviçonginx-ingress-ingress-nginx-controlleré um endereço IP privado. This address is the private IP of a frontend IP configuration in thekubernetes-internalprivate load balancer of your AKS cluster.NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE nginx-ingress-ingress-nginx-controller LoadBalancer 172.16.42.152 10.240.0.7 80:32117/TCP,443:32513/TCP 7m31s nginx-ingress-ingress-nginx-controller-admission ClusterIP 172.16.78.85 <none> 443/TCP 7m31s nginx-ingress-ingress-nginx-controller-metrics ClusterIP 172.16.109.138 <none> 10254/TCP 7m31s
Prepare-se para implementar a aplicação Yelb
Se quiser implementar o exemplo usando a abordagem rescisão TLS no Gateway de Aplicação e invocação Yelb via HTTP, pode encontrar os scripts Bash e os modelos YAML para implementar a aplicação Yelb na pasta http.
Se pretender implementar o exemplo utilizando a arquitetura de Implementação de TLS de ponta a ponta com o Azure Application Gateway, pode encontrar os scripts Bash e os modelos YAML para implementar a aplicação web na pasta https.
Nas secções restantes deste artigo, orientamo-lo através do processo de implementação da aplicação de exemplo utilizando a abordagem de TLS de ponta a ponta.
Personalizar variáveis
Antes de executar qualquer script, necessita de personalizar os valores das variáveis no ficheiro
00-variables.sh. Este ficheiro está incluído em todos os scripts e contém as seguintes variáveis:# Azure subscription and tenant RESOURCE_GROUP_NAME="<aks-resource-group>" SUBSCRIPTION_ID="$(az account show --query id --output tsv)" SUBSCRIPTION_NAME="$(az account show --query name --output tsv)" TENANT_ID="$(az account show --query tenantId --output tsv)" AKS_CLUSTER_NAME="<aks-name>" AGW_NAME="<application-gateway-name>" AGW_PUBLIC_IP_NAME="<application-gateway-public-ip-name>" DNS_ZONE_NAME="<your-azure-dns-zone-name-eg-contoso.com>" DNS_ZONE_RESOURCE_GROUP_NAME="<your-azure-dns-zone-resource-group-name>" DNS_ZONE_SUBSCRIPTION_ID="<your-azure-dns-zone-subscription-id>" # NGINX ingress controller installed via Helm NGINX_NAMESPACE="ingress-basic" NGINX_REPO_NAME="ingress-nginx" NGINX_REPO_URL="https://kubernetes.github.io/ingress-nginx" NGINX_CHART_NAME="ingress-nginx" NGINX_RELEASE_NAME="ingress-nginx" NGINX_REPLICA_COUNT=3 # Specify the ingress class name for the ingress controller # - nginx: Unmanaged NGINX ingress controller installed via Helm # - webapprouting.kubernetes.azure.com: Managed NGINX ingress controller installed via AKS application routing add-on INGRESS_CLASS_NAME="webapprouting.kubernetes.azure.com" # Subdomain of the Yelb UI service SUBDOMAIN="<yelb-application-subdomain>" # URL of the Yelb UI service URL="https://$SUBDOMAIN.$DNS_ZONE_NAME" # Secret provider class KEY_VAULT_NAME="<key-vault-name>" KEY_VAULT_CERTIFICATE_NAME="<key-vault-resource-group-name>" KEY_VAULT_SECRET_PROVIDER_IDENTITY_CLIENT_ID="<key-vault-secret-provider-identity-client-id>" TLS_SECRET_NAME="yelb-tls-secret" NAMESPACE="yelb"Pode executar o comando az aks show para obter o
clientIdda identidade gerida atribuída pelo utilizador utilizada pelo Azure Key Vault Provider para Secrets Store CSI Driver. A função de administrador do módulokeyVault.bicepKey Vault deve ser atribuída à identidade gerida do utilizador do suplemento para permitir que recupere o certificado utilizado pelo Kubernetes Ingress, usado para expor oyelb-uiserviço através do controlador de entrada NGINX.az aks show \ --name <aks-name> \ --resource-group <aks-resource-group-name> \ --query addonProfiles.azureKeyvaultSecretsProvider.identity.clientId \ --output tsv \ --only-show-errorsSe implantou a infraestrutura Azure usando os módulos Bicep fornecidos com este exemplo, pode prosseguir para implementar a aplicação Yelb. If you want to deploy the application in your AKS cluster, you can use the following scripts to configure your environment. Pode usar o
02-create-nginx-ingress-controller.shpara instalar o controlador de entrada NGINX com o firewall de aplicações web open-source ModSecurity (WAF) ativado.#!/bin/bash # Variables source ./00-variables.sh # Check if the NGINX ingress controller Helm chart is already installed result=$(helm list -n $NGINX_NAMESPACE | grep $NGINX_RELEASE_NAME | awk '{print $1}') if [[ -n $result ]]; then echo "[$NGINX_RELEASE_NAME] NGINX ingress controller release already exists in the [$NGINX_NAMESPACE] namespace" else # Check if the NGINX ingress controller repository is not already added result=$(helm repo list | grep $NGINX_REPO_NAME | awk '{print $1}') if [[ -n $result ]]; then echo "[$NGINX_REPO_NAME] Helm repo already exists" else # Add the NGINX ingress controller repository echo "Adding [$NGINX_REPO_NAME] Helm repo..." helm repo add $NGINX_REPO_NAME $NGINX_REPO_URL fi # Update your local Helm chart repository cache echo 'Updating Helm repos...' helm repo update # Deploy NGINX ingress controller echo "Deploying [$NGINX_RELEASE_NAME] NGINX ingress controller to the [$NGINX_NAMESPACE] namespace..." helm install $NGINX_RELEASE_NAME $NGINX_REPO_NAME/$nginxChartName \ --create-namespace \ --namespace $NGINX_NAMESPACE \ --set controller.nodeSelector."kubernetes\.io/os"=linux \ --set controller.replicaCount=$NGINX_REPLICA_COUNT \ --set defaultBackend.nodeSelector."kubernetes\.io/os"=linux \ --set controller.service.annotations."service\.beta\.kubernetes\.io/azure-load-balancer-health-probe-request-path"=/healthz fi # Get values helm get values $NGINX_RELEASE_NAME --namespace $NGINX_NAMESPACE
Implantar o aplicativo
Execute o seguinte script
03-deploy-yelb.shpara implementar a aplicação Yelb e um objeto Ingresso do Kubernetes para tornar o serviçoyelb-uiacessível à internet pública.#!/bin/bash # Variables source ./00-variables.sh # Check if namespace exists in the cluster result=$(kubectl get namespace -o jsonpath="{.items[?(@.metadata.name=='$NAMESPACE')].metadata.name}") if [[ -n $result ]]; then echo "$NAMESPACE namespace already exists in the cluster" else echo "$NAMESPACE namespace does not exist in the cluster" echo "creating $NAMESPACE namespace in the cluster..." kubectl create namespace $NAMESPACE fi # Create the Secret Provider Class object echo "Creating the secret provider class object..." cat <<EOF | kubectl apply -f - apiVersion: secrets-store.csi.x-k8s.io/v1 kind: SecretProviderClass metadata: namespace: $NAMESPACE name: yelb spec: provider: azure secretObjects: - secretName: $TLS_SECRET_NAME type: kubernetes.io/tls data: - objectName: $KEY_VAULT_CERTIFICATE_NAME key: tls.key - objectName: $KEY_VAULT_CERTIFICATE_NAME key: tls.crt parameters: usePodIdentity: "false" useVMManagedIdentity: "true" userAssignedIdentityID: $KEY_VAULT_SECRET_PROVIDER_IDENTITY_CLIENT_ID keyvaultName: $KEY_VAULT_NAME objects: | array: - | objectName: $KEY_VAULT_CERTIFICATE_NAME objectType: secret tenantId: $TENANT_ID EOF # Apply the YAML configuration kubectl apply -f yelb.yml echo "waiting for secret $TLS_SECRET_NAME in namespace $namespace..." while true; do if kubectl get secret -n $NAMESPACE $TLS_SECRET_NAME >/dev/null 2>&1; then echo "secret $TLS_SECRET_NAME found!" break else printf "." sleep 3 fi done # Create chat-ingress cat ingress.yml | yq "(.spec.ingressClassName)|="\""$INGRESS_CLASS_NAME"\" | yq "(.spec.tls[0].hosts[0])|="\""$SUBDOMAIN.$DNS_ZONE_NAME"\" | yq "(.spec.tls[0].secretName)|="\""$TLS_SECRET_NAME"\" | yq "(.spec.rules[0].host)|="\""$SUBDOMAIN.$DNS_ZONE_NAME"\" | kubectl apply -f - # Check the deployed resources within the yelb namespace: kubectl get all -n yelbAtualize o manifesto
yelb-uiYAML para incluir a definiçãocsi volumee para ler o certificado como um segredo do Azure Key Vault.
apiVersion: apps/v1
kind: Deployment
metadata:
namespace: yelb
name: yelb-ui
spec:
replicas: 1
selector:
matchLabels:
app: yelb-ui
tier: frontend
template:
metadata:
labels:
app: yelb-ui
tier: frontend
spec:
containers:
- name: yelb-ui
image: mreferre/yelb-ui:0.7
ports:
- containerPort: 80
volumeMounts:
- name: secrets-store-inline
mountPath: "/mnt/secrets-store"
readOnly: true
volumes:
- name: secrets-store-inline
csi:
driver: secrets-store.csi.k8s.io
readOnly: true
volumeAttributes:
secretProviderClass: yelb
Agora pode implementar a aplicação. O script utiliza o
yelb.ymlmanifesto YAML para implementar a aplicação e oingress.ymlpara criar o objeto ingress. Se utilizar uma Zona de DNS Pública do Azure para a resolução de nomes de domínio, pode empregar o script04-configure-dns.sh. Este script associa o endereço IP público do controlador de entrada NGINX com o domínio usado pelo objeto de entrada, que expõe o serviçoyelb-ui. O script executa as seguintes etapas:- Obtém o endereço público do IP público do Azure utilizado pela configuração de IP de front-end do Gateway de Aplicação.
- Verifica se existe um registo
Apara o subdomínio utilizado pelo serviçoyelb-ui. - Se o registo
Anão existir, o script irá criá-lo.
source ./00-variables.sh
# Get the address of the Application Gateway Public IP
echo "Retrieving the address of the [$AGW_PUBLIC_IP_NAME] public IP address of the [$AGW_NAME] Application Gateway..."
PUBLIC_IP_ADDRESS=$(az network public-ip show \
--resource-group $RESOURCE_GROUP_NAME \
--name $AGW_PUBLIC_IP_NAME \
--query ipAddress \
--output tsv \
--only-show-errors)
if [[ -n $PUBLIC_IP_ADDRESS ]]; then
echo "[$PUBLIC_IP_ADDRESS] public IP address successfully retrieved for the [$AGW_NAME] Application Gateway"
else
echo "Failed to retrieve the public IP address of the [$AGW_NAME] Application Gateway"
exit
fi
# Check if an A record for todolist subdomain exists in the DNS Zone
echo "Retrieving the A record for the [$SUBDOMAIN] subdomain from the [$DNS_ZONE_NAME] DNS zone..."
IPV4_ADDRESS=$(az network dns record-set a list \
--zone-name $DNS_ZONE_NAME \
--resource-group $DNS_ZONE_RESOURCE_GROUP_NAME \
--subscription $DNS_ZONE_SUBSCRIPTION_ID \
--query "[?name=='$SUBDOMAIN'].ARecords[].IPV4_ADDRESS" \
--output tsv \
--only-show-errors)
if [[ -n $IPV4_ADDRESS ]]; then
echo "An A record already exists in [$DNS_ZONE_NAME] DNS zone for the [$SUBDOMAIN] subdomain with [$IPV4_ADDRESS] IP address"
if [[ $IPV4_ADDRESS == $PUBLIC_IP_ADDRESS ]]; then
echo "The [$IPV4_ADDRESS] ip address of the existing A record is equal to the ip address of the ingress"
echo "No additional step is required"
continue
else
echo "The [$IPV4_ADDRESS] ip address of the existing A record is different than the ip address of the ingress"
fi
# Retrieving name of the record set relative to the zone
echo "Retrieving the name of the record set relative to the [$DNS_ZONE_NAME] zone..."
RECORDSET_NAME=$(az network dns record-set a list \
--zone-name $DNS_ZONE_NAME \
--resource-group $DNS_ZONE_RESOURCE_GROUP_NAME \
--subscription $DNS_ZONE_SUBSCRIPTION_ID \
--query "[?name=='$SUBDOMAIN'].name" \
--output tsv \
--only-show-errors 2>/dev/null)
if [[ -n $RECORDSET_NAME ]]; then
echo "[$RECORDSET_NAME] record set name successfully retrieved"
else
echo "Failed to retrieve the name of the record set relative to the [$DNS_ZONE_NAME] zone"
exit
fi
# Remove the A record
echo "Removing the A record from the record set relative to the [$DNS_ZONE_NAME] zone..."
az network dns record-set a remove-record \
--ipv4-address $IPV4_ADDRESS \
--record-set-name $RECORDSET_NAME \
--zone-name $DNS_ZONE_NAME \
--resource-group $DNS_ZONE_RESOURCE_GROUP_NAME \
--subscription $DNS_ZONE_SUBSCRIPTION_ID \
--only-show-errors 1>/dev/null
if [[ $? == 0 ]]; then
echo "[$IPV4_ADDRESS] ip address successfully removed from the [$RECORDSET_NAME] record set"
else
echo "Failed to remove the [$IPV4_ADDRESS] ip address from the [$RECORDSET_NAME] record set"
exit
fi
fi
# Create the A record
echo "Creating an A record in [$DNS_ZONE_NAME] DNS zone for the [$SUBDOMAIN] subdomain with [$PUBLIC_IP_ADDRESS] IP address..."
az network dns record-set a add-record \
--zone-name $DNS_ZONE_NAME \
--resource-group $DNS_ZONE_RESOURCE_GROUP_NAME \
--subscription $DNS_ZONE_SUBSCRIPTION_ID \
--record-set-name $SUBDOMAIN \
--ipv4-address $PUBLIC_IP_ADDRESS \
--only-show-errors 1>/dev/null
if [[ $? == 0 ]]; then
echo "A record for the [$SUBDOMAIN] subdomain with [$PUBLIC_IP_ADDRESS] IP address successfully created in [$DNS_ZONE_NAME] DNS zone"
else
echo "Failed to create an A record for the $SUBDOMAIN subdomain with [$PUBLIC_IP_ADDRESS] IP address in [$DNS_ZONE_NAME] DNS zone"
fi
Observação
Antes de implementar a aplicação Yelb e criar o objeto ingress, o script gera um SecretProviderClass para recuperar o certificado TLS do Azure Key Vault e gerar o segredo do Kubernetes para o objeto ingress. It's important to note that the Secrets Store CSI Driver for Key Vault creates the Kubernetes secret containing the TLS certificate only when the SecretProviderClass and volume definition is included in the deployment. Para garantir que o certificado TLS seja devidamente recuperado do Azure Key Vault e armazenado no segredo do Kubernetes utilizado pelo objeto ingress, precisamos fazer as seguintes alterações no manifesto YAML da implementação yelb-ui:
- Add
csi volumedefinition using thesecrets-store.csi.k8s.iodriver, which references theSecretProviderClassobject responsible for retrieving the TLS certificate from Azure Key Vault. - Inclua
volume mountpara ler o certificado como um segredo do Azure Key Vault.
Para mais informações, consulte Configurar Secrets Store CSI Driver para ativar o controlador de ingresso NGINX com TLS.
Testar a aplicação
Utilize o 05-call-yelb-ui.sh script para invocar o serviço yelb-ui, simular injeção de SQL, ataques XSS, e observe como o conjunto de regras gerido do ModSecurity bloqueia pedidos maliciosos.
#!/bin/bash
# Variables
source ./00-variables.sh
# Call REST API
echo "Calling Yelb UI service at $URL..."
curl -w 'HTTP Status: %{http_code}\n' -s -o /dev/null $URL
# Simulate SQL injection
echo "Simulating SQL injection when calling $URL..."
curl -w 'HTTP Status: %{http_code}\n' -s -o /dev/null $URL/?users=ExampleSQLInjection%27%20--
# Simulate XSS
echo "Simulating XSS when calling $URL..."
curl -w 'HTTP Status: %{http_code}\n' -s -o /dev/null $URL/?users=ExampleXSS%3Cscript%3Ealert%28%27XSS%27%29%3C%2Fscript%3E
# A custom rule blocks any request with the word blockme in the querystring.
echo "Simulating query string manipulation with the 'blockme' word in the query string..."
curl -w 'HTTP Status: %{http_code}\n' -s -o /dev/null $URL/?users?task=blockme
O script Bash deve produzir o seguinte resultado, onde a primeira chamada é bem-sucedida, enquanto as regras do ModSecurity bloqueiam as duas chamadas seguintes.
Calling Yelb UI service at https://yelb.contoso.com...
HTTP Status: 200
Simulating SQL injection when calling https://yelb.contoso.com...
HTTP Status: 403
Simulating XSS when calling https://yelb.contoso.com...
HTTP Status: 403
Simulating query string manipulation with the 'blockme' word in the query string...
HTTP Status: 403
Monitorizar a aplicação
Na solução proposta, o processo de implementação configura automaticamente o recurso Azure Application Gateway para coletar logs de diagnóstico e métricas para um espaço de trabalho do Azure Log Analytics Workspace. Ao ativar os registos, pode obter informações valiosas sobre as avaliações, correspondências e bloqueios realizados pelo Azure Web Application Firewall (WAF) dentro do Application Gateway. Mais informações podem ser consultadas em Registos de diagnóstico para Application Gateway. Também pode usar o Log Analytics para examinar os dados nos registos de firewall. Quando você tiver os logs do firewall no espaço de trabalho do Log Analytics, poderá exibir dados, escrever consultas, criar visualizações e adicioná-las ao painel do portal. Para informações detalhadas sobre consultas de registo, consulte Visão geral das consultas de registo no Azure Monitor.
Explore dados com consultas Kusto
Na solução proposta, o processo de implementação configura automaticamente o recurso Azure Application Gateway para recolher registos de diagnóstico e métricas para um espaço de trabalho do Azure Log Analytics. Ao ativar os registos, pode obter informações sobre as avaliações, correspondências e bloqueios realizados pelo Firewall de Aplicações Web Azure (WAF) dentro do Gateway de Aplicação. Para mais informações, consulte Registos de diagnóstico para o Gateway de Aplicações.
Pode também usar o Log Analytics para examinar os dados dentro dos registos de firewall. Quando você tiver os logs do firewall no espaço de trabalho do Log Analytics, poderá exibir dados, escrever consultas, criar visualizações e adicioná-las ao painel do portal. Para mais informações sobre consultas de registo, consulte Visão geral das consultas de registo no Azure Monitor.
AzureDiagnostics
| where ResourceProvider == "MICROSOFT.NETWORK" and Category == "ApplicationGatewayFirewallLog"
| limit 10
Alternatively, when working with the Resource-specific table, the raw firewall log data can be accessed using the following query. Para saber mais sobre tabelas específicas de recursos, consulte a documentação de Referência de dados de monitorização.
AGWFirewallLogs
| limit 10
Assim que tiver os dados, poderá aprofundar-se e criar gráficos ou visualizações. Aqui estão alguns exemplos adicionais de consultas KQL que podem ser utilizadas:
Pedidos correspondidos/bloqueados por IP
AzureDiagnostics
| where ResourceProvider == "MICROSOFT.NETWORK" and Category == "ApplicationGatewayFirewallLog"
| summarize count() by clientIp_s, bin(TimeGenerated, 1m)
| render timechart
Solicitações correspondentes/bloqueadas por URI
AzureDiagnostics
| where ResourceProvider == "MICROSOFT.NETWORK" and Category == "ApplicationGatewayFirewallLog"
| summarize count() by requestUri_s, bin(TimeGenerated, 1m)
| render timechart
Principais regras correspondentes
| where ResourceProvider == "MICROSOFT.NETWORK" and Category == "ApplicationGatewayFirewallLog"
| summarize count() by ruleId_s, bin(TimeGenerated, 1m)
| where count_ > 10
| render timechart
Os cinco principais grupos de regras correspondentes
AzureDiagnostics
| where ResourceProvider == "MICROSOFT.NETWORK" and Category == "ApplicationGatewayFirewallLog"
| summarize Count=count() by details_file_s, action_s
| top 5 by Count desc
| render piechart
Analisar os recursos implementados
Pode utilizar o Azure CLI ou o Azure PowerShell para listar os recursos implementados no grupo de recursos.
List the deployed resources in the resource group using the [az resource list][az-resource-list] command.
az resource list --resource-group <resource-group-name>
Pode utilizar o Azure CLI ou o Azure PowerShell para eliminar o grupo de recursos quando já não precisar dos recursos que criou neste tutorial.
Elimine o grupo de recursos e os seus recursos associados utilizando o comando az group delete.
az group delete --name <resource-group-name>
Próximos passos
Pode aumentar a segurança e proteção contra ameaças da solução usando Azure DDoS Protection e Azure Firewall. Para obter mais informações, consulte os seguintes artigos:
- Tutorial: Protect your application gateway with Azure DDoS Network Protection
- Firewall e Application Gateway para redes virtuais
- Rede de Confiança Zero para aplicações web com Azure Firewall e Application Gateway
If you use the NGINX ingress controller or any other AKS hosted ingress controller in place of the Azure Application Gateway, you can use the Azure Firewall to inspect traffic to and from the AKS cluster and protect the cluster from data exfiltration and other undesired network traffic. Para obter mais informações, consulte os seguintes artigos:
- Use Azure Firewall to protect Azure Kubernetes Service (AKS) clusters
- Use o Azure Firewall para ajudar a proteger um cluster do Azure Kubernetes Service (AKS)
Contribuidores
A Microsoft mantém este artigo. Os seguintes colaboradores escreveram-no originalmente:
Autor principal:
- Paolo Salvatori | Engenheiro Principal de Clientes
Outros contribuidores:
- Ken Kilty | Principal TPM
- Russell de Pina | Principal TPM
- Erin Schaffer | Desenvolvedora de Conteúdo 2