Proteja o WinRM para o Ansible com Certificados em 10 Etapas

O Ansible está se tornando uma das ferramentas de gerenciamento de configuração mais, se não a mais utilizada hoje em dia. O Ansible é uma ferramenta útil (e gratuita na maioria dos casos) que permite aos engenheiros DevOps e aos engenheiros/administradores de sistemas construir e manter infraestruturas em todos os ambientes de maneira idempotente, como códigode infraestrutura. No entanto, configurá-lo para se comunicar com o Windows via WinRM para o Ansible pode ser um desafio.

Assim como muitos outros componentes de infraestrutura, o Ansible pode implantar e manter estados de configuração em hosts Windows. O Ansible se conecta a esses hosts Windows via WinRM, embora estejam experimentando com SSH.

Ao configurar o WinRM para o Ansible, você tem algumas opções diferentes, que variam da facilidade de configuração às implicações de segurança. Muitas pessoas optam pela abordagem mais fácil; autenticação básica usando HTTP. Embora você evite o trabalho extra envolvendo certificados, nunca é uma boa ideia enviar dados não criptografados pela rede, a menos que seja necessário.

Neste artigo, você vai aprender como configurar o WinRM para o Ansible usando autenticação baseada em certificado com certificados autoassinados para que o Ansible possa se comunicar com eles.

A configuração que você aprenderá neste tutorial não se aplica apenas ao Ansible como cliente. Essa autenticação baseada em certificado também pode ser aplicada a outros clientes WinRM, como outros hosts do Windows.

Suposições

Este artigo será um tutorial passo a passo. Se você pretende seguir os passos apresentados aqui para configurar o WinRM para o Ansible, o tutorial pressupõe:

  • Você já tem o Ansible instalado em um host Linux.
  • Você configurou um inventário do Ansible com base nos seus hosts do Windows.
  • Você tem um servidor Windows 2016 ou posterior para gerenciar. Alguns cmdlets usados neste tutorial não funcionarão com versões mais antigas do Windows.
  • O host do Windows não está em um domínio. Embora os exemplos tenham sido executados em um host não associado a um domínio, esta configuração deve funcionar também em hosts associados a um domínio.
  • Você tem acesso RDP ou console ao host do Windows e está logado como administrador local.
  • Você está familiarizado com o PowerShell. Quase todos os exemplos usarão código PowerShell para fazer alterações no host do Windows.

Cada seção usará um trecho de código que depende do anterior. Alguns trechos farão referência a variáveis definidas anteriormente. Certifique-se de deixar seu console aberto enquanto copia/cola este código se planeja seguir exatamente.

Se você só quer o código sem toda a explicação, sinta-se à vontade para baixar este gist do GitHub.

Habilitar Remoção do PowerShell para WinRm para Ansible

Embora todos os servidores Windows Server 2016 ou posterior tenham a Remoção do PowerShell habilitada, é sempre uma boa ideia confirmar isso.

No host Windows que deseja gerenciar, abra um console do PowerShell como administrador e execute o seguinte trecho de código. Este trecho de código garante que o serviço WinRm seja iniciado e configurado para iniciar automaticamente durante a inicialização do sistema.

Set-Service -Name "WinRM" -StartupType Automatic
Start-Service -Name "WinRM"

Em seguida, certifique-se de que a Remoção do PowerShell está habilitada verificando primeiro se há alguma configuração de sessão ativa. Se não houver, verifique se não há nenhum ouvinte disponível. O WinRm para Ansible deve ter pelo menos um ouvinte. Se alguma dessas condições retornar vazia, execute Enable-PSRemoting.

if (-not (Get-PSSessionConfiguration) -or (-not (Get-ChildItem WSMan:\localhost\Listener))) {
    ## Use SkipNetworkProfileCheck para disponibilizar mesmo em perfis públicos do Firewall do Windows
    ## Use Force para não ser solicitado se temos certeza ou não.
    Enable-PSRemoting -SkipNetworkProfileCheck -Force
}
Configuring WinRM for Ansible (a listener) via the winrm command

Habilitar Autenticação Baseada em Certificado

Por padrão, o WinRM não está configurado para autenticação baseada em certificado. Você deve habilitar isso configurando o WSMan conforme mostrado abaixo.

#região Habilitar autenticação baseada em certificado
Set-Item -Path WSMan:\localhost\Service\Auth\Certificate -Value $true
#fimregião

Criar uma Conta de Usuário Local

Para usar a autenticação baseada em certificado do WinRM para autenticação do Ansible, você deve “mapear” uma conta de usuário local para um certificado. Você poderia usar a conta de administrador local para fazer isso, mas é sempre uma boa ideia criar uma conta específica para facilitar a administração.

O trecho de código a seguir está criando uma conta de usuário local para o WinRM do Ansible chamada ansibletestuser com uma senha de p@$$w0rd12 se ela não existir. Para garantir que ela sempre permaneça ativa, a senha dessa conta nunca expirará.

$testUserAccountName = 'ansibletestuser'
$testUserAccountPassword = (ConvertTo-SecureString -String 'p@$$w0rd12' -AsPlainText -Force)
if (-not (Get-LocalUser -Name $testUserAccountName -ErrorAction Ignore)) {
    $newUserParams = @{
        Name                 = $testUserAccountName
        AccountNeverExpires  = $true
        PasswordNeverExpires = $true
        Password             = $testUserAccountPassword
    }
    $null = New-LocalUser @newUserParams
}

Criar o Certificado do Cliente

O WinRM para o Ansible (de forma segura) deve ter dois certificados: um certificado de cliente e um certificado de servidor.

Você pode usar o mesmo certificado para o cliente/servidor, mas tive problemas com essa abordagem. Nos documentos do Ansible e em muitas outras fontes, você encontrará instruções para gerar o certificado do cliente por meio do cmdlet New-SelfSignedCert do PowerShell. Embora esse método possa funcionar, não consegui fazer isso funcionar facilmente.

Para criar o certificado do cliente para WinRM no Ansible, você deve criar uma chave privada e uma chave pública. Comece fazendo SSH no host do Ansible e execute o seguinte comando openssl. Este comando cria uma chave privada em um arquivo chamado cert_key.pem e uma chave pública chamada cert.pem. A utilização da chave será autenticação do cliente (1.3.6.1.4.1.311.20.2.3) “mapeada” para a conta de usuário local que você criou anteriormente chamada ansibletestuser.

## Esta é a chave pública gerada a partir do servidor Ansible usando:
cat > openssl.conf << EOL
distinguished_name = req_distinguished_name
[req_distinguished_name]
[v3_req_client]
extendedKeyUsage = clientAuth
subjectAltName = otherName:1.3.6.1.4.1.311.20.2.3;UTF8:ansibletestuser@localhost
EOL
export OPENSSL_CONF=openssl.conf
openssl req -x509 -nodes -days 3650 -newkey rsa:2048 -out cert.pem -outform PEM -keyout cert_key.pem -subj "/CN=ansibletestuser" -extensions v3_req_client
rm openssl.conf 

Mais um passo em direção à autenticação WinRM do Ansible!

Importe o Certificado do Cliente

Depois de criar o certificado do cliente para WinRm no Ansible, será necessário importá-lo em dois repositórios de certificados no host do Windows para que o WinRm no Ansible funcione. Para fazer isso, primeiro transfira a chave pública cert.pem para o host do Windows. O exemplo abaixo pressupõe que a chave existe em C:\cert.pem.

Assim que tiver o certificado público no host do Windows, importe-o nos repositórios de certificados Autoridades de Certificação Raiz Confiáveis e Pessoas Confiáveis usando Import-Certificate, conforme mostrado abaixo.

$pubKeyFilePath = 'C:\cert.pem'

## Importe a chave pública em Autoridades de Certificação Raiz Confiáveis e Pessoas Confiáveis
$null = Import-Certificate -FilePath $pubKeyFilePath -CertStoreLocation 'Cert:\LocalMachine\Root'
$null = Import-Certificate -FilePath $pubKeyFilePath -CertStoreLocation 'Cert:\LocalMachine\TrustedPeople'

Crie o Certificado do Servidor

O WinRM para o Ansible precisa de um certificado definido com uma utilização de chave para autenticação do servidor. Esse certificado será armazenado no repositório de certificados LocalMachine\My do host do Windows. Crie o certificado autoassinado usando o trecho de código abaixo.

$hostname = hostname
$serverCert = New-SelfSignedCertificate -DnsName $hostName -CertStoreLocation 'Cert:\LocalMachine\My'

Criar o Listener WinRm do Ansible

Depois de criar ambos os certificados, agora você deve criar um ouvinte WinRm no host do Windows. Este ouvinte começa a escutar na porta 5986 para conexões de entrada. Uma vez criado, este ouvinte aceita conexões de entrada e tentará criptografar os dados usando o certificado do servidor criado anteriormente.

O PowerShell Remoting utiliza este ouvinte WinRM como transporte uma vez que a autenticação tenha ocorrido.

No trecho de código abaixo, você pode ver um ótimo exemplo de verificação de um ouvinte HTTPS existente. Se nenhum ouvinte for encontrado usando o certificado do servidor criado anteriormente, ele criará um novo.

## Encontrar todos os ouvintes HTTPS
$httpsListeners = Get-ChildItem -Path WSMan:\localhost\Listener\ | where-object { $_.Keys -match 'Transport=HTTPS' }

