Entenda de forma técnica como expor serviços HTTP, TCP e UDP no Network Load Balancer e NGINX Ingress Controller no AWS EKS. - Artigo de Leandro Damascena

Por Lendro Damascena

Expondo serviços HTTP, TCP e UDP no Network Load Balancer (com TLS Termination) e NGINX Ingress Controller no AWS EKS.

Antes de começarmos a conversa técnica, é preciso entender quais são os requisitos técnicos dessa demanda e o motivo pelo qual foi adotado o AWS Network Load Balancer com NGINX Ingress Controller.

Os requisitos:

1. Payload com dezenas/centenas de MB;
2. IP estático para controle de firewall da rede corporativa do cliente. Por isso a escolha do Network Load Balancer;
3. Alto throughput. Mais 1 ponto para o Network Load Balancer;
4. Uso do NGINX Ingress Controller como ingress controller devido a familiaridade da equipe do cliente;
5. Poder trafegar HTTP/S,TCP,UDP utilizando apenas 1 Load Balancer e ter a possibilidade de TLS Termination no próprio Load Balancer;
6. SSL Offloading entre o Load Balancer e os pods;
7. Múltiplos subdomínios;
8. Redirecionamento de tráfego HTTP baseado em path.

Os recursos utilizados:

1. Nginx Ingress controller do projeto Kubernetes;
2. TLS termination no Network Load Balancer.Recurso suportado desde 2019;
3. Múltiplos ingress para múltiplos subdomínios (ACM wildcard);
4. Múltiplos ingress com routes para diferentes services;
5. TCP/UDP Proxy para serviços nativamente TCP/UDP.

A implementação:

Como o tema deste artigo é de nível avançado e requer um bom conhecimento da parte de networking do Kubernetes, então eu vou assumir que neste momento você já criou seu cluster (público ou privado), criou os node groups, criou seu OIDC provider e as service account necessárias ou fez o attach das policies necessárias na IAM Role dos nós do seu cluster. Caso tenha dúvidas, a AWS possui um artigo em seu blog que pode ajudar em sua compreensão.

1. Certificado

Crie um certificado ACM para o domínio que desejar. Procure adicionar o certificado como wildcard para que você possa utilizar diversos subdomínios. No meu caso, eu tenho um domínio chamado awscdk.cloud e vou usar ele como exemplo. Caso tenha dúvidas, utilize este artigo como referência:

O certificado tem que estar com status “issued” para poder ser utilizado.

2. Instalando o NGINX Ingress Controller

Faça o download do arquivo de deploy direto do repositório do GitHub
Uma vez que o arquivo foi baixado, precisamos fazer algumas alterações para que seja possível ajustar o certificado, os IPs estáticos (vamos alocar Elastic IPs) e o protocolo que será TLS (para termos TLS Termination no NLB).
Vá até mais ou menos a linha 263 e você verá os annotations do Kubernetes para o “aws-load-balancer”

Primeira alteração:
Adicione as seguintes linhas:
service.beta.kubernetes.io/aws-load-balancer-ssl-cert: arn:aws:acm: xxx (ARN DO SEU CERTIFICADO ACM)service.beta.kubernetes.io/aws-load-balancer-ssl-ports: “https”service.beta.kubernetes.io/aws-load-balancer-eip-allocations: “eipalloc-5bc1bb50,eipalloc-xxx,eipalloc-xxx” (adicione quantos ips elásticos você quiser, lembrando que tem que ser o máximo de número de AZs)
Seu arquivo ficará próximo disso:

Segunda alteração:
Para que o Network Load Balancer consiga fazer o TLS Termination nele, e não nos pods, é preciso alterar o protocolo de destino que o ingress vai enviar. Vá até a linha 287 e localize o item “- name: https”. Altere o targetPort e o appProtocol para http ao invés de https, dessa forma a conexão SSL terminará no Network Load Balancer e não nos pods.

Abaixo segue uma imagem que explica como funciona o SSL Offloading em um Load Balancer.

Crie os resources no Kubernetes com o comando “kubectl apply -f deploy.yaml” e aguarde a criação de todos os resources.
ATENÇÃO: Se a criação do service “ingress-nginx-controller” ficar em pending e você não enxergar o Network Load Balancer na AWS, há algum problema de permissão da sua role ou do serviceaccount. Utilize o Cloudtrail para ajudar a identificar se o problema é permissão.
Assumindo que tudo deu certo e o Network Load Balancer foi criado com sucesso, você deve enxergar na AWS o recurso da seguinte forma:

