19 de setembro de 2021

Do bit Ao Byte

Embarcados, Linux e programação

Como criar VPC endpoint interface com AWS CLI

VPC endpoint interface

Esse artigo é mais um pretexto para explicar a queda de publicações. Bem, recentemente tive a honra de ser recrutado para uma mega missão, da qual ainda não posso dar detalhes. Apesar de ter um vasto conhecimento em Linux e redes (modéstia à parte), tenho um pífio conhecimento em nuvem – que é um dos principais requisitos. Nesse artigo vou mostrar uma tarefa básica, que só saiu depois de estudar um bocado antes conseguir criar rapidamente o script: Como criar VPC endpoint interface com AWS CLI.

VPC endpoint interface?

Pra quem é de redes, talvez eu consiga explicar com mais clareza. Imagine termos várias redes em uma infraestrutura, porém isoladas. De repente, precisamos acessar a rede B a partir da rede A. Normalmente incluiríamos uma interface física ou uma rota para essa rede. Dá pra ir longe com esse raciocínio; um roteador, um firewall, um switch layer3 etc. Porém, com a AWS fazemos esse serviço simplesmente incluindo uma interface VPC endpoint.

Esse não é um tutorial de AWS, até porque estou aprendendo, mas gostaria de mostrar um procedimento básico para a criação de VPCs endpoint interface já definidas, usando o AWS CLI – que é um client de linha de comando para dispensar o uso do console e agilizar tarefas.

Por que fazer um script para criar VPC endpoint interface?

Tudo na AWS tem custo. Imagine ter um ambiente de desenvolvimento e um ambiente de produção; aliás, se não está acostumado com esses dois ambientes, alguma coisa não está certa com seu desenvolvimento.

Podemos subir as VPCs em um ambiente de testes e enquanto não estiver desenvolvendo, podemos excluir essas interfaces para não gerar custo. Também podemos recriá-las e, tendo diversas VPCs, pode ser uma tarefa chata e repetitiva.

Script de exemplo e jq

Primeiro, precisamos ter instalado o programa jq, que faz parsing da saída em formato json, do AWS CLI.

Quando criamos a interface VPC endpoint, temos o retorno em formato json, do qual precisamos da informação do VPC Endpoint ID. Para guardar esse valor, podemos usar a seguinte linha:

VPC_ENDPOINT_ID=`$AWS_CLI create-vpc-endpoint --vpc-id $VPC_TARGET --vpc-endpoint-type Interface --service-name ${ENDPOINTS[$i]} --security-group-id $SECURITY_GROUP_ID  --region sa-east-1  --tag-specifications "ResourceType=vpc-endpoint,Tags=[{Key=Name,Value=$CHOICE}]"|jq '.[] |  .VpcEndpointId'`

A variável AWS_CLI contém o valor aws ec2 –profile PERFIL, onde “PERFIL” pode ser o default ou um configurado por você.

A vairável VPC_TARGET contém a VPC à qual será atrelada a interface VPC endpoint.

A variável ENDPOINTS foi montada como um array e contém todas as interfaces VPCs endpoints que serão criadas.

A variável SECURITY_GROUP_ID contém o ID do grupo de segurança – que é explicitamente um conjunto de liberação de portas de serviço.

A variável CHOICE contém um valor qualquer para servir de identificação. Essa identificação pode ser vista no painel EC2, olhando nas instâncias. Tive um problema terrível para descobrir que de Resources à Value=X deveriam ser protegidas com aspas. A documentação da AWS não mostra as aspas e então li e executei montes de outros comandos para entender a lógica, até que consegui chegar no resultado esperado. A vantagem é que acabei aprendendo um monte de outras interações.

Esse também não é um tutorial de shell script, por isso não vou entrar em detalhes, mas vou explicar rapidamente como funciona um array em shell script. Vamos criar um array com os valores “um” “dois” “tres”:

SH_ARRAY=("um" "dois" "tres")

Para acessarmos os itens, usamos o índice, começando em 0:

echo ${SH_ARRAY[0]}

Isso deve retornar o valor “um”. Se quisermos ver todos os valores, usamos:

echo ${SH_ARRAY[@]}

Mas para fazer um loop interativo, precisamos saber o número de itens no array. Para isso:

echo ${#SH_ARRAY[@]}
VPC endpoint interface

Assim sendo:

${ENDPOINTS[$i]}

Fica claro que essa variável está dentro de um loop, com o contador $i.

Após criar a interface VPC endpoint, precisamos adicionar as subnet; é muito parecido à configuração de IPs em interfaces ethernet – foi a forma mais simplória que consegui pensar para fazer essa relação: Cria a interface, atribui a(s) rede(s) a ela. Por essa razão tivemos que guardar o VPC_ENDPOINT_ID. Agora é hora de atrelar as subnets:

$AWS_CLI modify-vpc-endpoint --vpc-endpoint-id $VPC_ENDPOINT_ID --add-subnet-ids ${SUBNETS[0]} ${SUBNETS[1]}

As subnets foram criadas em forma de array, mas isso foi por opção.

Supondo que tenhamos várias VPCs endpoint interfaces, podemos ter um script assim:

#!/bin/bash

ENDPOINTS=("com.amazonaws.vpce.sa-east-1-blablabla" "com.amazonaws.vpce.sa-east-1-blablabla" \
"com.amazonaws.vpce.sa-east-1-blablabla" "ccom.amazonaws.vpce.sa-east-1-blablabla")

ENDP_IDX=("NomeDaPrimeira" "NomeDaSegunda" "NomeDaTerceira" "NomeDaQuarta")

VPC_TARGET="vpc-XXXXXXXX"
SECURITY_GROUP_ID="sg-xxxxxxxxxxxxxxxxxx"
SUBNETS=("subnet-xxxxxxxx" "subnet-yyyyyyyy")

set_profile(){
    AWS_CLI="aws ec2 --profile $1"
}

create_vpcei(){
    for i in `seq 0 ${#ENDP_IDX[@]}`; do
        CHOICE=${ENDP_IDX[$i]}
        VPC_ENDPOINT_ID=`$AWS_CLI create-vpc-endpoint --vpc-id $VPC_TARGET --vpc-endpoint-type Interface --service-name ${ENDPOINTS[$i]} --security-group-id $SECURITY_GROUP_ID  --region sa-east-1  --tag-specifications "ResourceType=vpc-endpoint,Tags=[{Key=Name,Value=$CHOICE}]"|jq '.[] |  .VpcEndpointId'`
        VPC_ENDPOINT_ID=`echo $VPC_ENDPOINT_ID|tr -d [:punct:]|sed -re 's/(vpce)/\1-/'`
        $AWS_CLI modify-vpc-endpoint --vpc-endpoint-id $VPC_ENDPOINT_ID --add-subnet-ids ${SUBNETS[0]} ${SUBNETS[1]}
    done

}

delete_vpcei(){
    VPCE_LIST=(`$AWS_CLI describe-vpc-endpoints|jq '.[] | .[] | .ServiceName, .Tags[].Value'|tr " " "_"`)
    [ ${#VPCE_LIST[@]} -gt 0 ] || {
        echo "Sem VPCEs nesse perfil. Saindo..."
        exit 0 
    }

    $AWS_CLI describe-vpc-endpoints|jq '.[] | .[] | .VpcEndpointId'|tr -d [:punct:]|sed -re 's/(vpce)/\1-/'|while read line; do
    $AWS_CLI delete-vpc-endpoints --vpc-endpoint-ids $line; done 
}

helper(){
    echo "Use: $0 <profile> create/delete"
    echo "TODAS as interfaces serao removidas ou criadas"
}

[ $# -eq 2 ] ||{
    echo "passe o perfil seguido de create ou delete. Ex.:"
    echo "db_producao delete"
    echo "Seus perfis sao:"
    echo " "
    egrep '^\[' ~/.aws/credentials|while read line; do
        echo $line|tr -d [[:cntrl:]]
        echo ""
    done
    exit 0
}


    PROFILE_OK=`egrep "^\[$1\]$" ~/.aws/credentials|wc -c`
    [ $PROFILE_OK -gt 0 ] || {
        echo "Digitou o perfil errado ($1)?"
        echo "Saindo..."
        exit 0
    }

    if [ "$2" = "create" ]; then
        set_profile $1
        create_vpcei
    elif [ "$2" = "delete" ]; then
        set_profile $1
        delete_vpcei
    else
        echo "Digitou errado o comando a executar ($2)?"
    fi

Apesar de ser simples, tem uma montanha de conceitos aí, que só quem já usa AWS vai entender. Por exemplo, a região escolhida sa-east-1 é onde estão os datacenters (são no mínimo 2, para oferecer redundância geográfica e tolerância à falhas). A região sa-east-1 é São Paulo. Escolher a região mais próxima de todas as partes envolvidas do sistema é fundamental para diminuir a latência, já que isso reduz o número de hops para um destino.

Usando aws seguido de ec2, estamos usando o serviço Elastic Computing, que é o serviço de aluguel de computadores virtuais da Amazon. Se, por exemplo, o primeiro parâmetro fosse s3, o serviço a utilizar seria um storage. Aí começa um monte de frescuras de nomeclaturas, tipo: “um bucket que armazena objetos blablabla…”. O serviço é a cara do rsync e pretendo manter essa visão, mas de fato, seu uso é “muito” mais simples. Só que não faz parte desse artigo, escreverei a respeito em outra oportunidade.

Em Tags, a Key não é de livre escolha. Para que apareça como nome de identificação, seu valor “deve” ser Name. Já em Value, colocamos o que quisermos de nome.

Bem, essa foi uma tarefa simples que fiz logo após o café da manhã de um dia qualquer dessa semana, mas creio que seja o suficiente para justificar a ausência de artigos durante esses dias. Mas trago boas novas; em breve mostrarei como criar uma instância gratuita na AWS, a qual poderemos usar como broker MQTT com endereço público. Nada mal, hum? A AWS oferece um conjunto extra de serviços gratuitos para quem quer aprender, incluindo também armazenamento S3, banco de dados, banco de dados DynamoDB (esse último é gratuito para sempre), machine learning e lambda. Não estou ganhando nada para divulgar, apenas estou desejando que alguns de vocês me acompanhem nessa empreitada.

Já citei isso duas vezes, mas vou citar uma terceira: Estou aprendendo ainda e estou no começo. Aceito sugestões, mas cagarei quilos para críticas, esse artigo não é um tutorial.

Os artigos retornarão com mais frequência em breve, por enquanto estou usando 100% da minha energia ao aprendizado da primeira fase, que é AWS. Depois tem criação de infraestrutura com terraform, certificações AWS e SRE e mais um mar de coisas que pretendo ir contando como experiências e exemplos dos primeiros passos.

Por fim, está chegando o material de um de nossos parceiros e trarei bons artigos, dependendo do que vai chegar, acompanhem!