## Se nenhum ouvinte estiver definido ou nenhum ouvinte estiver configurado para funcionar com
## o certificado do servidor criado, criar um novo com um Assunto igual ao nome do host do computador
## e associado ao certificado do servidor.
if ((-not $httpsListeners) -or -not (@($httpsListeners).where( { $_.CertificateThumbprint -ne $serverCert.Thumbprint }))) {
    $newWsmanParams = @{
        ResourceUri = 'winrm/config/Listener'
        SelectorSet = @{ Transport = "HTTPS"; Address = "*" }
        ValueSet    = @{ Hostname = $hostName; CertificateThumbprint = $serverCert.Thumbprint }
        # UseSSL = $true
    }
    $null = New-WSManInstance @newWsmanParams
}

Associar o Certificado do Cliente à Conta de Usuário Local

O próximo passo é garantir que quando o Ansible se conectar ao host do Windows usando o certificado do servidor, ele então execute todas as instruções como um usuário local. Neste caso, toda atividade realizada pelo WinRm para o Ansible usará a conta de usuário local, ansibletestuser.

$credential = New-Object -TypeName System.Management.Automation.PSCredential -ArgumentList $testUserAccountName, $testUserAccountPassword

## Encontrar a impressão digital do certificado para o certificado do cliente criado no host do Ansible
$ansibleCert = Get-ChildItem -Path 'Cert:\LocalMachine\Root' | Where-Object {$_.Subject -eq 'CN=ansibletestuser'}

$params = @{
	Path = 'WSMan:\localhost\ClientCertificate'
	Subject = "$testUserAccountName@localhost"
	URI = '*'
	Issuer = $ansibleCert.Thumbprint
  Credential = $credential
	Force = $true
}
New-Item @params

Permita o WinRm para o Ansible com Controle de Conta de Usuário (UAC)

Se estiver usando uma conta local para mapear um certificado, também deve definir o LocalAccountTokenFilterPolicy para 1 para garantir que o UAC não atrapalhe. O LocalAccountTokenFilterPolicy se aplica a todas as contas locais (não contas de domínio) e faz com que o seu logon de rede seja a parte limitada do seu token. Isso impedirá que ele faça logon, pois o Windows não o reconhece como um Administrador e o WinRM, por padrão, exige que o usuário seja um administrador local.

Ao definir o LocalAccountTokenFilterPolicy, você está instruindo o Windows a não criar um token limitado para logons de rede por uma conta local e usar seu token completo.

$newItemParams = @{
    Path         = 'HKLM:\SOFTWARE\Microsoft\Windows\CurrentVersion\Policies\System'
    Name         = 'LocalAccountTokenFilterPolicy'
    Value        = 1
    PropertyType = 'DWORD'
    Force        = $true
}
$null = New-ItemProperty @newItemParams

Abra a porta 5986 no Firewall do Windows

O WinRm via HTTPS usa a porta 5986. Se você tiver o Firewall do Windows ativado, deve abrir esta porta. Você pode fazer isso executando o seguinte trecho de código PowerShell. Este trecho de código é excessivamente relaxado, permitindo que todos os computadores o usem. Se deseja restringir isso ainda mais, certifique-se de usar o parâmetro LocalAddress e especificar o IP do Ansible.

#região Garantir que o WinRM 5986 esteja aberto no firewall
 $ruleDisplayName = 'Windows Remote Management (HTTPS-In)'
 if (-not (Get-NetFirewallRule -DisplayName $ruleDisplayName -ErrorAction Ignore)) {
     $newRuleParams = @{
         DisplayName   = $ruleDisplayName
         Direction     = 'Inbound'
         LocalPort     = 5986
         RemoteAddress = 'Any'
         Protocol      = 'TCP'
         Action        = 'Allow'
         Enabled       = 'True'
         Group         = 'Windows Remote Management'
     }
     $null = New-NetFirewallRule @newRuleParams
 }
 #endregion

Adicione o Usuário Local ao Grupo de Administradores

Você pode estar se perguntando por que este tutorial não adicionou o usuário local ao grupo de Administradores anteriormente. A razão é que, por algum motivo desconhecido, quando você tenta mapear o certificado do cliente para o usuário, a conta do usuário não pode ser um administrador local.

Execute o trecho de código a seguir para adicionar a conta de usuário local ansibletestuser ao grupo de administradores.

## Adicione o usuário local ao grupo de administradores. Se esta etapa não for feita, o Ansible exibirá um erro "AccessDenied"
Get-LocalUser -Name $testUserAccountName | Add-LocalGroupMember -Group 'Administrators'

Conclusão

Se você seguiu cada uma dessas etapas conforme mostrado, agora deve ser capaz de executar comandos do Ansible em um host Windows. Use o módulo win_shell para realizar seus testes. Se este módulo tiver sucesso, você configurou com sucesso o WinRM para o Ansible e a autenticação baseada em certificado!

Source:
https://adamtheautomator.com/winrm-for-ansible/