Agora podemos realizar o deploy dos nossos primeiros serviços e testar o acesso HTTP e HTTPS.

3. Deploy de serviços HTTP

Como exemplo para este artigo, vamos utilizar um deploy de um pod com apache e criar 1 ingress para ele. Esse é apenas um exemplo, você pode fazer deploy da aplicação HTTP que desejar.
Criando o deployment e o ingress
Digite o seguinte comando para criar deployment da sua primeira app:
kubectl apply -f https://raw.githubusercontent.com/leandrodamascena/medium-nlb/main/apache-deploy.yaml

Agora que temos o deployment criado, é hora de criar um ingress para apontar para este deployment.
Digite o seguinte comando:
wget https://raw.githubusercontent.com/leandrodamascena/medium-nlb/main/ingress-1.yaml
Abra o arquivo e altere a linha “- host: medium.awscdk.cloud” para o domínio/subdomínio que você criou o ACM. Lembre-se de adicionar uma entrada na sua zona de DNS (do tipo CNAME) apontando para o endereço do Network Load Balancer, no meu caso ficou da seguinte maneira:

Faça o deploy deste arquivo utilizando o comando: “kubectl apply -f ingress-1.yaml”.
Caso queira realizar o deploy de mais ingress HTTP apontando para outros subdomínios e outros services, então copie o arquivo “ingress-1.yaml” para outro arquivo e troque as entradas de “host”, “serviceName” e “servicePort”. Desta forma, você terá múltiplos ingress respondendo por múltiplos domínios.
ATENÇÃO: A partir da versão 1.22 o Kubernetes vai mudar a API do Ingress de “extensions/v1beta1” para “networking.k8s.io/v1”.
Mais informações em: https://kubernetes.io/docs/reference/using-api/deprecation-guide/#ingress-v122
Acessando os domínios
Abra o browser e digite o domínio configurado, no meu caso “https://medium.awscdk.cloud/”


Caso encontre qualquer problema ou erro 404, verifique os logs do pod “ingress-nginx-controller-*” no namespace “ingress-nginx”.

4. Deploy de serviços TCP

Como exemplo para este deploy, vamos utilizar o serviço do mongodb queestá disponível/ na página do próprio Kubernetes.
Deploy do mongo e do service
Digite os seguintes comandos:
kubectl apply -f https://k8s.io/examples/application/mongodb/mongo-deployment.yamlkubectl apply -f https://k8s.io/examples/application/mongodb/mongo-service.yaml
Após executar os comandos acima, você verá no namespace default o pod e o service do mongo.

Configurando o ingress controller

Abra novamente o arquivo “deploy.yaml” e agora faremos uma série de alterações:
• No service do Ingress Controller ( mais ou menos na linha 260) devemos adicionar as seguintes linhas abaixo da porta https:
– name: mongo
port: 27017
protocol: TCP
targetPort: 27017
appProtocol: TCP


• Procure pelo deployment do controller (mais ou menos linha 330) e adicione os seguintes comandos na chave “args”:
– –tcp-services-configmap=$(POD_NAMESPACE)/tcp-services
– –udp-services-configmap=$(POD_NAMESPACE)/udp-services

• Desça um pouco mais o arquivo e onde tem as portas do container, adicione também a porta 27017:
– name: mongo
containerPort: 27017
protocol: TCP

• Agora execute o comando para carregar as novas configurações para nosso ingress controller. Se tudo correr bem, o seu Load Balancer deve ficar conforme foto abaixo:
kubectl apply -f deploy.yaml

• Ainda precisamos criar os configmap e abaixo é possível entender o motivo pelo qual precisamos disso. Execute os seguintes comandos:
kubectl apply -f https://raw.githubusercontent.com/leandrodamascena/medium-nlb/main/config-map-tcp.yamlkubectl apply -f https://raw.githubusercontent.com/leandrodamascena/medium-nlb/main/config-map-udp.yaml
Note que no arquivo TCP eu mapeio a porta para o namespace, service e porta do serviço. Você pode adicionar quantas portas quiser.
Para adicionar para o serviço UDP, edite o arquivo e faça o mapping das portas como fiz no serviço TCP.
ATENÇÃO:
O motivo pelo qual precisamos criar configmaps para serviços TCP e UDP é que o Ingress Controller não aceita TCP/UDP nativamente, então ele deve apontar para um configmap para indicar o namespace, o service e a porta que vai usar. Abaixo segue a explicação do site oficial: (https://kubernetes.github.io/ingress-nginx/user-guide/exposing-tcp-udp-services/)
“Ingress does not support TCP or UDP services. For this reason this Ingress controller uses the flags –tcp-services-configmap and –udp-services-configmap to point to an existing config map where the key is the external port to use and the value indicates the service to expose using the format: ::[PROXY]:[PROXY]
It is also possible to use a number or the name of the port. The two last fields are optional. Adding PROXY in either or both of the two last fields we can use Proxy Protocol decoding (listen) and/or encoding (proxy_pass) in a TCP service. The first PROXY controls the decode of the proxy protocol and the second PROXY controls the encoding using proxy protocol. This allows an incoming connection to be decoded or an outgoing connection to be encoded. It is also possible to arbitrate between two different proxies by turning on the decode and encode on a TCP service.”

Agora basta conectar no endereço medium.awscdk.cloud, na porta 27017 e o ingress fechará a conexão com seu serviço TCP:
[root@ip-172-31-78-41 keys]# telnet medium.awscdk.cloud 27017
Trying 44.195.204.52…
Connected to medium.awscdk.cloud.
Escape character is ‘^]’.

Logs do Ingress Controller:

[3.232.229.57] [01/Sep/2021:01:14:46 +0000] TCP 200 0 19 6.752
[3.232.229.57] [01/Sep/2021:01:15:18 +0000] TCP 200 0 17 8.460
I0901 01:15:29.333757 6 leaderelection.go:253] successfully acquired lease ingress-nginx/ingress-controller-leader
I0901 01:15:29.333775 6 status.go:84] “New leader elected” identity=”ingress-nginx-controller-8468b46b64-8xvhp”
I0901 01:15:29.344527 6 status.go:284] “updating Ingress status” namespace=”default” ingress=”micro-ingress” currentValue=[] newValue=[{IP: Hostname:a16e087863c2d457fbe56a20746cbd60-e176fb991afdfd87.elb.us-east-1.amazonaws.com Ports:[]}]
I0901 01:15:29.353062 6 event.go:282] Event(v1.ObjectReference{Kind:”Ingress”, Namespace:”default”, Name:”micro-ingress”, UID:”c8ee028a-c3b5-4e02-94d8-80499b961375″, APIVersion:”networking.k8s.io/v1″, ResourceVersion:”125703″, FieldPath:””}): type: ‘Normal’ reason: ‘Sync’ Scheduled for sync
183.89.148.191 – – [01/Sep/2021:01:21:30 +0000] “GET / HTTP/1.1” 400 150 “-” “-” 18 0.000 [] [] – – – – c92a1c3e761d28b8ceee528fa71c37ed
[3.232.229.57] [01/Sep/2021:01:41:38 +0000] TCP 200 0 16 67.223

Logs do pod do Mongo:

2021-09-01T00:58:50.933+0000 I NETWORK [listener] connection accepted from 127.0.0.1:48504 #1 (1 connection now open)
2021-09-01T00:58:56.312+0000 I NETWORK [conn1] Error receiving request from client: ProtocolError: Client sent an HTTP request over a native MongoDB connection. Ending connection from 127.0.0.1:48504 (connection id: 1)
2021-09-01T00:58:56.312+0000 I NETWORK [conn1] end connection 127.0.0.1:48504 (0 connections now open)
2021-09-01T01:14:00.155+0000 I NETWORK [listener] connection accepted from 172.31.4.141:40024 #2 (1 connection now open)
2021-09-01T01:14:38.425+0000 I NETWORK [conn2] Error receiving request from client: SSLHandshakeFailed: SSL handshake received but server is started without SSL support. Ending connection from 172.31.4.141:40024 (connection id: 2)
2021-09-01T01:14:38.425+0000 I NETWORK [conn2] end connection 172.31.4.141:40024 (0 connections now open)
2021-09-01T01:14:39.655+0000 I NETWORK [listener] connection accepted from 172.31.15.47:35708 #3 (1 connection now open)
2021-09-01T01:14:46.407+0000 I NETWORK [conn3] Error receiving request from client: SSLHandshakeFailed: SSL handshake received but server is started without SSL support. Ending connection from 172.31.15.47:35708 (connection id: 3)
2021-09-01T01:14:46.407+0000 I NETWORK [conn3] end connection 172.31.15.47:35708 (0 connections now open)
2021-09-01T01:15:10.100+0000 I NETWORK [listener] connection accepted from 172.31.15.47:36014 #4 (1 connection now open)
2021-09-01T01:15:18.560+0000 I NETWORK [conn4] Error receiving request from client: SSLHandshakeFailed: SSL handshake received but server is started without SSL support. Ending connection from 172.31.15.47:36014 (connection id: 4)
2021-09-01T01:15:18.560+0000 I NETWORK [conn4] end connection 172.31.15.47:36014 (0 connections now open)
2021-09-01T01:40:31.110+0000 I NETWORK [listener] connection accepted from 172.31.15.47:49656 #5 (1 connection now open)
2021-09-01T01:41:38.332+0000 I NETWORK [conn5] Error receiving request from client: SSLHandshakeFailed: SSL handshake received but server is started without SSL support. Ending connection from 172.31.15.47:49656 (connection id: 5)
2021-09-01T01:41:38.332+0000 I NETWORK [conn5] end connection 172.31.15.47:49656 (0 connections now open)
2021-09-01T01:41:40.091+0000 I NETWORK [listener] connection accepted from 172.31.15.47:50262 #6 (1 connection now open)

Para limpar o ambiente basta apenas digitar o seguinte comando:
kubectl delete -f deploy.yaml
Espero que tenham gostado do artigo e deixem seus comentários em caso de dúvidas!

OUTRAS PUBLICAÇÕES

Novidades da Semana 16 a 20 de agosto

