ANSIBLE SERIES: Final … (WinRM + Chocolatey) A Windows Friend

De longe, a maior série do BLOG até agora. Se pegarmos a quantidade de posts somada a data do primeiro artigo, essa foi sim a mais longa (e completa) que já fiz. Mas antes de abordar esse assunto pela última vez … Você sabia que dá pra gerenciar estações Windows via Ansible? Sim, pois é. O nosso carinha é tão de boa, tão gente fina, que é amigável à todos os sistemas operacionais, incluindo a “janela” do Tio Gattes. E por falar em última(o), caso tenha prestado atenção ao título, essa não será a primeira nem a “última” (haha) vez que o Chocolatey aparece por aqui. Não, não. Já o vimos com o Terraform lembram?

Voltando ao foco da conversa. Para entendermos melhor a interação entre esses dois (ANSIBLE-WINDOWS), iremos compará-los com o Linux. Então, sem mais delongas: Let’s bora!!!

SSH e Python no Windows? Como pode?

Bem, na verdade não. Quero dizer, sim! Tenho plena ciência de que a Microsoft já disponibilizou o OpenSSH nativamente a partir do Windows 10 e Server 2016. Não é novidade pra ninguém! Mas o que acontece é que somente agora os desenvolvedores do Ansible começaram a dar suporte ao SSH no Windows, e ainda por cima de forma experimental. Palavras retiradas da própria documentação oficial, e você pode conferir aqui. Sendo assim, por ora o que temos é:

  • O protocolo chamado Windows Remote Management (ou WinRM¹) desempenhando o papel de SSH para o Ansible.
  • A linguagem de script proprietária da Microsoft, transformando os playbooks que chegam em Python para sintaxe do PowerShell².

¹ WinRM

A primeira diferença é na forma de conexão entre o controlador e o host. É utilizado o Windows Remote Management (WinRM), que é a implementação da Microsoft do Web Services Management (WS-Man), um padrão aberto do Distributed Management Task Force (DMTF), em que se utiliza um web service baseado em SOAP para gerência remota de diversos dispositivos.

² PowerShell

A segunda diferença é o uso de scripts PowerShell no lugar do Python na execução das tasks nos hosts. Ao gerenciar servidores Linux, o Ansible converte as playbooks em scripts Python que são transferidos via SSH para os hosts e executados remotamente.
No caso do Windows, são gerados scripts PowerShell que são transferidos via WinRM (utilizando a biblioteca pywinrm), para então serem executados nos hosts.

Pré-requisitos:

  • Windows 8.1 e Windows 10
  • Windows Server 2012, 2012 R2, 2016, 2019 e 2022
  • PowerShell 3.0 ou maior
  • .NET 4.0 ou maior

Atualizando o PowerShell e .NET Framework

O Ansible requer o PowerShell versão 3.0 e .NET Framework 4.0, ou mais recente, para funcionar em sistemas operacionais mais antigos, como Server 2008 e Windows 7. A imagem base não atende a esse requisito. Você pode usar o script Upgrade-PowerShell.ps1 para atualizá-los.

Este é o exemplo extraído do site oficial e você pode executá-lo tranquilamente no Windows:

[Net.ServicePointManager]::SecurityProtocol = [Net.SecurityProtocolType]::Tls12
$url = "https://raw.githubusercontent.com/jborean93/ansible-windows/master/scripts/Upgrade-PowerShell.ps1"
$file = "$env:temp\Upgrade-PowerShell.ps1"
$username = "Administrator"
$password = "Password"

(New-Object -TypeName System.Net.WebClient).DownloadFile($url, $file)
Set-ExecutionPolicy -ExecutionPolicy Unrestricted -Force

# Version can be 3.0, 4.0 or 5.1
&$file -Version 5.1 -Username $username -Password $password -Verbose
Figura 01. upgrade-powershell.ps1

Uma vez concluído, você precisará remover o logon automático e definir a política de execução de volta ao padrão (Restricted para clientes Windows ou RemoteSigned para servidores Windows). Você pode fazer isso com os seguintes comandos do PowerShell:

# This isn't needed but is a good security practice to complete
Set-ExecutionPolicy -ExecutionPolicy RemoteSigned -Force

