Puppetを介してWMIアクセス許可を管理する



序文として



私の仕事の主な目的は、鉄とvmホストの艦隊をサポートすることです-すでに200未満(そして100未満でした、ああ、時間が実行されていました...)私はすべてのハードウェアとネットワークをサポートします。 また、すべてのモニタリング(Opsviewを使用-nagiosコアで作成)、ログの集約(Logstashを実装し、非常に高価なSplunk用の素晴らしいオープンソースソリューション)、構成管理(puppet)、バックアップ、データベースサポート、その他のシステムも利用できます(MongoDB、MySQL、Redis、ElasticSearchなど)。 一般的に-すべての最も興味深い)。 サポートと開発の間にはかなり細い線があり、開発者は自分が望むことをよく言うので、既に実装しています。 おもしろいことや、使用できるテクノロジーについてお話したいと思います。 どちらが定着し、何らかの理由でそうではなくなった。



問題を解決してからの空き時間に、インフラストラクチャをコードとしてインフラストラクチャ(IaaC)に移行しました。インフラストラクチャの不均一性のため、このためにパペットを選択しました。 私のネットワークでは、動物園はWindows Server 2008、Windows Server 2012、CentOS 5.5、CentOS 6.4のものです。 そうそう、2003年の数人の祖父-すぐに引退するために彼らを送る時が来ました...



OpsvewでPuppetを使用して自動的に監視を設定する方法についてはすでに書いていますが、今日は自分の環境の不均一性ともう一度「戦った」ことについてお話したいと思います。



挑戦する



Windows 2008/2012サーバーでWMI構成を自動化する必要がありました。重要な必要性は、WMIのリモート使用、およびパフォーマンスカウンター、パフォーマンスログへのアクセスを許可するローカルサーバーグループにサービスユーザーを追加することです。一般に、サーバーをリモートで監視するために必要なすべてのものに。 グループ自身が十分に迅速に決定しましたが、これを行うための便利で迅速な方法を見つけることが残っています。 また、ユーザードメイン\サービスユーザーにルートWMS名前空間へのアクセスを許可する必要がありました。 また、これはすべてIaaCの一般的な概念の一部である必要があります。これは、少なくとも現在の状態を確認し、グループ内のユーザーの有無のバージョンで必要に応じてユーザーが既に追加されている場合は実行をスキップすることを意味します。 つまり ソリューションは可能な限り自動化するか、完全に自動化する必要があります。 少しグーグルで調べた後、私のケースに必要なものが明らかになりましたが、次のことをしなければなりませんでした。



ドメインユーザーdomain \ service-userをローカルグループに追加します(少なくとも):

-証​​明書サービスDCOMアクセス

-パフォーマンスログユーザー

-パフォーマンスモニターユーザー

-分散COMユーザー。

ドメイン\ service-userの少なくとも「読み取り」アクセス権を次のWMI名前空間に設定します。

-CIMV2

-MicrosoftIISv2。

すべてがインストールされると、check_wmi_plus(標準Opsview Proパッケージに含まれています)は、IISおよびその他の興味深いパラメーター(必要なもの)に関する必要なデータを取得できるようになります。



難しさ



発生した主な困難-実行するための既成のソリューションはなく、「サーバーを監視に使用できるようにする」ことを確認してください。 一般的に、私はあまり動揺しません。なぜなら、自分のタスクに対する既製の解決策は非常にまれであり、それが起こった場合、彼らはしばしば何か間違ったことをしているからです。



Puppetには、リソース「ユーザー」が組み込まれています。理論的には、すべてのタスクの半分を完了する必要があり、「ドメインユーザー-ローカルグループ」接続では機能しませんでした。 判明したように、これは既知のバグであり、修正する予定です( UPD:リリース3.4で既に修正済み )が、常にパペットを次のリリースに委ねています。 パペットDSLで回避策を実行しようとする試みは、常に機能するとは限らない複雑なエスケープシーケンスを必要とする非常に複雑な構造のために失敗しました。



別の問題-Windowsには、レジストリを選択してホイールを再発明するだけの場合、パペットで「ラップ」できるwmiクラスへのアクセス権を管理する組み込みの普遍的な方法はありません。



実装



その結果、ドメインユーザーをサーバー上のローカルグループに追加するためのネイティブプロバイダーが修復されるまで、プロバイダーを作成して使用することにしました。 そして、私はそれをしました... PowerShellのコードをラップ!



win_user.rb


