DevSecOps

10 jul, 2017

Criando uma VM Azure usando Chef

Publicidade

Não faz mais sentido, em pleno 2017, configurar um servidor sem algum sistema de orquestração. A própria ideia de configurar um servidor talvez esteja caindo em desuso. Não faz mais sentido se logar em um servidor Linux por SSH e instalar pacotes como se você estivesse na sua máquina de trabalho. Temos ferramentas para versionar, organizar e automatizar cada passo. E a preocupação com a orquestração não é um papel apenas de um DevOps, mas um papel que precisa ser apropriado por qualquer desenvolvedor.

O propósito deste artigo é o de criar uma VM Azure através de Resource Manager Templates via Chef. Não é necessário nenhum conhecimento prévio de ARM Templates ou de Chef, mas quem conhece um ou outro também pode se beneficiar.

Porque alguém criaria uma VM via Chef, usando um artigo com uma dezena de passos quando posso criar uma VM pelo portal do Azure ou numa simples linha de comando usando Azure Cli?

E se você precisar criar não uma, mas 5, 10 VMs? E se essas VMs não forem idênticas, mas com configurações específicas, como você organiza a configuração de cada VM? Numa planilha? E se você tivesse um repositório onde pudesse replicar toda a sua infra estrutura em poucos minutos? E se você puder manter tudo isso versionado, num Git, por exemplo? E mesmo que seja uma única VM, ter as características desta VM salvas num repositório versionado com a possibilidade do ambiente poder ser recriado a qualquer momento já não é uma vantagem suficiente?

As possibilidades são infinitas. E como os recipes são em Ruby, você tem em mãos todas as possibilidades lógicas que uma linguagem de alto nível oferece.

  • Nossa VM vai ser criada usando Chef em local-mode, ou seja, apenas através de sua máquina de trabalho.
  • Esse aritgo deve funcionar em qualquer Sistema Operacional. Como o Powershell aceita tanto barras simples (/) quanto invertidas (\), nos comandos comuns mantive as barras simples, em nome da simplicidade.
  • Se você usa Bash on Windows ou Cygwin, pode acompanhar o artigo seguindo os passos de UNIX, sem medo.
  • No universo UNIX, chamamos de diretório o que no Windows se chama de pasta. Quando ler diretório, entenda como pasta. Para quem curte uma discussão filosófica, o Stack Overflow é sempre um ponto de partida.
  • No Mac, se você não tiver o comando wget, pode usar o curl para fazer downloads por linha de comando. A sintaxe é bem simples:
curl -O [url]

Requisitos:

chef gem install chef-provisioning-azurerm
  • Instale o Python Azure CLI 2.0 ou o Powershell Azure SDK para configurar as credenciais para o Chef.
    • Num shell UNIX: Você precisa de Python PIP (digite pip, veja se o comando existe). Caso não tenha, siga uma destas instruções para alguma distro Linux. Claro que com Bash on Windows você deve seguir as instruções de Ubuntu. Para Mac, um simples sudo easy_install pip pode ser o suficiente. Ou use MacPorts ou Homebrew. No Cygwin você precisa de python-setuptools para, então, instalar o pip via easy_install pip.
pip install --user azure-cli

Acrescente o diretório bin de instalação do Python local na variável PATH do usuário.

echo 'PATH=~/.local/bin:$PATH' >> ~/.bashrc
source ~/.bashrc
  • No Windows, Azure Powershell.

Os detalhes podem ser encontrados aqui.

A instalação do módulo azurerm precisa ser executada com uma instância de Powershell como Administrador. Abra uma nova janela, selecionando através do menu Executar como administrador.

Install-Module AzureRM

Se receber o prompt abaixo, digite Y ou A:

Untrusted repository
You are installing the modules from an untrusted repository. If you trust this repository, change its
InstallationPolicy value by running the Set-PSRepository cmdlet. Are you sure you want to install the modules from      'PSGallery'?
[Y] Yes  [A] Yes to All  [N] No  [L] No to All  [S] Suspend  [?] Help (default is "N"): Y

Altere a política de execução para Bypass:

Set-ExecutionPolicy -ExecutionPolicy Bypass

Feche essa janela como administrador, retorne à janela comum de Powershell e importe o módulo que acabamos de instalar:

Import-Module AzureRM

Mãos à obra!

  • Crie um repositório Chef: eu costumo criar meus ambientes de trabalho em ~/Projects. Mas você pode organizar de outra forma, em outro diretório. O nome do repositório Chef também fica a critério de cada um.
cd ~/Projects
chef generate repo chef-repo

Para facilitar, vamos exportar uma variável temporária para a raiz do repositório.

  • Num shell UNIX:
export CHEF_REPO=~/Projects/chef-repo
  • No Powershell:
$CHEF_REPO = "~\Projects\chef-repo"

No decorrer do artigo, vamos usar a localização de diretórios a partir desta variável, $CHEF_REPO.

  • Crie um diretório .chef dentro do repositório que acabamos de criar:
mkdir $CHEF_REPO/.chef
  • Crie o arquivo knife.rb. Este é um arquivo de configuração básico do nosso ambiente de Chef local. Use o seu editor favorito.
# $CHEF_REPO/.chef/knife.rb
log_level                :info
current_dir = File.dirname(__FILE__)
node_name                "provisioner"
client_key               "#{current_dir}/dummy.pem"
validation_key           "#{current_dir}/dummy.pem"
validation_client_name   "validator"
  • Vamos criar uma chave SSH. Ela vai ser nossa forma de autenticação para a nova VM.

É importante que o nome das chaves que você for criar corresponda às variáveis no arquivo $CHEF_REPO/.chef/knife.rb. Vamos referenciar a chave pública por este arquivo logo mais no recipe.

  • Nos UNIX:
cd $CHEF_REPO/.chef
ssh-keygen -f dummy.pem
  • No Windows, se você não tiver um OpenSSH ou não quiser instalar um, pode instalar o PuTTY.

Execute PuTTYgen e clique em generate. Deixe os valores padrão, ou pelo menos adicione uma senha. Clique em Save private key e escolhe um nome. Aqui, estamos usando dummy, mas o critério é seu. Navegue até a pasta .chef dentro do nosso repositório chef e salve sua chave privada.

Clique em Save public key. Por coerência, use o mesmo nome, mas acrescente uma extensão, que por convenção, estamos chamando de .ppk.pub. No nosso exemplo é dummy.ppk.pub.

Volte ao Powershell e liste o conteúdo de $CHEF_REPO/.chef. O comando deve te listar três arquivos.

PS C:\Users\aline\Projects\chef-repo\.chef> dir


    Directory: C:\Users\aline\Projects\chef-repo\.chef


Mode                LastWriteTime         Length Name
----                -------------         ------ ----
-a----       22/06/2017     20:13           1460 dummy.ppk
-a----       22/06/2017     20:13            477 dummy.ppk.pub
-a----       22/06/2017     20:13            252 knife.rb
  • Crie as credenciais de acesso ao Azure pelo Chef:
    • UNIX
az login

Siga os passos, se autentique no navegador. Quando terminar execute:

az account list

Tenha certeza que a assinatura (subscription) que você vai utilizar esteja com o valor IsDefault para true.

Substitua a subscription ID do comando anterior com SUA_SUBSCRIPTION_ID no parâmetro scopes a seguir:

az ad sp create-for-rbac --role="Contributor" --scopes="/subscriptions/SUA_SUBSCRIPTION_ID"

Crie o arquivo ~/.azure/credentials neste formato:

[SUA_SUBSCRIPTION_ID]
client_id = "48b9bba3-YOUR-GUID-HERE-90f0b68ce8ba"
client_secret = "your-client-secret-here"
tenant_id = "9c117323-YOUR-GUID-HERE-9ee430723ba3"

Sendo:

  1. SUA_SUBSCRIPTION_ID, a subscription ID utilizada anteriormente.
  2. client_id, o valor de AppId.
  3. client_secret, o valor de Password.
  4. tenant_id, o valor de tenant.
  • Windows Powershell:
Login-AzureRmAccount

Verifique se a subscription corrente é a subscription que você realmente pretende trabalhar.

(Get-AzureRmContext).Subscription

Anote o Name e a Id da sua subscription. A Id vamos usar logo mais no recipe.

Faça o download do script e execute:

Invoke-WebRequest -URI https://gist.githubusercontent.com/sjkp/186d36334b27656a05cd/raw/6acba8599e0906e7fc1957195cd5f7204673d952/New-AzureRmServicePrincipal.ps1 -OutFile New-AzureRmServicePrincipal.ps1
.\New-AzureRmServicePrincipal.ps1

Ele pede subscriptionName, que mencionei logo acima.

Observe que é o nome, não a ID. E ele pede uma senha, que vai ser a senha que irá utilizar para seu APP. Gere uma senha ramdomica complexa, já que ela vai ficar salva numa variável de ambiente.

Pelo Powershell, vamos adicionar as seguintes variáveis:

AZURE_CLIENT_ID com o valor de Service Principal Id.
AZURE_CLIENT_SECRET com o valor da senha que você criou.
AZURE_TENANT_ID com o valor de Tenant Id.

Aqui adicionamos as variáveis no Powershell corrente:

$Env:AZURE_CLIENT_ID = "48b9bba3-YOUR-GUID-HERE-90f0b68ce8ba"
$Env:AZURE_CLIENT_SECRET = "your-client-secret-here"
$Env:AZURE_TENANT_ID = "9c117323-YOUR-GUID-HERE-9ee430723ba3"

E aqui adicionamos permanentemente nas variáveis de usuário:

[Environment]::SetEnvironmentVariable("AZURE_CLIENT_ID", $AZURE_CLIENT_ID, "User")
[Environment]::SetEnvironmentVariable("AZURE_CLIENT_SECRET", $AZURE_CLIENT_SECRET, "User")
[Environment]::SetEnvironmentVariable("AZURE_TENANT_ID", $AZURE_TENANT_ID, "User")
  • Crie um cookbook para nosso recipe, ou seja, nossa receita de criação de uma VM Azure:
cd $CHEF_REPO/cookbooks
chef generate cookbook chef-azure
  • Vamos criar o recipe propriamente. Use seu editor favorito e edite o arquivo $CHEF_REPO/cookbooks/chef-azure/recipes/default.rb
# cookbooks/chef-azure/recipes/default.rb
#
# Cookbook:: chef-azure
# Recipe:: default
#
# Copyright:: 2017, Aline Freitas, All Rights Reserved.
 
require 'chef/provisioning/azurerm'
with_driver 'AzureRM:SUA_SUBSCRIPTION_ID'
 
azure_resource_group 'chefrg' do
  location 'East US'
  tags businessUnit: 'DEV'
end
 
azure_resource_template 'MyDeployment' do
  resource_group 'chefrg'
  template_source "#{Chef::Config[:cookbook_path]}/#{cookbook_name}/files/azuredeploy.json"
  parameters adminUsername: 'ubuntu',
             sshKeyData: File::read("#{Chef::Config[:validation_key]}.pub")
end
  • O campo with_driver ‘AzureRM:SUA_SUBSCRIPTION_ID’ precisa ser corrigido com a sua SUBSCRIPTION ID que usamos outras vezes;
  • adminUsername pode ser substituído por outro nome de usuário a sua escolha;
  • Como informei antes, sshKeyData lê a chave pela localização da chave privada no arquivo $CHEF_REPO/.chef/knife.rb acrescido da extensão .pub. Adapte ao seu cenário se for necessário.

 

  • Precisamos acrescentar o template da nossa VM. Aqui vamos utilizar um template bem simples, que cria uma VM Ubuntu usando uma chave SSH como método de autenticação.
mkdir $CHEF_REPO/cookbooks/chef-azure/files
cd $CHEF_REPO/cookbooks/chef-azure/files
  • UNIX:

wget https://raw.githubusercontent.com/Azure/azure-quickstart-templates/master/101-vm-sshkey/azuredeploy.json

  • Powershell:

Invoke-WebRequest -URI https://raw.githubusercontent.com/Azure/azure-quickstart-templates/master/101-vm-sshkey/azuredeploy.json -OutFile azuredeploy.json

  • E por fim vamos executar a criação do nosso ambiente:
cd $CHEF_REPO
chef-client -o chef-azure -z

O chef-azure aqui no comando é o nome do nosso cookbook. Lembre-se de substituir se o cookbook for criado com outro nome.

  • Agora podemos nos logar na nossa nova VM. Em um cenário de produção, o nome da VM seria dado como um parâmetro, ou gerado automaticamente através de algum critério do usuário. No caso deste template, como ele é bem simples, apenas para demonstração, o nome da VM é hardcoded: sshvm.

 

  • UNIX: Precisamos novamente do azure-cli para obter o IP da nossa VM.
az vm list-ip-addresses -n sshvm

O output vai ser algo assim:

VirtualMachine    PublicIPAddresses    PrivateIPAddresses
—————-         ——————-         ——————–
sshvm                   91.169.135.236                 10.0.1.35

Então, se logar é bem simples. Lembre-se do nosso recipe, o nome de usuário utilizado foi ubuntu.

ssh -i $CHEF_REPO/.chef/dummy.pem.pub ubuntu@91.169.135.236
  • Powershell: Como tivemos que abrir uma nova instância de powershell, talvez você precise se logar novamente.
Import-Module AzureRM
Login-AzureRmAccount

E no snippet abaixo, informe o nome do Resource Group utilizado na criação da sua VM. No nosso exemplo, foi chefrg.

Como o template é bem simples, apenas para demonstração, o nome da VM é hardcoded: sshvm.

$vm = Get-AzureRmVM -Name "sshvm" -ResourceGroupName "chefrg"
$NIC = Get-AzureRmNetworkInterface  | where { $_.Id -eq $vm.NetworkProfile.NetworkInterfaces[0].Id }
Get-AzureRmPublicIpAddress | where {$_.Id -eq $NIC.IpConfigurations[0].PublicIpAddress.Id} | Select IpAddress

O output vai ser algo assim:

IpAddress
---------
91.169.135.236
  • PuTTY

Para se logar, abra o PuTTY. Pelo menu Category do lado esquerdo, navegue para Connection -> SSH -> Auth.Em Private key for authentication e navegue até a nossa chave, que chamamos de dummy.

No mesmo menu Category, clique no primeiro item, Session.

Em Host Name (or IP Address) insira no formato usuário@IP.

No nosso exemplo fica: ubuntu@91.169.135.236.

Se você conseguiu se logar e receber um shell prompt, parabéns!

***

Este artigo foi produzido em parceria com a Lambda3. Leia outros conteúdos no blog da empresa: blog.lambda3.com.br