Ansible/winrm: "basic: auth method basic requires a password"

Problem:
Basic Auth not working as expected. When running a playbook locally using an ini it works as expected. Running via job I get:

fatal: [win-iot-1.int.m-box.de]: UNREACHABLE! => {"changed": false, "msg": "basic: auth method basic requires a password", "unreachable": true}

Expected outcome:

Foreman and Proxy versions:
3.14

Foreman and Proxy plugin versions:

Distribution and version:
Rocky Linux 9.5

Other relevant data:
The following params are set on the host group:

ansible_connection=winrm
ansible_become=false
ansible_user=ansible
ansible_password=******
ansible_winrm_transport=basic
ansible_winrm_scheme=http
ansible_port=5985
ansible_winrm_server_cert_validation=ignore

Ansible

ansible [core 2.16.14]
  config file = /etc/ansible/ansible.cfg
  configured module search path = ['/usr/share/foreman-proxy/.ansible/plugins/modules', '/usr/share/ansible/plugins/modules']
  ansible python module location = /usr/lib/python3.12/site-packages/ansible
  ansible collection location = /usr/share/foreman-proxy/.ansible/collections:/usr/share/ansible/collections
  executable location = /bin/ansible
  python version = 3.12.5 (main, Apr  2 2025, 00:00:00) [GCC 11.5.0 20240719 (Red Hat 11.5.0-5)] (/usr/bin/python3.12)
  jinja version = 3.1.5
  libyaml = True

cc @nofaralfasi

Does anybody have an idea? Shoud I open an issue?

When looking at the inventory, ansible_password is not included indeed:

Even I have a same issue, are you able to figure out any solution ?

@amgokak - no, not really - ansible_password is still filtered.

I moved away from basic auth winrm; this is the right choice I guess (only wanted to give it a quick test).
My windows hosts now use cert based authenticaton and integrate mostly with ansible_winrm_ host vars. Below the snippet I use at deploy time from foreman; it adds a cert I generated for foreman_proxy user. In the end the config more or less equals SSH. Because it is Windows after all, the setup is involed. I tested this with Windows 10/11 Pro and thier IoT LTSC equivalents.

# WAIK-Ansible-setup.ps1
# Create ansible user account
$ansibleUser = "<%= host_param('ansible_user') ? host_param('ansible_user') : 'ansible' %>"
$ansiblePassword = <% if host_param('ansiblecert_pem_string') or !host_param("ansible_password") %>"$(-join ((48..57) + (97..122) | Get-Random -Count 14 | % {[char]$_}))"<% else %>'<%= host_param("ansible_password") %>'<%end%>
$winRmPort = <%= host_param('ansible_port') ? host_param('ansible_port') : '5986' %>

$createUserParams = @{
    Name = $ansibleUser
    Description = "Ansible User"
    Password = ConvertTo-SecureString -AsPlainText -Force -String $ansiblePassword
    PasswordNeverExpires = $true
    UserMayNotChangePassword = $true
}
Remove-LocalUser -Name $ansibleUser -ErrorAction SilentlyContinue
New-LocalUser @createUserParams | Add-LocalGroupMember -Group Administrators

# Allows local user accounts to be used with WinRM
# This can be ignored if using domain accounts
$tokenFilterParams = @{
    Path         = 'HKLM:\SOFTWARE\Microsoft\Windows\CurrentVersion\Policies\System'
    Name         = 'LocalAccountTokenFilterPolicy'
    Value        = 1
    PropertyType = 'DWORD'
    Force        = $true
}
New-ItemProperty @tokenFilterParams

# Firewall settings
Get-NetConnectionProfile | foreach{Set-NetConnectionProfile -InterfaceIndex $_.InterfaceIndex -NetworkCategory Private -Confirm:$false -PassThru}
New-NetFirewallRule -DisplayName 'Allow WinRM HTTPS' -Direction Inbound -LocalPort $winRmPort -Protocol TCP -Action Allow

$winrmcert = New-SelfSignedCertificate -DnsName ([System.Net.Dns]::GetHostByName($env:computerName)).Hostname -CertStoreLocation "cert:LocalMachine\My" -FriendlyName $ansibleUser
$listenerParams   = @{
	ResourceURI   = "winrm/config/Listener"
	SelectorSet   = @{
		address   = "*"
		transport = "https"
	}
	ValueSet      = @{
		Hostname              = [System.Net.Dns]::GetHostByName(($env:computerName)).Hostname
		CertificateThumbprint = $winrmcert.Thumbprint
		Enabled               = $true
        Port                  = $winRmPort
	}
}

# Setup WinRM instance
Remove-Item -Path "WSMan:\localhost\Listener\*" -Recurse -Force -ErrorAction SilentlyContinue
Set-WSManQuickConfig -Force
New-WSManInstance @listenerParams

# Remove HTTP listener from Quick Config
Get-ChildItem -Path WSMan:\localhost\Listener |
	Where-Object Keys -contains "Transport=HTTP" |
	Remove-Item -Recurse -Force

<% authTransport = (host_param('ansible_psrp_auth') || host_param("ansible_winrm_transport")) || 'basic' -%>
# Using Auth: <%= authTransport %>
<% case authTransport -%>
<% when 'certificate' -%>
$cert_file = 'cert.pem'
[IO.File]::WriteAllLines($cert_file, '<%= host_param("ansiblecert_pem_string") %>')
$cert = [System.Security.Cryptography.X509Certificates.X509Certificate2]::new($cert_file)

$store = Get-Item -LiteralPath Cert:\LocalMachine\TrustedPeople
$store.Open('ReadWrite')
$store.Add($cert)
$store.Dispose()

$store = Get-Item -LiteralPath Cert:\LocalMachine\Root
$store.Open('ReadWrite')
$store.Add($cert)
$store.Dispose()

$certChain = [System.Security.Cryptography.X509Certificates.X509Chain]::new()
[void]$certChain.Build($cert)
$caThumbprint = $certChain.ChainElements.Certificate[-1].Thumbprint

$certMapping = @{
    Path       = 'WSMan:\localhost\ClientCertificate'
    Subject    = $cert.GetNameInfo('UpnName', $false)
    Issuer     = $caThumbprint
    Credential = [PSCredential]::new($ansibleUser, (ConvertTo-SecureString -AsPlainText -Force -String $ansiblePassword))
    Force      = $true
}
New-Item @certMapping
Set-Item -Path WSMan:\localhost\Service\Auth\Certificate -Value $true
Remove-Item -Path $cert_file -Force
<% when 'basic' -%>
cmd.exe /c winrm set "winrm/config/service/auth" '@{Basic="true"}'
cmd.exe /c winrm set "winrm/config/client/auth" '@{Basic="true"}'
<% end %>
# Default config for reliability
cmd.exe /c winrm set "winrm/config" '@{MaxTimeoutms="1800000"}'
cmd.exe /c winrm set "winrm/config/winrs" '@{MaxMemoryPerShellMB="1024"}'
winrm enumerate "winrm/config/Listener"

These are my hostgroup vars; they shoud get you started. Keep in mind:

  • ansiblecert_pem_string is the content of ansible_winrm_cert_pem
  • The forman_proxy user can read both cert files
  • If you have any suggestions - reply back here!

Cheers, Helge