Puppet::Type.type(:win_user).provide(:win_user) do @doc = %q{Manage windows users and groups} desc "Manage windows users and groups" confine :operatingsystem => :windows defaultfor :operatingsystem => :windows commands :powershell => if File.exists?("#{ENV['SYSTEMROOT']}\\sysnative\\WindowsPowershell\\v1.0\\powershell.exe") "#{ENV['SYSTEMROOT']}\\sysnative\\WindowsPowershell\\v1.0\\powershell.exe" elsif File.exists?("#{ENV['SYSTEMROOT']}\\system32\\WindowsPowershell\\v1.0\\powershell.exe") "#{ENV['SYSTEMROOT']}\\system32\\WindowsPowershell\\v1.0\\powershell.exe" else 'powershell.exe' end def add_user_to_group # end def exists? #add transform to array if just a string groups = resource[:groups] if groups.kind_of?(String) groups.to_a end found = false groups.to_a.each do |group| Puppet.debug("Checking the existence of value: #{self} in #{group}") result = powershell 'if (([ADSI]"WinNT://$env:computername/'+group+'").IsMember(([ADSI]"WinNT://$env:userdomain/'+ resource[:name]+'").ADsPath) -eq $False){echo 0} else {echo 1}' if result.chomp == "0" #if not found (ps returned false on search of user in group) Puppet.debug("User '#{resource[:name]}' is not found in group '#{group}'") found = false # break else Puppet.debug("User '#{resource[:name]}' is found in a group '#{group}'") found = true end end found end def create groups = resource[:groups] if groups.kind_of?(String) groups.to_a end groups.to_a.each do |group| Puppet.debug("Adding user to a group #{self}") powershell 'if (([ADSI]"WinNT://$env:computername/'+group+'").IsMember(([ADSI]"WinNT://$env:userdomain/'+ resource[:name]+'").ADsPath) -eq $False){$([ADSI]"WinNT://$env:computername/'+group+'").Add(([ADSI]"WinNT://$env:userdomain/'+resource[:name]+'").ADsPath)} else {echo "User is already in a group"}' end end def destroy end end
      
      







WMIパラメータを構成するには、サードパーティのオープンソースのwmisecurity.exeユーティリティを使用する必要がありました。 それをインストールするには、chocoaltey.org- wmisecurityにパッケージを作成しました。 パッケージをインストールするために、私は常に使用しているチョコレートのパペットプロバイダーを使用しました。



また、パペットマニフェスト自体は、以前に作成されたモジュールを使用し、ユーザーのwmiクラスにアクセス権を追加するためのpowershellフックも含んでいます(多分、これを別のモジュールとして書き直します)。



wmi.pp
 class packages::wmi { $wmiuser = 'service-user' ###Doesn't work on windows right now #user { $wmiuser: # groups => ['Certificate Service DCOM Access','Performance Log Users','Performance Monitor Users', 'Distributed COM Users'], # } win_user { $wmiuser: groups => ['Certificate Service DCOM Access','Performance Log Users','Performance Monitor Users', 'Distributed COM Users'], ensure => present_local, } ###it is required to add user to those local groups in order monitoring to perform correctly. exec {"add-to-wmi-cimv2": command => "wmisecurity.exe /C=\$env:computername /A /N=Root/CIMV2 /M=\$env:userdomain\\$wmiuser:REMOTEACCESS /R", path => $::path, #if found user guid - skip onlyif => "if (WmiSecurity.exe /c=\$env:computername /N=Root/CIMV2 /R | Select-String $($(New-Object System.Security.Principal.NTAccount( \"\$env:userdomain\", '$wmiuser')).Translate([System.Security.Principal.SecurityIdentifier]).Value)){exit 1} else {exit 0}", provider => powershell, require => Package['wmisecurity'], } exec {"add-to-wmi-microsoftiisv2": command => "wmisecurity.exe /C=\$env:computername /A /N=Root/MicrosoftIISv2 /M=\$env:userdomain\\$wmiuser:REMOTEACCESS /R", path => $::path, #if found user guid - skip onlyif => "if (WmiSecurity.exe /c=\$env:computername /N=Root/MicrosoftIISv2 /R | Select-String $($(New-Object System.Security.Principal.NTAccount( \"\$env:userdomain\", '$wmiuser')).Translate([System.Security.Principal.SecurityIdentifier]).Value)){exit 1} else {exit 0}", provider => powershell, require => Package['wmisecurity'], } package {'wmisecurity': provider => 'chocolatey', install_options => '-pre', require => Class["packages::chocolatey"] } }
      
      







おわりに



もちろん、モジュール自体は理想からはほど遠いものであり、多くのことが欠けています。コードは明らかに汚いですが、意図したとおりに機能し、実行されます。 リファクタリングは次のイテレーションで計画されており、3.4がリリースされたときに起こると思います。 ここに私が想像する理想的なマニフェストがあります(「機能する汚いコード」について誓う人のために):



wmi.pp
 class packages::wmi { $wmiuser = "${env:userdomain}\\service-user" user { $wmiuser: groups => ['Certificate Service DCOM Access','Performance Log Users','Performance Monitor Users', 'Distributed COM Users'], ensure => present, } wmi_security_user { $wmiuser: namespaces => ['Root/CIMV2','Root/MicrosoftIISv2'], ensure => present, } }
      
      







今、新しいサーバーをセットアップするときに、パッケージを::このサーバーに(手動で、またはincludeを介して)割り当てることが残ります。これで、Puppetはその役割を果たします。 個人的に、私はこのクラスをopsviewクラスを通して使用することがほとんどです。このクラスはopsviewで監視するためのホストを自動的に作成し、必要なテンプレートを割り当てます。 これが、たとえばIISを備えたサーバーである場合、最終的なパペットクラスは、IISを備えたホストであるという必要な情報をすべてopsviewに伝え、そのようなホストも特定の方法で監視する必要があり、監視テンプレートをopsviewに割り当てます上記のクラスに依存するwmiを介して。 だから、私は何も見逃していないように。



結果のスクリーンショットのカップル:







All Articles