Por Anderson Santos Todos os dias a AWS lança uma série novidades e atualizações em seus produtos que visam melhorar a vida de seus usuários. Reunimos algumas delas que fazem mais sentido para nosso mercado e que certamente aplicaremos em nosso dia a dia. Confira as novidades das últimas semanas. Compute Amazon API Gateway – Suporte a TLS mútuo com certificados de CAs de terceiros e CA privada ACM O Amazon API Gateway agora permite a autenticação usando TLS mútuo baseado em certificado, onde os certificados digitais são trocados entre o cliente e o API Gateway antes que uma conexão segura seja estabelecida. AWS Lambda – Suporte a Python 3.9 O AWS Lambda agora oferece suporte ao Python 3. Assim permitindo criar funções do AWS Lambda no Python 3.9 e usar seus novos recursos, como suporte para TLS 1.3, novas operações de string e dicionário, além do suporte aprimorado de fuso horário. Amazon EC2 – Novas instancias M6i AWS anunciou as instâncias M6i, expandindo o portfólio de instâncias EC2 de 6ª geração para incluir opções de computação baseadas em x86. A M6i possui Intel Xeon de 3ª geração (codinome Ice Lake) com uma frequência turbo all-core de 3,5 GHz, que oferece desempenho de preço de computação até 15% melhor em relação às instâncias M5 e criptografia de memória sempre ativa usando Intel Total Criptografia de memória (TME). AWS Neuron – Instâncias Inf1 compatíveis com TensorFlow 2 O AWS Neuron , o SDK para executar a inferência de machine learning nas instâncias do Amazon EC2 Inf1 baseadas no AWS Inferentia, agora oferece suporte ao TensorFlow 2. Amazon EC2 – Suporte a chaves ED25519 para autenticação A AWS anunciou que agora é possível utilizar as chaves ED25519 para provar sua identidade ao se conectar a instâncias EC2. ED25519 é um sistema de chave pública baseado em curva elíptica comumente usado para autenticação SSH. Anteriormente, os clientes EC2 só podiam usar chaves baseadas em RSA para se autenticar em instâncias EC2. Amazon WorkSpaces – Novos pacotes com Windows Server 2019 e Microsoft Office 2019 de 64 bits O Amazon WorkSpaces agora oferece novos pacotes com o Windows Server 2019, proporcionando uma experiência de desktop do Windows 10 junto com uma opção de pacote do Microsoft Office 2019 Professional Plus de 64 bits. AWS Elastic Beanstalk – Suporte ao reequilíbrio de capacidade para instâncias spot do Amazon EC2 O AWS Elastic Beanstalk agora oferece suporte ao reequilíbrio de capacidade para grupos do Amazon EC2 Auto Scaling (ASG) . Este recurso reduz as interrupções da Instância Spot para os aplicativos dos clientes. Database Amazon Redshift – Novo recurso de compartilhamento de contas O compartilhamento de dados do Amazon Redshift permite que você compartilhe dados transacionais consistentes em diferentes clusters Redshift sem a complexidade e os atrasos associados às cópias e movimentação de dados. Amazon RDS para SQL Server – Suporte a atualizações automáticas de minor versions O Amazon RDS para SQL Server agora inclui aprimoramentos para o recurso de atualização automática de minor version para instâncias de banco de dados do Amazon RDS para SQL Server. A atualização automática de versão secundária é um recurso que pode ser habilitado para que seu banco de dados seja atualizado automaticamente quando uma nova versão secundária do mecanismo de banco de dados estiver disponível. Security & Governance AWS Systems Manager – Fleet Manager com recurso de geração de relatórios para instâncias gerenciadas O AWS Systems Manager Fleet Manager, um recurso do AWS Systems Manager (SSM) que ajuda a otimizar e dimensionar seus processos de gerenciamento de servidor remoto, agora oferece a capacidade de gerar relatórios instantâneos sobre suas instâncias gerenciadas SSM. O novo recurso permite que você personalize o painel de informações do Fleet Manager, no qual você pode visualizar alertas, status e detalhes de instâncias gerenciadas e fazer o download para visualização e análise local. AWS Transfer Family – Expansão de compatibilidade para clientes FTPS / FTP e aumento do limite para o número de servidores O AWS Transfer Family agora oferece suporte à configuração de um endereço IP acessível para clientes em um servidor FTPS / FTP, permitindo que eles se conectem ao servidor. Além disso, os clientes agora podem escalar facilmente suas cargas de trabalho criando até 50 servidores dentro do AWS Transfer Family em uma única conta e região da AWS, um aumento de cinco vezes no limite anteriormente suportado de 10 servidores. AWS Security Hub – 18 novos controles ao seu padrão de práticas recomendadas O AWS Security Hub lançou 18 novos controles para seu padrão de práticas recomendadas de segurança básica para aprimorar o monitoramento da postura de segurança na nuvem dos clientes. O Security Hub também adicionou 5 parceiros de integração e 3 parceiros de consultoria, o que traz o Security Hub para um total de 71 parceiros. Analytics & Machine Learning Amazon CodeGuru Profiler – Extensão da capacidade de visualizações com uma nova opção de comparação para perfil de aplicativo O Amazon Code Guru Profiler estendeu a capacidade de visualizações com uma nova opção de comparação entre dois intervalos de tempo diferentes do mesmo grupo de criação de perfil. A opção CodeGuru Profiler Compare ajuda a diagnosticar problemas em seu aplicativo para um intervalo de tempo específico de dados de criação de perfil e pode ser usada para identificar melhorias de desempenho em potencial para seu aplicativo. AWS Glue DataBrew – Suporte à gravação de dados preparados em tabelas do AWS Glue Data Catalog S3 baseadas na AWS Lake Formation O AWS Glue DataBrew agora oferece suporte à gravação de dados preparados de tarefas de receita em tabelas AWS Glue Data Catalog S3 baseadas na AWS Lake Formation. Com esse recurso, o DataBrew adota automaticamente as permissões de acesso existentes e a segurança definidas na tabela Glue Data Catalog baseada na AWS Lake Formation e sua localização no Amazon S3 associada. AWS Glue DataBrew – Suporte a transformações de formato numérico O AWS Glue DataBrew agora oferece suporte a transformações de formato numérico, incluindo configuração de precisão decimal, personalização

Novidades da AWS – 21 a 25 de setembro

Todos os dias a AWS lança uma série novidades e atualizações em seus produtos que visam melhorar a vida de seus usuários. Veja as novidades da semana de 21 a 25 de setembro.

Nós usamos cookies para garantir e oferecer a melhor experiência de navegação em nosso site! Mais informações