تأمين WinRM لـ Ansible بشهادات في 10 خطوات

أنسيبل تصبح واحدة من أكثر، إن لم تكن الأكثر، أدوات إدارة التكوين وجودًا اليوم. أنسيبل هي أداة مفيدة (ومجانية في معظم الحالات) تتيح لمهندسي DevOps ومهندسي النظام والمسؤولين بناء وصيانة البنية التحتية عبر جميع البيئات بطريقة تكرارية، بطريقة البنية كشفرة (infrastructure-as-code). ولكن، تكوينها للتحدث مع نظام Windows عبر WinRM بواسطة Ansible قد يكون تحدياً.

مثل العديد من مكونات البنية التحتية الأخرى، يمكن لأنسيبل نشر وصيانة حالات تكوين عبر مضيفي Windows. يتصل أنسيبل بهذه المضيفات عبر WinRM، على الرغم من أنهم يجربون SSH.

عند تكوين WinRm لـ Ansible، لديك خيارات مختلفة تتراوح من سهولة الإعداد إلى آثار الأمان. الكثيرون يختارون النهج السهل، المصادقة الأساسية باستخدام HTTP. على الرغم من أنك تتخلى عن العمل الإضافي المتعلق بالشهادات، إلا أنه من غير الجيد أبدًا إرسال البيانات غير المشفرة عبر الشبكة ما لم تكن مضطرًا للقيام بذلك.

في هذا المقال، ستتعلم كيفية إعداد WinRm لـ Ansible باستخدام الشهادة للمصادقة باستخدام شهادات ذاتية التوقيع بحيث يمكن لـ Ansible التحدث إليها.

الإعداد الذي ستتعلمه في هذا البرنامج التعليمي لا ينطبق فقط على Ansible كعميل. يمكن تطبيق هذه المصادقة على أساس الشهادة بنفس القدر على عملاء WinRm الآخرين مثل مضيفي Windows الآخرين.

الافتراضات

سيكون هذا المقال مستندًا إلى البرنامج التعليمي. إذا كنت تنوي اتباع الخطوات المقدمة هنا لتكوين WinRm لـ Ansible، سيفترض البرنامج التعليمي ما يلي:

  • لديك بالفعل Ansible مثبتة على مضيف Linux.
  • لقد قمت بإعداد مخزن Ansible على أساس مضيفي Windows الخاص بك.
  • لديك خادم Windows 2016 أو الإصدارات الأحدث للإدارة. قد لا تعمل بعض الأوامر النصية المستخدمة في هذا البرنامج التعليمي مع الإصدارات القديمة من Windows.
  • لا يتواجد مضيف Windows في مجال. على الرغم من أن الأمثلة تم تنفيذها على مضيف غير منضم إلى النطاق، يجب أن تعمل هذه الإعدادات على المضيفات المنضمة إلى النطاق أيضًا.
  • لديك وصول إلى RDP أو واجهة التحكم في المضيف Windows وتم تسجيل الدخول كمسؤول محلي.
  • أنت ملم بـ PowerShell. ستستخدم معظم الأمثلة رموز PowerShell لإجراء التغييرات على مضيف Windows.

سيتم استخدام قطعة رمزية في كل قسم تعتمد على السابقة. قد تشير بعض القطع الى المتغيرات المعرفة سابقًا. تأكد من ترك النافذة المخصصة مفتوحة عند نسخ ولصق هذا الكود إذا كنت تخطط لاتباعه بالضبط.

إذا كنت ترغب فقط في الحصول على الكود دون كل التفسيرات، فلا تتردد في تنزيل هذا الملف من GitHub.

تمكين التحكم عن بُعد لـ PowerShell لـ WinRm لـ Ansible

على الرغم من أن جميع خوادم Windows Server 2016 أو الأحدث لديها تمكين التحكم عن بُعد لـ PowerShell، إلا أنه من الجيد دائمًا التحقق من ذلك.

على الخادم الذي ترغب في إدارته، افتح نافذة PowerShell كمسؤول وقم بتشغيل قطعة الرمز التالية. تضمن هذه القطعة أن خدمة WinRM قد بدأت وتم تعيينها للتشغيل التلقائي عند تشغيل النظام.

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

بعد ذلك، تأكد من تمكين التحكم عن بُعد لـ PowerShell عن طريق التحقق أولاً مما إذا كان لديه أي تكوينات جلسة نشطة. إذا لم يكن الأمر كذلك، تأكد من عدم وجود أي استماعات متاحة. يجب أن يحتوي WinRM لـ Ansible على مستمع واحد على الأقل. إذا جاء أي من هذه الشروط بدون أي شيء، قم بتشغيل Enable-PSRemoting.