$reg_winlogon_path = "HKLM:\Software\Microsoft\Windows NT\CurrentVersion\Winlogon"
Set-ItemProperty -Path $reg_winlogon_path -Name AutoAdminLogon -Value 0
Remove-ItemProperty -Path $reg_winlogon_path -Name DefaultUserName -ErrorAction SilentlyContinue
Remove-ItemProperty -Path $reg_winlogon_path -Name DefaultPassword -ErrorAction SilentlyContinue
Figura 02. Set-ExecutionPolicy RemoteSigned

O script funciona verificando quais programas precisam ser instalados (como .NET Framework 4.5.2) e qual versão do PowerShell é necessária. Se uma reinicialização for necessária e os parâmetros de nome de usuário e senha estiverem definidos, o script será reinicializado e conectado automaticamente quando voltar da reinicialização. O script continuará até que não sejam necessárias mais ações e a versão do PowerShell corresponda à versão de destino. Se os parâmetros de nome de usuário e senha não estiverem definidos, o script solicitará que o usuário reinicialize manualmente e faça logon quando necessário. Quando o usuário fizer login novamente, o script continuará de onde parou e o processo continuará até que não sejam necessárias mais ações.

Configurando o WinRM

Depois que o Powershell for atualizado para o mínimo (versão 3.0+), a etapa final é configurar o serviço WinRM para que o Ansible possa se conectar a ele. Existem dois componentes principais do serviço WinRM que ditam como o Ansible pode interagir com o Windows: o listener e o próprio service

WinRM Listener

Os serviços WinRM escutam solicitações em uma ou mais portas. Cada uma dessas portas deve ter um listener criado e configurado. Para visualizar os ouvintes atuais em execução no serviço WinRM, execute o seguinte comando:

winrm enumerate winrm/config/Listener

A saída será algo mais ou menos assim:

Figura 03. winrm enumerate

Algumas das principais opções que são úteis para entender são:

  • Transport: Independentemente de o ouvinte ser executado em HTTP ou HTTPS, é recomendável usar um ouvinte em HTTPS, pois os dados são criptografados sem a necessidade de outras alterações.
  • Port: A porta em que o listener é executado, por padrão é 5985 para HTTP e 5986 para HTTPS. Esta porta pode ser alterada para o que for necessário e corresponde ao host var ansible_port.
  • URLPrefix: O prefixo da URL para atender, por padrão é wsman. Se isso for alterado, o host var ansible_winrm_path deve ser definido com o mesmo valor.
  • CertificateThumbprint: Se estiver executando em um ouvinte HTTPS, esta é a impressão digital do certificado no Windows Certificate Store usado na conexão.
Setup Listener

Existem três maneiras de configurar um ouvinte WinRM:

  • Usando winrm quickconfig para HTTP ou winrm quickconfig -transport:https para HTTPS. Essa é a opção mais fácil de usar ao executar fora de um ambiente de domínio e é necessário um ouvinte simples. Ao contrário das outras opções, esse processo também tem o benefício adicional de abrir o Firewall para as portas necessárias e iniciar o serviço WinRM.
  • Usando Objetos de Diretiva de Grupo. Esta é a melhor maneira de criar um listener quando o host é membro de um domínio porque a configuração é feita automaticamente sem nenhuma entrada do usuário. Para obter mais informações sobre objetos de política de grupo, consulte a documentação de objetos de política de grupo.
  • Usando o PowerShell para criar o ouvinte com uma configuração específica. Isso pode ser feito executando os seguintes comandos do PowerShell:
$selector_set = @{
    Address = "*"
    Transport = "HTTPS"
}
$value_set = @{
    CertificateThumbprint = "E6CDAA82EEAF2ECE8546E05DB7F3E01AA47D76CE"
}

New-WSManInstance -ResourceURI "winrm/config/Listener" -SelectorSet $selector_set -ValueSet $value_set

WinRM Service

Há várias opções que podem ser definidas para controlar o comportamento do componente de serviço WinRM, incluindo opções de autenticação e configurações de memória. Para obter uma saída das opções de configuração de serviço atuais, execute o seguinte comando:

winrm get winrm/config/Service
winrm get winrm/config/Winrs
Figura 04. winrm get config

