diff --git a/README.md b/README.md index 755cb45..14a6907 100644 --- a/README.md +++ b/README.md @@ -193,6 +193,156 @@ jobs: ``` Because the workflow runs on a self-hosted runner inside the internal network, it can resolve `db-primary.internal.example.com` -- hosts that would not be reachable from GitHub-hosted runners. The action's Docker image supplies Ansible and all dependencies, so no additional setup is needed on the runner host. + + +## Enabling WinRM on Windows Nodes for Ansible + +WinRM (Windows Remote Management) is Microsoft's implementation of the WS-Management protocol. Ansible uses WinRM to communicate with Windows hosts because Windows does not ship with an SSH server by default. Before you can manage a Windows node with Ansible, WinRM must be enabled and configured on that node. + +### 1. Enable WinRM on the Windows node + +Run the following commands in an **elevated PowerShell** session (Run as Administrator) on each Windows target: + +```powershell +# Quick configuration of WinRM listener +winrm quickconfig -q + +# Enable WSMan CredSSP (required for credential delegation) +Enable-WSManCredSSP -Role Server -Force +``` + +`winrm quickconfig` does the following: +- Starts the WinRM service and sets it to auto-start. +- Creates an HTTP listener on port `5985`. +- Adds a firewall exception for WS-Management traffic. + +### 2. Configure the firewall + +If the firewall rules are not created automatically, or if you need HTTPS access on port `5986`, add them manually: + +```powershell +New-NetFirewallRule -DisplayName "Allow WinRM TCP 5985 (HTTP)" -Direction Inbound -Protocol TCP -LocalPort 5985 -Action Allow +New-NetFirewallRule -DisplayName "Allow WinRM TCP 5986 (HTTPS)" -Direction Inbound -Protocol TCP -LocalPort 5986 -Action Allow +``` + +| Port | Protocol | Use | +|------|----------|-----| +| 5985 | HTTP | Default WinRM listener (can be encrypted via Kerberos/NTLM) | +| 5986 | HTTPS | WinRM over SSL (requires a certificate) | + +### 3. Set up HTTPS with a self-signed certificate (optional but recommended) + +For production environments, use HTTPS with a valid certificate signed by a trusted CA. For testing, you can create a self-signed certificate: + +```powershell +# Create a self-signed certificate +$cert = New-SelfSignedCertificate -CertStoreLocation Cert:\LocalMachine\My ` + -DnsName "$env:COMPUTERNAME" -FriendlyName "WinRM HTTPS" + +# Create the HTTPS listener +New-Item -Path WSMan:\Localhost\Listener -Transport HTTPS -Address * ` + -CertificateThumbprint $cert.Thumbprint -Force +``` + +When using a self-signed certificate, set `ansible_winrm_server_cert_validation=ignore` in your Ansible inventory to bypass certificate validation. + +### 4. Verify WinRM is listening + +On the Windows node itself, confirm the listeners are active: + +```powershell +winrm enumerate winrm/config/Listener +``` + +You should see output similar to: + +``` +Listener + Address = * + Transport = HTTP + Port = 5985 + Enabled = true + ... + +Listener + Address = * + Transport = HTTPS + Port = 5986 + Enabled = true + ... +``` + +### 5. Test WinRM connectivity from the control node + +From the Ansible control node (or the GitHub Actions runner), verify you can reach the Windows host over WinRM **before** running playbooks: + +```bash +# Test HTTP (port 5985) +ansible windows -i inventory.ini -m ansible.windows.win_ping + +# Or use the ansible-cli action locally via Docker +docker run --rm eftechcombr/ansible-cli-github-action \ + ansible windows -i inventory.ini -m ansible.windows.win_ping +``` + +If connectivity fails, check that: +- The Windows node is reachable from the runner (no firewall blocking). +- The WinRM service is running (`Get-Service WinRM`). +- The `ansible_user` has the necessary permissions. +- CredSSP or the chosen transport (NTLM, Kerberos) is correctly configured. + +### 6. Inventory variables for Windows nodes + +When using the `ansible-cli` action with Windows targets, your inventory must include the following variables: + +```ini +[windows] +windows-server-01.example.com + +[windows:vars] +ansible_connection=winrm +ansible_winrm_transport=ntlm +ansible_user=Administrator +ansible_password={{ windows_admin_password }} +ansible_winrm_server_cert_validation=ignore +``` + +| Variable | Value | Purpose | +|----------|-------|---------| +| `ansible_connection` | `winrm` | Tells Ansible to use the WinRM connection plugin instead of SSH. | +| `ansible_winrm_transport` | `ntlm` / `credssp` / `kerberos` | Authentication protocol. NTLM works for most environments; CredSSP is needed for credential delegation (e.g., when the playbook needs to pass credentials to a second host). | +| `ansible_user` | `Administrator` | Local or domain user with admin privileges. | +| `ansible_password` | `{{ password_variable }}` | The user's password (use secrets in CI). | +| `ansible_winrm_server_cert_validation` | `ignore` | Required when using a self-signed certificate. Omit or set to `validate` for CA-signed certs. | + +### 7. Common issues and tips + +**Python fork-safety on macOS** +If you are developing or testing locally on macOS with zsh, you may encounter crashes when Ansible spawns subprocesses. Add this to your `.zshrc`: + +```bash +export OBJC_DISABLE_INITIALIZE_FORK_SAFETY=YES +``` + +**pywinrm is pre-installed** +The `ansible-cli-github-action` Docker image includes `pywinrm[credssp]`, so no additional Python packages are needed when running inside GitHub Actions. For local testing, install it with: + +```bash +python3 -m venv env +source env/bin/activate +pip install pywinrm[credssp] ansible +``` + +**Transport selection** +- **NTLM** — Simplest; works across domains; does not support double-hop (passing credentials to a second machine). +- **CredSSP** — Enables double-hop; requires `Enable-WSManCredSSP -Role Server -Force` on the Windows host. +- **Kerberos** — Best for domain-joined hosts; provides the strongest security but requires additional setup (keytab or `kinit`). + +**Reference links** +- [Ansible Windows WinRM guide](https://docs.ansible.com/ansible/latest/os_guide/windows_winrm.html) +- [Homebrew and Python PEP 668](https://docs.brew.sh/Homebrew-and-Python#pep-668-python312-and-virtual-environments) + + ## Testing Run the smoke test suite locally to verify the Docker image builds and all Ansible tools work correctly: