Ansibleを使ってWindows Serverを操作してみたので、その時のメモを引っ張り出して作成いたしました。
内容は、AnsibleでWindows Serverを操作するための準備作業です。(win_ping
を使った動作確認をします)
「Ansibleでサーバを管理してみたい」とお考えの場合、WindowsはLinuxほど簡単に行かない部分があることをご認識いただけたらと思います。
公式ドキュメントを参考としております。最新の情報などは、こちらから確認できると思います。
また、初期設定等が行える公式スクリプト(ConfigureRemotingForAnsible.ps1)が用意されていますが、こちらの記事では使用しておりません。
(ちなみに、Linuxの場合はsshが通ればほぼ使えるはず)
Linuxの前提条件
- ssh接続が可能
- Python 2 (version 2.6以上) or Python 3 (version 3.5以上)
検証環境
- Control node:Amazon Linux
- ansible: 2.9.6
- Managed node:Windows Server 2012
AnsibleでWindows Serverを管理するための前提条件
以下の条件を満たす必要があります。
- Windows Server
- 2008, 2008R2, 2012, 2012R2, 2016, 2019
- PowerShell
- 3.0以上
- .NET
- 4.0以上
# Windows Serverバージョン
PS> wmic os get caption
# PowerShellバージョン
PS> $PSVersionTable
# .NETバージョン
PS> reg query "HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\NET Framework Setup\NDP\v4\Full"
Windows Server 2008/2008R2の場合、標準のPowershell、.Netのバージョンは条件を満たしてないため、別途バージョンアップが必要になります。
Windows Server 2012以降の場合、標準のPowerShell、.NETのバージョンは条件を満たしています。
調べると、Windows 2008/2008R2は2020/01
でサポート終了しているみたいですね。
2008でAnsibleを動かしたいということはほぼないと思いますが、そういった場合はまずはサポート対象のOSに切り替えたほうがgoodだと思いました。
Windows Server設定
Windows Serverの設定を行っていきます。
AnsibleでWindowsを操作するためには、WinRMを設定する必要があります。
WinRMとは、Windows Remote Management(Windows リモート管理)
PS> Get-Service | Where-Object { $_.Name -eq "WinRM" } | ft -AutoSize
Status Name DisplayName
------ ---- -----------
Running WinRM Windows Remote Management (WS-Management)
Windows Serverはデフォルトで起動(Running)していたため、サービス起動設定は不要でした。
続いて、WinRMのListnerの設定を行います。
接続方法としてHTTP(5985)
と、HTTPS(5986)
を使用した場合がありますので、必要に応じて確認ください。
HTTP接続編(5985)
WinRM設定
Windows Server 2012は、デフォルトでHTTPのListenerが設定されていました。
5985ポートでHTTPのListen設定が確認できます。
PS> winrm enumerate winrm/config/Listener
Listener
Address = *
Transport = HTTP
Port = 5985
Hostname
Enabled = true
URLPrefix = wsman
CertificateThumbprint
ListeningOn = 10.8.0.10, 127.0.0.1, ::1, fe80::5efe:10.8.0.10%14, fe80::917:f75:5272:4a68%12
次に、認証方法を確認します。
PS> 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 = false
Kerberos = true
Negotiate = true
Certificate = false
CredSSP = false
CbtHardeningLevel = Relaxed
DefaultPorts
HTTP = 5985
HTTPS = 5986
IPv4Filter = *
IPv6Filter = *
EnableCompatibilityHttpListener = false
EnableCompatibilityHttpsListener = false
CertificateThumbprint
AllowRemoteAccess = true
HTTPの場合は、Basic認証の許可、平文の許可をする必要があります。
Basic認証の許可、平文の許可
# Basic認証の許可
PS> winrm set winrm/config/service/auth '@{Basic="true"}'
Basic = true
# 平文の許可
PS> winrm set winrm/config/service '@{AllowUnencrypted="true"}'
AllowUnencrypted = true
Ansible実行
それではAnsibleからWindows Serverへの動作確認をします。
インベントリの内容は下記です。
# file: hosts
[windows_server]
10.8.0.10
[windows_server:vars]
ansible_user=Administrator
ansible_password=password
ansible_ssh_port=5985
ansible_connection=winrm
ansible_winrm_server_cert_validation=ignore
$ ansible windows_server -i hosts -m win_ping
10.8.0.10 | UNREACHABLE! => {
"changed": false,
"msg": "plaintext: HTTPConnectionPool(host='10.8.0.10', port=5985): Max retries exceeded with url: /wsman (Caused by ConnectTimeoutError(<urllib3.connection.HTTPConnection object at 0x7feafc148bd0>, 'Connection to 10.8.0.10 timed out. (connect timeout=30)'))",
"unreachable": true
}
うまくいきません...。-v
オプションで詳細な出力をしてみたいと思います。
$ ansible windows_server -i hosts -m win_ping -vvv
(略)
Pipelining is enabled.
<10.8.0.10> ESTABLISH WINRM CONNECTION FOR USER: Administrator on PORT 5985 TO 10.8.0.10
10.8.0.10 | UNREACHABLE! => {
"changed": false,
"msg": "plaintext: HTTPConnectionPool(host='10.8.0.10', port=5985): Max retries exceeded with url: /wsman (Caused by ConnectTimeoutError(<urllib3.connection.HTTPConnection object at 0x7f88e4a48cd0>, 'Connection to 10.8.0.10 timed out. (connect timeout=30)'))",
"unreachable": true
}
<10.8.0.10> ESTABLISH WINRM CONNECTION FOR USER: Administrator on PORT 5985 TO 10.8.0.10
こちらでログが止まります。コネクションが張れないようですね。
接続のタイムアウトだと予想し、FireWall設定を見直しました。
今回の環境(AWS上のWindows Server 2012)では、デフォルト設定されていた以下のFireWallを変更しました。
- DisplayName : Windows Remote Management (HTTP-In) (注)Profileが
Public
のもの -
RemoteIP
をLocalSubnet
→Any
へ変更
PS> netsh advfirewall firewall show rule name="Windows Remote Management (HTTP-In)"
Rule Name: Windows Remote Management (HTTP-In)
----------------------------------------------------------------------
Enabled: Yes
Direction: In
Profiles: Public
Grouping: Windows Remote Management
LocalIP: Any
RemoteIP: LocalSubnet
Protocol: TCP
LocalPort: 5985
RemotePort: Any
Edge traversal: No
Action: Allow
それでは再度実行に移ります。
$ ansible windows_server -i hosts -m win_ping
10.8.0.10 | SUCCESS => {
"changed": alse,
"ping": "pong"
}
成功しました。
HTTPS接続編(5986)
Windows Serverで自己証明書を作成したいと思います。
参考
公的に署名された証明書なしで WinRM サービスまたは HTTPS を構成する
New-SelfSignedCertificate (Windows Server 2016)
New-SelfSignedCertificate (Windows Server 2012)
###自己証明書作成
HTTPS用の自己証明書を作成します。
PS> $cert = New-SelfSignedCertificate -CertstoreLocation Cert:\LocalMachine\My -DnsName "HOSTNAME"
上記コマンドで作成することができますが、証明書の有効期限が1年になります。
有効期限を延長して作りたい場合はオプション(-NotAfter
)を付与ください。
※ただし New-SelfSignedCertificate
の -NotAfter
オプションが使用できるのは、Windows Server 2016からでした。Windows Server 2012でやりたい場合は、Certreq
を使用しましょう。(2016のドキュメントを見ていたため、結構ハマってました..)
PS> C:\Windows\System32\certreq.exe -new cert.txt
cert.txtファイルに記載するパラメータで指定できるみたいです。
ValidityPeriodUnits
ValidityPeriod
; cert.txt
[NewRequest]
; At least one value must be set in this section
Subject = "CN=HOSTNAME"
KeyLength = 2048
Exportable = TRUE
KeyAlgorithm = RSA
MachineKeySet = true
RequestType = Cert
ValidityPeriodUnits = 1
ValidityPeriod = days
[EnhancedKeyUsageExtension]
OID=1.3.6.1.5.5.7.3.1
OID=1.3.6.1.5.5.7.3.2
作成した自己証明書を確認します。
PS> Get-Childitem -Path Cert:\LocalMachine\My -Recurse
Directory: Microsoft.PowerShell.Security\Certificate::LocalMachine\My
Thumbprint Subject
---------- -------
2B7B061E276307484DC5D1D133697DF98C62B5B7 CN=HOSTNAME
ちなみに、下記コマンドのように、fl
を付与すると有効期限などの値が確認できます。
PS> Get-Childitem -Path Cert:\LocalMachine\My -Recurse | fl
Subject : CN=HOSTNAME
Issuer : CN=HOSTNAME
Thumbprint : ****************************************
FriendlyName :
NotBefore : 5/03/2020 4:14:16 PM
NotAfter : 5/03/2020 4:24:16 PM
Extensions : {System.Security.Cryptography.Oid, System.Security.Cryptography.Oid}
WinRM設定
HTTPS (5986) の設定を行います。
PS> New-Item -Path WSMan:\LocalHost\Listener -Transport HTTPS -Address * -CertificateThumbPrint $cert.Thumbprint -Force
WSManConfig: Microsoft.WSMan.Management\WSMan::localhost\Listener
Type Keys Name
---- ---- ----
Container {Transport=HTTPS, Address=*} Listener_1305953032
certreqで自己証明書を作成した場合は、コマンドの$cert.Thumbprint
部分を"{自己証明書確認で確認したThumbprint}"
に変更して下さい。
PS> winrm enumerate winrm/config/Listener
Listener
Address = *
Transport = HTTPS
Port = 5986
Hostname
Enabled = true
URLPrefix = wsman
CertificateThumbprint = 3A7B061E276307484DC5D1D133697DF98C62B5B7
ListeningOn = 10.8.0.10, 127.0.0.1, ::1, fe80::5efe:10.8.0.10%14, fe80::68a5:c889:ade8:b530%12
設定したHTTPSが確認できました。
Basic認証の許可
HTTPSの場合も Basic認証をtrue
とする必要がありました。
平文の許可はfalse
でも問題ありません。
# Basic認証の許可
PS> winrm set winrm/config/service/auth '@{Basic="true"}'
Basic = true
FireWall設定
必要に応じてFireWallの設定をします。
以下コマンドでFireWallルールを追加することが可能です。今回は複雑な設定はしておりません。
PS> New-NetFirewallRule -DisplayName "Windows Remote Management (HTTPS-In)" -Name "Windows Remote Management (HTTPS-In)" -Profile Any -LocalPort 5986 -Protocol TCP
Name : Windows Remote Management (HTTPS-In)
DisplayName : Windows Remote Management (HTTPS-In)
Description :
DisplayGroup :
Group :
Enabled : True
Profile : Any
Platform : {}
Direction : Inbound
Action : Allow
EdgeTraversalPolicy : Block
LooseSourceMapping : False
LocalOnlyMapping : False
Owner :
PrimaryStatus : OK
Status : The rule was parsed successfully from the store. (65536)
EnforcementStatus : NotApplicable
PolicyStoreSource : PersistentStore
PolicyStoreSourceType : Local
Ansible実行
それではAnsibleからWindows Serverへの動作確認をしましょう。
インベントリの内容を変更しておきます。
# file: hosts
(略)
[windows_server:vars]
ansible_ssh_port=5986
$ ansible windows_server -i hosts -m win_ping
10.8.0.10 | SUCCESS => {
"changed": false,
"ping": "pong"
}
できました。
これでHTTP/HTTPSどちらでもwin_ping
の動作確認ができました!
以上、最後まで読んでいただきありがとうございました!!