Embora muitas dessas opções raramente devam ser alteradas, algumas podem afetar facilmente as operações no WinRM e são úteis para entender. Algumas das opções importantes são:

  • Service\AllowUnencrypted: Esta opção define se o WinRM permitirá o tráfego executado em HTTP sem criptografia de mensagem. A criptografia em nível de mensagem só é possível quando ansible_winrm_transport for ntlm, kerberos ou credssp. Por padrão, isso é falso e só deve ser definido como verdadeiro ao depurar mensagens do WinRM.
  • Service\Auth*: Esses sinalizadores definem quais opções de autenticação são permitidas com o serviço WinRM. Por padrão, Negociar (NTLM) e Kerberos estão habilitados.
  • Service\Auth\CbtHardeningLevel: especifica se os tokens de associação de canal não são verificados (Nenhum), verificados, mas não obrigatórios (Relaxado) ou verificados e obrigatórios (Estritos). O CBT é usado apenas ao se conectar com NTLM ou Kerberos por HTTPS.
  • Service\CertificateThumbprint: Esta é a impressão digital do certificado usado para criptografar o canal TLS usado com a autenticação CredSSP. Por padrão, isso está vazio; um certificado autoassinado é gerado quando o serviço WinRM é iniciado e usado no processo TLS.
  • Winrs\MaxShellRunTime: Este é o tempo máximo, em milissegundos, que um comando remoto pode executar.
  • Winrs\MaxMemoryPerShellMB: Esta é a quantidade máxima de memória alocada por shell, incluindo os processos filho do shell.

Autenticando no WinRM

Ao contrário dos hosts Linux/Unix, que usam SSH por padrão, os hosts Windows são configurados com WinRM. WinRM é um protocolo de gerenciamento usado pelo Windows para se comunicar remotamente com outro servidor. É um protocolo baseado em SOAP que se comunica por HTTP/HTTPS e está incluído em todos os sistemas operacionais Windows recentes. Desde o Windows Server 2012, o WinRM foi habilitado por padrão, mas na maioria dos casos é necessária uma configuração extra para usar o WinRM com o Ansible.

O Ansible usa o pacote pywinrm para se comunicar com servidores Windows pelo WinRM. Ele não é instalado por padrão com o pacote Ansible, mas pode ser instalado executando o seguinte:

pip install "pywinrm>=0.3.0"

Ao se conectar a um host Windows, existem várias opções diferentes que podem ser usadas ao autenticar com uma conta. O tipo de autenticação pode ser definido em hosts ou grupos de inventário com a variável ansible_winrm_transport.

A tabela a seguir é uma visão geral das opções:

Figura 05. opções de autenticação

Cobriremos aqui somente as três principais que são: básica, kerberos e NTLM

Basic

A autenticação básica é uma das opções mais simples de usar, mas também é a mais insegura. Isso ocorre porque o nome de usuário e a senha são simplesmente codificados em base64 e, se um canal seguro não estiver em uso (por exemplo, HTTPS), ele poderá ser decodificado por qualquer pessoa. A autenticação básica só pode ser usada para contas locais (não contas de domínio).

O exemplo a seguir mostra vars de host configuradas para autenticação básica:

ansible_user: LocalUsername
ansible_password: Password
ansible_connection: winrm
ansible_winrm_transport: basic

A autenticação básica não é habilitada por padrão em um host Windows, mas pode ser habilitada executando o seguinte no PowerShell:

Set-Item -Path WSMan:\localhost\Service\Auth\Basic -Value $true

Kerberos

Kerberos é a opção de autenticação recomendada para usar ao executar em um ambiente de domínio. O Kerberos oferece suporte a recursos como delegação de credenciais e criptografia de mensagens por HTTP e é uma das opções mais seguras disponíveis por meio do WinRM.

O Kerberos requer algum trabalho de configuração adicional no host Ansible antes de poder ser usado corretamente.

O exemplo a seguir mostra vars de host configuradas para autenticação Kerberos:

ansible_user: [email protected]
ansible_password: Password
ansible_connection: winrm
ansible_port: 5985
ansible_winrm_transport: kerberos

Existem algumas dependências de pacote que devem ser instaladas antes de usar o Kerberos. Observe abaixo a lista de dependências baseada na sua distro favorita (em uso):

# Via Yum (RHEL/Centos/Fedora for the older version)
yum -y install gcc python-devel krb5-devel krb5-libs krb5-workstation

