summaryrefslogtreecommitdiff
path: root/docsite/rst/intro_windows.rst
blob: 40450325b35197c42358f5bc0e348bfb5405ed9f (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
Windows Support
===============

.. contents:: Topics

.. _windows_how_does_it_work:

Windows: How Does It Work
`````````````````````````

As you may have already read, Ansible manages Linux/Unix machines using SSH by default.

Starting in version 1.7, Ansible also contains support for managing Windows machines.  This uses
native PowerShell remoting, rather than SSH.

Ansible will still be run from a Linux control machine, and uses the "winrm" Python module to talk to remote hosts.

No additional software needs to be installed on the remote machines for Ansible to manage them, it still maintains the agentless properties that make it popular on Linux/Unix.

Note that it is expected you have a basic understanding of Ansible prior to jumping into this section, so if you haven't written a Linux playbook first, it might be worthwhile to dig in there first.

.. _windows_installing:

Installing on the Control Machine
`````````````````````````````````

On a Linux control machine::

   pip install "pywinrm>=0.1.1"

Note:: on distributions with multiple python versions, use pip2 or pip2.x, where x matches the python minor version Ansible is running under.

Active Directory Support
++++++++++++++++++++++++

Ansible supports both local accounts and domain accounts on Windows, to use domain accounts you can use either of these authentication method;

- NTLM
- Kerberos

NTLM authentication can be used on versions of pywinrm>=0.2.0 and does not need any special configuration on the Ansible control host. To use NTLM set ``ansible_winrm_transport=ntlm`` in the host_vars.

To use Kerberos you will need to install the "python-kerberos" module on the Ansible control host (and the MIT krb5 libraries it depends on). The Ansible control host also requires a properly configured computer account in Active Directory.


Installing python-kerberos dependencies
---------------------------------------

.. code-block:: bash

   # Via Yum
   yum -y install python-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

Installing python-kerberos
--------------------------

Once you've installed the necessary dependencies, the python-kerberos wrapper can be installed via pip:

.. code-block:: bash

   pip install kerberos requests_kerberos

Kerberos is installed and configured by default on OS X and many Linux distributions. If your control machine has not already done this for you, you will need to.

Configuring Kerberos
--------------------

Edit your /etc/krb5.conf (which should be installed as a result of installing packages above) and add the following information for each domain you need to connect to:

In the section that starts with

.. code-block:: bash

   [realms]

add the full domain name and the fully qualified domain names of your primary and secondary Active Directory domain controllers.  It should look something like this:

.. code-block:: bash

   [realms]
   
    MY.DOMAIN.COM = {
     kdc = domain-controller1.my.domain.com
     kdc = domain-controller2.my.domain.com
    }


and in the [domain_realm] section add a line like the following for each domain you want to access:

.. code-block:: bash

    [domain_realm]
        .my.domain.com = MY.DOMAIN.COM

You may wish to configure other settings here, such as the default domain.

Testing a kerberos connection
-----------------------------

If you have installed krb5-workstation (yum) or krb5-user (apt-get) you can use the following command to test that you can be authorised by your domain controller.

.. code-block:: bash

   kinit user@MY.DOMAIN.COM

Note that the domain part has to be fully qualified and must be in upper case.

To see what tickets if any you have acquired, use the command klist

.. code-block:: bash

   klist


Troubleshooting kerberos connections
------------------------------------

If you unable to connect using kerberos, check the following:

Ensure that forward and reverse DNS lookups are working properly on your domain.

To test this, ping the windows host you want to control by name then use the ip address returned with nslookup.  You should get the same name back from DNS when you use nslookup on the ip address.  

If you get different hostnames back than the name you originally pinged, speak to your active directory administrator and get them to check that DNS Scavenging is enabled and that DNS and DHCP are updating each other.

Ensure that the Ansible controller has a properly configured computer account in the domain.

Check your Ansible controller's clock is synchronised with your domain controller.  Kerberos is time sensitive and a little clock drift can cause tickets not be granted.

Check you are using the real fully qualified domain name for the domain.  Sometimes domains are commonly known to users by aliases.  To check this run:


.. code-block:: bash

   kinit -C user@MY.DOMAIN.COM
   klist

If the domain name returned by klist is different from the domain name you requested, you are requesting using an alias, and you need to update your krb5.conf so you are using the fully qualified domain name, not its alias.

.. _windows_inventory:

Inventory
`````````

Ansible's windows support relies on a few standard variables to indicate the username, password, and connection type (windows) of the remote hosts.  These variables are most easily set up in inventory.  This is used instead of SSH-keys or passwords as normally fed into Ansible::

    [windows]
    winserver1.example.com
    winserver2.example.com

.. include:: ../rst_common/ansible_ssh_changes_note.rst

Examples
++++++++

Below are some examples of how to set your inventory based on the auth method chosen. These should all be defined in the group_vars/windows.yml file.

Basic Auth
----------

Inventory setup for Basic auth::

   ansible_user: USER
   ansible_password: SecretPasswordGoesHere
   ansible_port: 5986
   ansible_connection: winrm

Certificate Auth
----------------

Inventory setup for Certificate auth::

   ansible_port: 5986
   ansible_connection: winrm
   ansible_transport: certificate
   ansible_winrm_cert_pem: path to the client authentication certificate file path in PEM format
   ansible_winrm_cert_key_pem: path to the client authentication certificate key file path in PEM format


Kerberos Auth
-------------

Inventory setup for Kerberos auth, note: specifying ansible_password does not make any difference here, you need to have obtained a valid Kerberos ticket outside of Ansible for this to work::

   ansible_user: USER@DOMAIN.COM
   ansible_port: 5986
   ansible_connection: winrm


NTLM Auth
---------

Inventory setup for NTLM auth::

   ansible_user: DOMAIN\USER
   ansible_password: SecretPasswordGoesHere
   ansible_port: 5986
   ansible_connection: winrm
   ansible_transport: ntlm

Other Options
-------------

There are other inventory options you can set for additional configuration of the WinRM connections::

* ``ansible_winrm_scheme``: Specify the connection scheme (``http`` or ``https``) to use for the WinRM connection.  Ansible uses ``https`` by default unless the port is 5985.
* ``ansible_winrm_path``: Specify an alternate path to the WinRM endpoint.  Ansible uses ``/wsman`` by default.
* ``ansible_winrm_realm``: Specify the realm to use for Kerberos authentication.  If the username contains ``@``, Ansible will use the part of the username after ``@`` by default.
* ``ansible_winrm_transport``: Specify one or more transports as a comma-separated list.  When older versions of pywinrm <0.2.0, Ansible will use ``kerberos,plaintext`` if the ``kerberos`` module is installed and a realm is defined, otherwise ``plaintext``.
* ``ansible_winrm_server_cert_validation``: Specify the server certificate validation mode (``ignore`` or ``validate``). Ansible defaults to ``validate`` on Python 2.7.9 and higher, which will result in certificate validation errors against the Windows self-signed certificates. Unless verifiable certificates have been configured on the WinRM listeners, this should be set to ``ignore``
* ``ansible_winrm_*``: Any additional keyword arguments supported by ``winrm.Protocol`` may be provided.

Attention for the older style variables (``ansible_ssh_*``): ansible_ssh_password doesn't exist, should be ansible_ssh_pass.

Although Ansible is mostly an SSH-oriented system, Windows management will not happen over SSH (`yet <http://blogs.msdn.com/b/powershell/archive/2015/06/03/looking-forward-microsoft-support-for-secure-shell-ssh.aspx>`).

If you have installed the ``kerberos`` module and ``ansible_user`` contains ``@`` (e.g. ``username@realm``), Ansible will first attempt Kerberos authentication. *This method uses the principal you are authenticated to Kerberos with on the control machine and not ``ansible_user``*. If that fails, either because you are not signed into Kerberos on the control machine or because the corresponding domain account on the remote host is not available, then Ansible will fall back to "plain" username/password authentication.

When using your playbook, don't forget to specify --ask-vault-pass to provide the password to unlock the file.

Test your configuration like so, by trying to contact your Windows nodes.  Note this is not an ICMP ping, but tests the Ansible
communication channel that leverages Windows remoting::

    ansible windows [-i inventory] -m win_ping --ask-vault-pass

If you haven't done anything to prep your systems yet, this won't work yet.  This is covered in a later
section about how to enable PowerShell remoting - and if necessary - how to upgrade PowerShell to
a version that is 3 or higher.

You'll run this command again later though, to make sure everything is working.

.. _windows_system_prep:

Windows System Prep
```````````````````

In order for Ansible to manage your windows machines, you will have to enable and configure PowerShell remoting.

To automate the setup of WinRM, you can run `this PowerShell script <https://github.com/ansible/ansible/blob/devel/examples/scripts/ConfigureRemotingForAnsible.ps1>`_ on the remote machine.

The example script accepts a few arguments which Admins may choose to use to modify the default setup slightly, which might be appropriate in some cases.

Pass the -CertValidityDays option to customize the expiration date of the generated certificate.
  powershell.exe -File ConfigureRemotingForAnsible.ps1 -CertValidityDays 100

Pass the -SkipNetworkProfileCheck switch to configure winrm to listen on PUBLIC zone interfaces.  (Without this option, the script will fail if any network interface on device is in PUBLIC zone)
  powershell.exe -File ConfigureRemotingForAnsible.ps1 -SkipNetworkProfileCheck

Pass the -ForceNewSSLCert switch to force a new SSL certificate to be attached to an already existing winrm listener. (Avoids SSL winrm errors on syspreped Windows images after the CN changes)
  powershell.exe -File ConfigureRemotingForAnsible.ps1 -ForceNewSSLCert

.. note::
   On Windows 7 and Server 2008 R2 machines, due to a bug in Windows
   Management Framework 3.0, it may be necessary to install this
   hotfix http://support.microsoft.com/kb/2842230 to avoid receiving
   out of memory and stack overflow exceptions.  Newly-installed Server 2008
   R2 systems which are not fully up to date with windows updates are known
   to have this issue.

   Windows 8.1 and Server 2012 R2 are not affected by this issue as they
   come with Windows Management Framework 4.0.

.. _getting_to_powershell_three_or_higher:

Getting to PowerShell 3.0 or higher
```````````````````````````````````

PowerShell 3.0 or higher is needed for most provided Ansible modules for Windows, and is also required to run the above setup script. Note that PowerShell 3.0 is only supported on Windows 7 SP1, Windows Server 2008 SP1, and later releases of Windows.

Looking at an Ansible checkout, copy the `examples/scripts/upgrade_to_ps3.ps1 <https://github.com/cchurch/ansible/blob/devel/examples/scripts/upgrade_to_ps3.ps1>`_ script onto the remote host and run a PowerShell console as an administrator.  You will now be running PowerShell 3 and can try connectivity again using the win_ping technique referenced above.

.. _what_windows_modules_are_available:

Verifying Windows Configuration
```````````````````````````````

After you have set up the Windows host you can use the following commands to verify the setup to ensure Ansible can communicate with the host.

Verify WinRM Listeners
++++++++++++++++++++++

To see what listeners are currently active you can run the following ``winrm`` command in PowerShell::

   #!powershell
   PS C:\> winrm enumerate winrm/config/listener

   Listener
       Address = *
       Transport = HTTP
       Port = 5985
       Hostname
       Enabled = true
       URLPrefix = wsman
       CertificateThumbprint
       ListeningOn = 127.0.0.1, ::1

   Listener
       Address = *
       Transport = HTTPS
       Port = 5986
       Hostname = WINDOWS-SERVER
       Enabled = true
       URLPrefix = wsman
       CertificateThumbprint = 1234567890ABCDEF111213141516171819101A1B
       ListeningOn = 127.0.0.1, ::1

In the above example we can see both a HTTP and HTTPS listener has been created and are listening on ports 5985 and 5986 respectively.

Verify Service Settings
+++++++++++++++++++++++

Once you have verified that WinRM is setup and listening on a port you can use ``winrm get winrm/config/service`` to get the configuration of the WinRM service::

   #!powershell
   PS C:\> winrm get winrm/config/service

   Service
       RootSDDL = O:NSG:BAD:P(A;;GA;;;BA)(A;;GR;;;IU)S:P(AU;FA;GA;;;WD)(AU;SA;GXGW;;;WD)
       MaxConcurrentOperations = 4294967295
       MaxConcurrentOperationsPerUser = 1500
       EnumerationTimeoutms = 240000
       MaxConnections = 300
       MaxPacketRetrievalTimeSeconds = 120
       AllowUnencrypted = false
       Auth
           Basic = true
           Kerberos = true
           Negotiate = true
           Certificate = false
           CredSSP = false
           CbtHardeningLevel = Relaxed
       DefaultPorts
           HTTP = 5985
           HTTPS = 5986
       IPv4Filter = *
       IPv6Filter = *
       EnableCompatibilityHttpListener = false
       EnableCompatibilityHttpsListener = false
       CertificateThumbprint
       AllowRemoteAccess = true

In the above example we are able to authenticate with the Windows host using:

- Basic (local accounts only)
- Kerberos (domain accounts only)
- Negotiate [Kerberos/NTLM] (local and domain accounts)

Because AllowUnencrypted is set to false we also have to use a HTTPS listener as pywinrm does not currently support encrypted WinRM messages over HTTP.

The following section defines the purpose of each relevant value::

* ``AllowUnencrypted``: When set to ``true`` allows WinRM messages to be sent without encryption.
* ``Auth/Basic``: Allows basic authentication, only for local accounts
* ``Auth/Kerberos``: Allows Kerberos authentication, only for domain accounts
* ``Auth/Negotiate``: Leverages Windows SSPI for auth, used by NTLM and Kerberos
* ``Auth/Certificate``: Allows certificate authentication, only for local accounts
* ``Auth/CredSSP``: Allows CredSSP authentication for credential delegation (double-hop). Not currently supported by pywinrm
* ``Auth/CbtHardeningLevel``: Channel Binding Token is either mandatory (``Strict``) or optional (``Relaxed``, ``None``). ``Strict`` not currently supported by pywinrm

.. note::
   It is highly recommended to not set AllowUnencrypted to true, please
   use HTTPS endpoints wherever possible.

   Double-hop authentication is currently supported by pywinrm with
   the Kerberos auth method. Please set ``ansible_winrm_kerberos_delegation=true``
   in host vars for this.

What modules are available
``````````````````````````

Most of the Ansible modules in core Ansible are written for a combination of Linux/Unix machines and arbitrary web services, though there are various
Windows modules as listed in the `"windows" subcategory of the Ansible module index <http://docs.ansible.com/list_of_windows_modules.html>`_.

Browse this index to see what is available.

In many cases, it may not be necessary to even write or use an Ansible module.

In particular, the "script" module can be used to run arbitrary PowerShell scripts, allowing Windows administrators familiar with PowerShell a very native way to do things, as in the following playbook::

    - hosts: windows
      tasks:
        - script: foo.ps1 --argument --other-argument

Note:: There are a few other Ansible modules that don't start with "win" that also function with Windows, including "fetch", "slurp", "raw", and "setup" (which is how fact gathering works).

.. _developers_developers_developers:

Developers: Supported modules and how it works
``````````````````````````````````````````````

Developing Ansible modules are covered in a `later section of the documentation <http://docs.ansible.com/developing_modules.html>`_, with a focus on Linux/Unix.
What if you want to write Windows modules for Ansible though?

For Windows, Ansible modules are implemented in PowerShell.  Skim those Linux/Unix module development chapters before proceeding. Windows modules in the core and extras repo live in a "windows/" subdir. Custom modules can go directly into the Ansible "library/" directories or those added in ansible.cfg. Documentation lives in a `.py` file with the same name. For example, if a module is named "win_ping", there will be embedded documentation in the "win_ping.py" file, and the actual PowerShell code will live in a "win_ping.ps1" file. Take a look at the sources and this will make more sense.

Modules (ps1 files) should start as follows::

    #!powershell
    # <license>

    # WANT_JSON
    # POWERSHELL_COMMON

    # code goes here, reading in stdin as JSON and outputting JSON

The above magic is necessary to tell Ansible to mix in some common code and also know how to push modules out.  The common code contains some nice wrappers around working with hash data structures and emitting JSON results, and possibly a few more useful things.  Regular Ansible has this same concept for reusing Python code - this is just the windows equivalent.

What modules you see in windows/ are just a start.  Additional modules may be submitted as pull requests to github.

.. _windows_and_linux_control_machine:

Reminder: You Must Have a Linux Control Machine
```````````````````````````````````````````````

Note running Ansible from a Windows control machine is NOT a goal of the project.  Refrain from asking for this feature,
as it limits what technologies, features, and code we can use in the main project in the future.  A Linux control machine
will be required to manage Windows hosts.

Cygwin is not supported, so please do not ask questions about Ansible running from Cygwin.

.. _windows_facts:

Windows Facts
`````````````

Just as with Linux/Unix, facts can be gathered for windows hosts, which will return things such as the operating system version.  To see what variables are available about a windows host, run the following::

    ansible winhost.example.com -m setup

Note that this command invocation is exactly the same as the Linux/Unix equivalent.

.. _windows_playbook_example:

Windows Playbook Examples
`````````````````````````

Look to the list of windows modules for most of what is possible, though also some modules like "raw" and "script" also work on Windows, as do "fetch" and "slurp".

Here is an example of pushing and running a PowerShell script::

    - name: test script module
      hosts: windows
      tasks:
        - name: run test script
          script: files/test_script.ps1

Running individual commands uses the 'raw' module, as opposed to the shell or command module as is common on Linux/Unix operating systems::

    - name: test raw module
      hosts: windows
      tasks:
        - name: run ipconfig
          raw: ipconfig
          register: ipconfig
        - debug: var=ipconfig

Running common DOS commands like 'del", 'move', or 'copy" is unlikely to work on a remote Windows Server using Powershell, but they can work by prefacing the commands with "CMD /C" and enclosing the command in double quotes as in this example::

    - name: another raw module example
      hosts: windows
      tasks:
         - name: Move file on remote Windows Server from one location to another
           raw: CMD /C "MOVE /Y C:\teststuff\myfile.conf C:\builds\smtp.conf"

You may wind up with a more readable playbook by using the PowerShell equivalents of DOS commands.  For example, to achieve the same effect as the example above, you could use::

    - name: another raw module example demonstrating powershell one liner
      hosts: windows
      tasks:
         - name: Move file on remote Windows Server from one location to another
           raw: Move-Item C:\teststuff\myfile.conf C:\builds\smtp.conf

Bear in mind that using C(raw) will allways report "changed", and it is your responsiblity to ensure PowerShell will need to handle idempotency as appropriate (the move examples above are inherently not idempotent), so where possible use (or write) a module.

Here's an example of how to use the win_stat module to test for file existence.  Note that the data returned by the win_stat module is slightly different than what is provided by the Linux equivalent::

    - name: test stat module
      hosts: windows
      tasks:
        - name: test stat module on file
          win_stat: path="C:/Windows/win.ini"
          register: stat_file

        - debug: var=stat_file

        - name: check stat_file result
          assert:
              that:
                 - "stat_file.stat.exists"
                 - "not stat_file.stat.isdir"
                 - "stat_file.stat.size > 0"
                 - "stat_file.stat.md5"

Again, recall that the Windows modules are all listed in the Windows category of modules, with the exception that the "raw", "script", "slurp" and "fetch" modules are also available.  These modules do not start with a "win" prefix.

.. _windows_contributions:

Windows Contributions
`````````````````````

Windows support in Ansible is still relatively new, and contributions are quite welcome, whether this is in the
form of new modules, tweaks to existing modules, documentation, or something else.  Please stop by the ansible-devel mailing list if you would like to get involved and say hi.

.. seealso::

   :doc:`developing_modules`
       How to write modules
   :doc:`playbooks`
       Learning Ansible's configuration management language
   `List of Windows Modules <http://docs.ansible.com/list_of_windows_modules.html>`_
       Windows specific module list, all implemented in PowerShell
   `Mailing List <http://groups.google.com/group/ansible-project>`_
       Questions? Help? Ideas?  Stop by the list on Google Groups
   `irc.freenode.net <http://irc.freenode.net>`_
       #ansible IRC chat channel