אבטח את WinRM עבור Ansible באמצעות תעודות ב- 10 שלבים

ענסיבל מתפתחת להיות אחת מכלי ניהול התצורה הנפוצים ביותר, אם לא הכלי הנפוץ ביותר כיום. ענסיבל היא כלי שימושי (וחינם ברוב המקרים) המאפשר למהנדסי DevOps ולמהנדסי/מנהלי מערכות לבנות ולתחזק את התשתיות שלהם בצורה אידמפוטנטית, בצורה של תשתיות-כקוד. אך, להגדיר את התקשורת שלו עם Windows דרך WinRM עשוי להיות אתגר.

כמו רוב רכיבי התשתיות האחרים, ענסיבל יכולה להפעיל ולתחזק את מצבי התצורה במארחי Windows. ענסיבל מתחברת למארחי Windows אלו דרך WinRM, אף על פי שהם ניסויים עם SSH.

כאשר אתה מגדיר את WinRM עבור ענסיבל, יש לך מספר אפשרויות שונות הנעות בין קלות להתקנה לבין השפעות בטחוניות. הרבה אנשים בוחרים בגישה הקלה; אימות בסיסי באמצעות HTTP. אף שאתה מוותר על העבודה הנוספת הקשורה לתעוזה באמצעות תעוזות, זה לעולם לא רעיון טוב לשלוח נתונים לא מוצפנים מעל רשת אלא אם כן יש לך לכך צורך.

במאמר זה, תלמד כיצד להגדיר את WinRM עבור Ansible באמצעות אימות מבוסס אישור באמצעות תעודות שנחתמות באופן עצמאי כך ש-Ansible תוכל לדבר איתם.

ההגדרה שתלמדו במדריך זה אינה רק חלה על Ansible כלקוח. אימות מבוסס תעודה זה יכול להתייחס באותה מידה ללקוחות WinRM אחרים כמו מארחי Windows אחרים.

הנחות

המאמר הזה יהיה מדריך עקרוני. אם תתכוונו לעקוב אחר השלבים המוצגים כאן כדי להגדיר את WinRM עבור Ansible, המדריך יניח:

  • כבר יש לכם Ansible מותקן על מארח Linux.
  • הגדרתם אינוונטורי של Ansible על סמך מארחי Windows שלכם.
  • יש לכם שרת Windows 2016 או מאוחר יותר לניהול. חלק מה-cmdlets המשמשים במדריך זה לא יעבדו עם גרסאות ישנות יותר של Windows.
  • המארח של Windows אינו בדומיין. אף על פי שהדוגמאות בוצעו על מארח שאינו מצוי בדומיין, ההגדרה הזו אמורה לעבוד גם עם מארחים שנמצאים בדומיין.
  • יש לכם גישה RDP או גישת מסוף למארח Windows ואתם מחוברים כמנהל מקומי.
  • אתם מכירים עם PowerShell. רוב הדוגמאות ישתמשו בקוד PowerShell כדי לבצע שינויים במארח Windows.

כל קטע ישתמש בקטע קוד שתלוי בקוד הקודם. חלק מהקטעים יתייחסו למשתנים שהוגדרו מראש. ודא שהקונסול שלך פתוח כשאתה מעתיק את הקוד אם אתה מתכנן לעקוב אחריו בדיוק.

אם אתה רוצה רק את הקוד בלי כל ההסבר, נסה להוריד את קובץ ה-GitHub gist הזה.

הפעלת רימוטינג בפוורשל עבור WinRm עבור Ansible

אם כל השרתים Windows Server 2016 או מאוחר יותר מכילים את פקודת ה-PowerShell Remoting מופעלת, תמיד כדאי לוודא זאת.

על המארח בווינדוס שברצונך לנהל, פתח קונסולת פוורשל כמנהל מערכת והרץ את קטע הקוד הבא. קטע הקוד הזה מבטיח ששירות ה-WinRm הופעל ומוגדר להתחיל באופן אוטומטי בעת פתיחת המערכת.

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

בשלב הבא, הוודא ש-PowerShell Remoting מופעל על ידי בדיקה ראשית אם יש לו תצורות פעילות של הפעלת המשתמש. אם לא, אז הוודא שאין לו שום מאזין זמין. WinRm עבור Ansible חייבת להכיל לפחות מאזין אחד. אם אחד מתנאים אלה חוזר עם כלום, הרץ את Enable-PSRemoting.

if (-not (Get-PSSessionConfiguration) -or (-not (Get-ChildItem WSMan:\localhost\Listener))) {
    ## השתמש ב-SkipNetworkProfileCheck כדי להפוך את הפעולה זמינה גם בפרופילים ציבוריים של מערכת האש
    ## השתמש ב-Force כדי שלא יתבקש מאיתנו להפעיל את זה או לא.
    Enable-PSRemoting -SkipNetworkProfileCheck -Force
}
Configuring WinRM for Ansible (a listener) via the winrm command

הפעלת אימות מבוסס אישורים

לפי ברירת מחדל, WinRM אינו מוגדר לאימות באמצעות אישורים מבוססי תעודות. עליך להפעיל זאת על ידי הגדרת WSMan כפי שמוצג למטה.

#region אפשר אימות באמצעות תעודות
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, ייבא אותה לאחסניות תעודות מפעילי האימות של השורש האמינים ו־אנשים שאתה מסתמך עליהם באמצעות Import-Certificate כמו שמוצג למטה.

$pubKeyFilePath = 'C:\cert.pem'

## יבוא את המפתח הציבורי לתעודות מפעילי האימות של השורש האמינים ולאנשים שאתה מסתמך עליהם
$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 לחיבורים נכנסים. לאחר היצירה, מאזין זה מקבל חיבורים נכנסים וינסה להצפין נתונים באמצעות התעודה שנוצרה לשרת למעלה.

פעילות Remoting של PowerShell משתמשת במאזין 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 חל על כל החשבונות המקומיים (לא חשבונות דומיין) וגורם לכניסה שלך ברשת להיות החלק המוגבל של האסימון שלך. זה ימנע ממנו להתחבר כמו שווינדוס לא רואה אותו כמנהל ו-WinRM דורשת כברירת מחדל שהמשתמש יהיה מנהל מקומי.

על ידי הגדרת ה-LocalAccountTokenFilterPolicy, אתה אומר לווינדוס לא ליצור אסימון מוגבל לכניסות רשת על ידי חשבון מקומי ולהשתמש באסימון המלא שלו.

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

פתח פורט 5986 בחומת האש של ווינדוס

WinRm מעל HTTPS משתמש בפורט 5986. אם חומת האש של ווינדוס מופעלת, עליך לפתוח את הפורט הזה. תוכל לעשות זאת על ידי הרצת קטע קוד 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 לקבוצת המנהלים.

## הוסף את המשתמש המקומי לקבוצת המנהלים. אם צעד זה אינו בוצע, Ansible יראה שגיאת "AccessDenied"
Get-LocalUser -Name $testUserAccountName | Add-LocalGroupMember -Group 'Administrators'

סיכום

אם עקבת אחר כל אחד מהשלבים הללו כפי שהוצגו, אתה כעת יכול לבצע פקודות Ansible נגד מארח Windows. השתמש במודול win_shell כדי לבצע את הבדיקה שלך. אם המודול הזה מצליח, הגדרת את WinRM בהצלחה עבור Ansible ואימות על ידי תעודת אישור!

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