# Via DNF (RHEL/Centos/Fedora for the newer version)
dnf -y install gcc python3-devel krb5-devel krb5-libs krb5-workstation

# Via Apt (Ubuntu)
sudo apt-get install python-dev libkrb5-dev krb5-user

# Via Portage (Gentoo)
emerge -av app-crypt/mit-krb5
emerge -av dev-python/setuptools

# Via Pkg (FreeBSD)
sudo pkg install security/krb5

# Via OpenCSW (Solaris)
pkgadd -d http://get.opencsw.org/now
/opt/csw/bin/pkgutil -U
/opt/csw/bin/pkgutil -y -i libkrb5_3

# Via Pacman (Arch Linux)
pacman -S krb5

Uma vez que as dependências foram instaladas, o wrapper python-kerberos pode ser instalado usando pip:

pip install pywinrm[kerberos]

NTLM

O NTLM é um mecanismo de autenticação mais antigo usado pela Microsoft que pode oferecer suporte a contas locais e de domínio. O NTLM é habilitado por padrão no serviço WinRM, portanto, nenhuma configuração é necessária antes de usá-lo.

O NTLM é o protocolo de autenticação mais fácil de usar e é mais seguro que a autenticação básica. Se estiver executando em um ambiente de domínio, o Kerberos deve ser usado em vez do NTLM.

O Kerberos tem várias vantagens sobre o uso do NTLM:

  • O NTLM é um protocolo mais antigo e não oferece suporte a protocolos de criptografia mais recentes.
  • O NTLM é mais lento para autenticar porque requer mais viagens de ida e volta ao host no estágio de autenticação.
  • Ao contrário do Kerberos, o NTLM não permite delegação de credenciais.

Este exemplo mostra as variáveis de host configuradas para usar a autenticação NTLM:

ansible_user: LocalUsername
ansible_password: Password
ansible_connection: winrm
ansible_winrm_transport: ntlm

Executando o Ansible para Windows

Ao usar o Ansible para gerenciar o Windows, muitas das sintaxes e regras que se aplicam aos hosts Unix/Linux também se aplicam ao Windows. Todavia, ainda há algumas diferenças quando se trata de certos componentes, como por exemplo, separadores de caminho e tarefas específicas do sistema operacional.

Instalando software

Existem três maneiras principais de usar o Ansible para instalar software:

  • Usando o módulo win_chocolatey. Isso origina os dados do programa do repositório público padrão do Chocolatey. Repositórios internos podem ser usados definindo a opção de origem.
  • Usando o módulo win_package. Isso instala o software usando um instalador MSI ou .exe de um caminho ou URL local/de rede.
  • Usando o módulo win_command ou win_shell para executar um instalador manualmente.

O módulo win_chocolatey é recomendado, pois possui a lógica mais completa para verificar se um pacote já foi instalado e está atualizado.

Abaixo estão alguns exemplos de uso das três opções para instalar o 7-Zip:

# Install/uninstall with chocolatey
- name: Ensure 7-Zip is installed via Chocolatey
  win_chocolatey:
    name: 7zip
    state: present

- name: Ensure 7-Zip is not installed via Chocolatey
  win_chocolatey:
    name: 7zip
    state: absent

# Install/uninstall with win_package
- name: Download the 7-Zip package
  win_get_url:
    url: https://www.7-zip.org/a/7z1701-x64.msi
    dest: C:\temp\7z.msi

- name: Ensure 7-Zip is installed via win_package
  win_package:
    path: C:\temp\7z.msi
    state: present

- name: Ensure 7-Zip is not installed via win_package
  win_package:
    path: C:\temp\7z.msi
    state: absent

# Install/uninstall with win_command
- name: Download the 7-Zip package
  win_get_url:
    url: https://www.7-zip.org/a/7z1701-x64.msi
    dest: C:\temp\7z.msi

- name: Check if 7-Zip is already installed
  win_reg_stat:
    name: HKLM:\SOFTWARE\Microsoft\Windows\CurrentVersion\Uninstall\{23170F69-40C1-2702-1701-000001000000}
  register: 7zip_installed

- name: Ensure 7-Zip is installed via win_command
  win_command: C:\Windows\System32\msiexec.exe /i C:\temp\7z.msi /qn /norestart
  when: 7zip_installed.exists == false

- name: Ensure 7-Zip is uninstalled via win_command
  win_command: C:\Windows\System32\msiexec.exe /x {23170F69-40C1-2702-1701-000001000000} /qn /norestart
  when: 7zip_installed.exists == true
Figura 06. antes
Figura 07. durante
Figura 08. depois

Criando usuários e grupos

O Ansible pode ser usado para adicionar usuários e grupos ao Windows, de forma local e/ou em um domínio do Active Directory.

Os módulos win_user, win_group e win_group_membership gerenciam usuários, grupos e associações de grupos do Windows localmente. Veja a seguir um exemplo de criação de contas e grupos locais que podem acessar uma pasta no mesmo host:

- name: Create local group to contain new users
  win_group:
    name: LocalGroup
    description: Allow access to C:\Development folder

- name: Create local user
  win_user:
    name: '{{ item.name }}'
    password: '{{ item.password }}'
    groups: LocalGroup
    update_password: no
    password_never_expires: yes
  loop:
  - name: User1
    password: Password1
  - name: User2
    password: Password2

- name: Create Development folder
  win_file:
    path: C:\Development
    state: directory

- name: Set ACL of Development folder
  win_acl:
    path: C:\Development
    rights: FullControl
    state: present
    type: allow
    user: LocalGroup

- name: Remove parent inheritance of Development folder
  win_acl_inheritance:
    path: C:\Development
    reorganize: yes
    state: absent
Figura 09. antes
Figura 10. durante
Figura 11. depois

Os módulos win_domain_user e win_domain_group gerenciam usuários e grupos em um domínio. Veja abaixo um exemplo de como garantir que um lote de usuários de domínio seja criado:

- name: Ensure each account is created
  win_domain_user:
    name: '{{ item.name }}'
    upn: '{{ item.name }}@MY.DOMAIN.COM'
    password: '{{ item.password }}'
    password_never_expires: no
    groups:
    - Test User
    - Application
    company: Ansible
    update_password: on_create
  loop:
  - name: Test User
    password: Password
  - name: Admin User
    password: SuperSecretPass01
  - name: Dev User
    password: '@fvr3IbFBujSRh!3hBg%wgFucD8^x8W5'

Rodando tarefas agendadas

O WinRM possui algumas restrições que causam erros ao executar determinados comandos. Uma maneira de contornar essas restrições é executar um comando por meio de uma tarefa agendada. Uma tarefa agendada é um componente do Windows que oferece a capacidade de executar um executável em uma agenda e/ou em uma conta diferente.

O Ansible versão 2.5 adicionou módulos que facilitam o trabalho com tarefas agendadas no Windows. Veja a seguir um exemplo de execução de um script como uma tarefa agendada que se exclui após a execução:

- name: Create scheduled task to run a process
  win_scheduled_task:
    name: adhoc-task
    username: SYSTEM
    actions:
    - path: PowerShell.exe
      arguments: |
        Start-Sleep -Seconds 30  # This isn't required, just here as a demonstration
        New-Item -Path C:\temp\test -ItemType Directory
    # Remove this action if the task shouldn't be deleted on completion
    - path: cmd.exe
      arguments: /c schtasks.exe /Delete /TN "adhoc-task" /F
    triggers:
    - type: registration

- name: Wait for the scheduled task to complete
  win_scheduled_task_stat:
    name: adhoc-task
  register: task_stat
  until: (task_stat.state is defined and task_stat.state.status != "TASK_STATE_RUNNING") or (task_stat.task_exists == False)
  retries: 12
  delay: 10
Figura 12. antes
Figura 13. depois

É isso aí pessoal \o/\o/\o/ Missão cumprida!

Até breve …

( CURTA, COMPARTILHE, COMENTE )

REFERÊNCIAS:

https://www.ansible.com/for/windows

https://docs.ansible.com/ansible/latest/user_guide/windows.html

https://www.redhat.com/pt-br/technologies/management/ansible/automate-microsoft-windows-with-ansible

http://ansible-br.org/primeiros-passos/windows-e-ansible/

Deixe uma resposta

Este site utiliza o Akismet para reduzir spam. Saiba como seus dados em comentários são processados.