if (-not (Get-PSSessionConfiguration) -or (-not (Get-ChildItem WSMan:\localhost\Listener))) {
    ## استخدم SkipNetworkProfileCheck لتوفيره أيضًا في ملفات تعريف جدار حماية Windows العامة
    ## استخدم Force لعدم طرح سؤال حول ما إذا كنا متأكدين أم لا.
    Enable-PSRemoting -SkipNetworkProfileCheck -Force
}
Configuring WinRM for Ansible (a listener) via the winrm command

تمكين المصادقة القائمة على الشهادات

بشكل افتراضي، لا يتم تكوين WinRM للمصادقة على أساس الشهادات. يجب عليك تمكين ذلك عن طريق تكوين WSMan كما هو موضح أدناه.

#region Enable cert-based auth
Set-Item -Path WSMan:\localhost\Service\Auth\Certificate -Value $true
#endregion

إنشاء حساب مستخدم محلي

لاستخدام WinRM الذي يعتمد على الشهادات للمصادقة باستخدام Ansible، يجب عليك “ربط” حساب مستخدم محلي بشهادة. يمكنك استخدام حساب المسؤول المحلي للقيام بذلك، ولكن دائمًا ما يكون من الجيد إنشاء حساب محدد لتسهيل الإدارة.

تقوم الكود التالي بإنشاء حساب مستخدم محلي لـ WinRM لـ Ansible يسمى ansibletestuser بكلمة مرور p@$$w0rd12 إذا لم يكن موجودًا. ولضمان أنه يظل نشطًا دائمًا، لن ينتهي صلاحية كلمة مرور هذا الحساب أبدًا.

$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
}

إنشاء شهادة العميل

يجب أن يكون لـ WinRM لـ Ansible (بشكل آمن) شهادتين؛ شهادة عميل وشهادة خادم.

يمكنك استخدام نفس الشهادة لكل من العميل والخادم، ولكن واجهت مشكلات بهذا النهج. في وثائق Ansible والعديد من المصادر الأخرى، ستجد تعليمات لإنشاء شهادة العميل عبر أمر New-SelfSignedCert في PowerShell. على الرغم من أن هذا الأسلوب قد يعمل، إلا أنني لم أتمكن بسهولة من جعله يعمل.

لإنشاء شهادة العميل لـ WinRM لـ Ansible ، يجب عليك إنشاء مفتاح خاص ومفتاح عام. ابدأ بالاتصال بـ SSH إلى مضيف Ansible وتشغيل الأمر التالي openssl. ينشئ هذا الأمر مفتاحًا خاصًا في ملف يسمى cert_key.pem ومفتاحًا عامًا يسمى cert.pem. سيكون استخدام المفتاح للمصادقة العميل (1.3.6.1.4.1.311.20.2.3) “مرتبطًا” بحساب المستخدم المحلي الذي قمت بإنشائه سابقًا والذي يسمى ansibletestuser.

## هذا هو المفتاح العام الذي تم إنشاؤه من خادم Ansible باستخدام:
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 

خطوة واحدة أقرب إلى مصادقة WinRM لـ Ansible!

استيراد شهادة العميل

بمجرد إنشاء شهادة العميل لـ WinRm لـ Ansible ، سيتعين عليك استيرادها إلى متجرين للشهادات على مضيف Windows ليعمل WinRm على Ansible. للقيام بذلك ، قم أولاً بنقل المفتاح العام cert.pem إلى مضيف Windows. يفترض المثال أدناه وجود المفتاح في C:\cert.pem.

بمجرد الحصول على الشهادة العمومية على مضيف Windows ، قم بتوريدها إلى متجري Trusted Root Certification Authorities و Trusted People باستخدام Import-Certificate كما هو موضح أدناه.

$pubKeyFilePath = 'C:\cert.pem'

## قم بتوريد المفتاح العام إلى متجري Trusted Root Certification Authorities و Trusted People
$null = Import-Certificate -FilePath $pubKeyFilePath -CertStoreLocation 'Cert:\LocalMachine\Root'
$null = Import-Certificate -FilePath $pubKeyFilePath -CertStoreLocation 'Cert:\LocalMachine\TrustedPeople'

إنشاء شهادة الخادم

WinRM لـ Ansible تحتاج إلى شهادة معرفة باستخدام مفتاح لمصادقة الخادم. ستتم تخزين هذه الشهادة في متجر الشهادات LocalMachine\My على مضيف Windows. قم بإنشاء الشهادة الموقعة ذاتياً باستخدام مقطع الكود أدناه.

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

إنشاء مستمع WinRm باستخدام Ansible

بمجرد إنشاء كل من الشهادات، يجب عليك الآن إنشاء مستمع WinRm على الخادم الذي يعمل بنظام Windows. يبدأ هذا المستمع في الاستماع على منفذ 5986 للاستعلامات الواردة. بمجرد الإنشاء، يقبل هذا المستمع الاتصالات الواردة وسيحاول تشفير البيانات باستخدام الشهادة الخادم التي تم إنشاؤها أعلاه.

يستخدم PowerShell Remoting هذا المستمع WinRM كوسيلة نقل بمجرد أن يتم التحقق من المصادقة.

في قطعة الكود أدناه، يمكنك رؤية مثال رائع على التحقق من وجود مستمع HTTPS قائم بالفعل. إذا لم يتم العثور على مستمع باستخدام الشهادة الخادم التي تم إنشاؤها أعلاه، فسيتم إنشاء واحد جديد.

## البحث عن جميع مستمعي HTTPS
$httpsListeners = Get-ChildItem -Path WSMan:\localhost\Listener\ | where-object { $_.Keys -match 'Transport=HTTPS' }

## إذا لم يتم تعريف مستمعين على الإطلاق أو إذا لم يتم تكوين مستمع للعمل مع
## الشهادة الخادم التي تم إنشاؤها، فسيتم إنشاء واحد جديد بموضوع اسم الخادم الخاص بالكمبيوتر
## ومرتبط بالشهادة الخادم.
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
}

مطابقة شهادة العميل مع حساب المستخدم المحلي

الخطوة التالية هي التأكد من أنه عندما يقوم Ansible بالاتصال بالخادم الذي يعمل بنظام Windows باستخدام الشهادة الخادم، سيقوم بتنفيذ جميع التعليمات باعتباره مستخدم محلي. في هذه الحالة، ستستخدم جميع الأنشطة التي يقوم بها WinRm لـ Ansible حساب المستخدم المحلي، ansibletestuser.

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

## البحث عن بصمة الشهادة للشهادة العميل التي تم إنشاؤها على خادم 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

اسمح بـ WinRm لـ Ansible مع تحكم حساب المستخدم (UAC)

إذا كنت تستخدم حسابًا محليًا لربط شهادة به، يجب أن تقوم أيضًا بتعيين LocalAccountTokenFilterPolicy على 1 لضمان عدم تدخل UAC. ينطبق LocalAccountTokenFilterPolicy على جميع الحسابات المحلية (وليس الحسابات المجالية) ويتسبب في أن تصبح عملية تسجيل الدخول الشبكية جزءًا محدودًا من الرمز الخاص بك. سيتوقف ذلك عن تسجيل الدخول كمسؤول في Windows، حيث لا يراها WinRM افتراضيًا مسؤولًا محليًا.

من خلال تعيين LocalAccountTokenFilterPolicy، فأنت تخبر Windows بعدم إنشاء رمز محدود لعمليات تسجيل الدخول الشبكية بواسطة حساب محلي واستخدام الرمز الكامل.

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

فتح منفذ 5986 على جدار الحماية الخاص بنظام Windows

يستخدم WinRm عبر HTTPS منفذ 5986. إذا كان جدار الحماية الخاص بنظام Windows ممكّنًا، فيجب عليك فتح هذا المنفذ. يمكنك القيام بذلك عن طريق تشغيل مقتطف الشفرة PowerShell التالي. يعد مقتطف الشفرة هذا سهل المراس ويسمح لجميع الأجهزة باستخدامه. إذا كنت ترغب في تقييد هذا بشكل أكبر، تأكد من استخدام المعلمة LocalAddress وتحديد عنوان IP الخاص بـ Ansible.

#region التأكد من فتح WinRM 5986 على جدار الحماية
 $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

إضافة المستخدم المحلي إلى مجموعة المسؤولين

ربما تتساءل لماذا لم يتم في هذا البرنامج التعليمي إضافة المستخدم المحلي إلى مجموعة المسؤولين في وقت سابق. السبب هو أنه لسبب غير معروف عند محاولتك لتعيين شهادة العميل على المستخدم، لا يمكن أن يكون حساب المستخدم مسؤولًا محليًا.

قم بتشغيل مقطع الشيفرة التالي لإضافة حساب المستخدم المحلي ansibletestuser إلى مجموعة المسؤولين.

## أضف المستخدم المحلي إلى مجموعة المسؤولين. إذا لم يتم القيام بهذه الخطوة، ستظهر خطأ "AccessDenied" لـ Ansible
Get-LocalUser -Name $testUserAccountName | Add-LocalGroupMember -Group 'Administrators'

الاستنتاج

إذا كنت قد اتبعت كل هذه الخطوات كما هو موضح، يجب أن تكون قادرًا الآن على تنفيذ أوامر Ansible على جهاز Windows. استخدم وحدة win_shell لإجراء اختباراتك. إذا نجحت هذه الوحدة، فقد قمت بتكوين WinRM بنجاح لـ Ansible واعتماد الشهادات!

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