これは、PowerShell DSC Advent Calendar 2014 - Adventar 11日目の記事です。
時空のゆがみ。
さて、前回まででシンプルなコンフィグレーションをプッシュで反映させる方法を見てきました。
今回は、センシティブな情報。そう、パスワードをどうやってリモート先に安全に伝搬するかです。
目次
センシティブな情報とは
PowerShell DSC の中では、[PSCredential]です。つまり、パスワードなどの機密情報です。
PowerShellには[PSCredential]
という型があるので、これがセンシティブな情報となります。
$Password
のような平文、SecureString
のようなやり方はベストプラクティスからは大きくずれます。やってる人はすぐやめましょう。というレベルで本当に今すぐやめてください。当然DSCでもそれらは非推奨です。当然です。
どうやって暗号化するの
暗号化は、公開鍵暗号方式を用いて行われます。ざっくりとした詳細はこちらに。
さくっと流れを抑えましょう。
ノード
DSCサーバーから取得したMOFファイルの暗号化データを自分の秘密鍵でデコードします。
- 秘密鍵(*.pfx) を、Cert:\LocalMachine\My** にインポートします
- この秘密鍵から公開鍵(***.cer)をエキスポートします ー この鍵のThumbPrint をノードのLCMにてCertificateId に指定します。
DSCサーバー
ノードでエキスポートした公開鍵を使って対称させます。
- DSCサーバーの任意のパスに公開鍵ファイル(****.cer)を設置します
- DSCサーバーの Cert:\LocalMachine\My に公開鍵をインポートします
- インポートした公開鍵のThumbprintを取得します
あとは、DSCサーバーの公開鍵をコンフィグレーション実行時に指定するだけです。
- コンフィグレーションに
PSCredential
でセンシティブ情報を渡します - コンフィグレーションの実行時に、
コンフィグレーションデータ
で、公開鍵ファイルパスとThumbPrintを渡します
さて、見てみましょう。今回はわかりやすいようにノードもDSCサーバーも自分自身(localhost) とします。
暗号化をしない
暗号化しないやり方はBest Practiceではありません
先に、暗号化をしないでコンフィグレーションを扱ってみましょう。
さらっと書いてみます。
コンフィグレーションNoEncryption
の実行時にエラーで停止します。
ConvertTo-MOFInstance : 型 'User' のプロパティ 'Password' の処理中に System.InvalidOperationException エラーが発生しました: 暗号化されたパスワ ードを変換してプレーンテキストとして格納することが許可されるのは、PSDscAllowPlainTextPassword が true に設定されている場合だけです。 At line:8 char:5 + User 発生場所 行:164 文字:16 + $aliasId = ConvertTo-MOFInstance $keywordName $canonicalizedValue + ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + CategoryInfo : InvalidOperation: (:) [Write-Error]、InvalidOperationException + FullyQualifiedErrorId : FailToProcessProperty,ConvertTo-MOFInstance 構成 'NoEncryption' を処理中にエラーが発生しました。 発生場所 C:\Windows\system32\WindowsPowerShell\v1.0\Modules\PSDesiredStateConfiguration\PSDesiredStateConfiguration .psm1:2088 文字:5 + throw $errorRecord + ~~~~~~~~~~~~~~~~~~ + CategoryInfo : InvalidOperation: (NoEncryption:String) []、InvalidOperationException + FullyQualifiedErrorId : FailToProcessConfiguration
コンフィグレーションデータを渡す
ではどうやるか。コンフィグレーションデータ
を使って、PSDscAllowPlainTextPassword
にtrue
を渡して実行します。コンフィグレーションデータが何か忘れた人は 8日目をどうぞ。
コンフィグレーションデータ を指定して書きなおします。
MOFが出力されましたね。
ディレクトリ: C:\test Mode LastWriteTime Length Name ---- ------------- ------ ---- -a--- 2014/12/16 4:09 1382 localhost.mof
MOF を見てみよう
生成されたMOFを見てみます。
あら、パスワードが丸見えですね。困ったものです。そう、Passw0rds
というのが今回指定したパスワードでした。
このままStart-DSCConfiguration
を実行してみましょう。
設定されました。
詳細: パラメーター ''methodName' = SendConfigurationApply,'className' = MSFT_DSCLocalConfigurationManager,'namespaceName ' = root/Microsoft/Windows/DesiredStateConfiguration' を使用して操作 'CimMethod の呼び出し' を実行します。 詳細: コンピューター DSCSERVER、ユーザー SID S-1-5-21-2427780029-983018638-525960072-500 から LCM メソッドが呼び出されました。 詳細: [DSCSERVER]: LCM: [ 開始 設定 ] 詳細: [DSCSERVER]: LCM: [ 開始 リソース ] [[User]NoEncryption] 詳細: [DSCSERVER]: LCM: [ 開始 テスト ] [[User]NoEncryption] 詳細: [DSCSERVER]: [[User]NoEncryption] test という名前のユーザーが存在しません。 詳細: [DSCSERVER]: LCM: [ 終了 テスト ] [[User]NoEncryption] 2.2810 秒かかりました。 詳細: [DSCSERVER]: LCM: [ 開始 設定 ] [[User]NoEncryption] 詳細: [DSCSERVER]: [[User]NoEncryption] ユーザー test の構成が開始されました。 詳細: [DSCSERVER]: [[User]NoEncryption] ユーザー test が正常に作成されました。 詳細: [DSCSERVER]: [[User]NoEncryption] ユーザー test の構成が正常に完了しました。 詳細: [DSCSERVER]: LCM: [ 終了 設定 ] [[User]NoEncryption] 2.2820 秒かかりました。 詳細: [DSCSERVER]: LCM: [ 終了 リソース ] [[User]NoEncryption] 詳細: [DSCSERVER]: LCM: [ 終了 設定 ] 詳細: [DSCSERVER]: LCM: [ 終了 設定 ] (4.5790 秒)。 詳細: 操作 'CimMethod の呼び出し' が完了しました。 詳細: 構成ジョブが完了するまでにかかった時間は 4.619 秒です
公開鍵暗号を行う
では証明書を使った公開鍵暗号を試しましょう。今回は、自己証明書でやりましょう。
手段はいろいろあるので、mkcert でも、 New-SelfSignedCertificate
でも、Active Directory の証明書機関でも、GEO証明書でもどれでもどうぞ。
コンフィグレーションを書く
さて細かくいっても仕方ないでしょう。コンフィグレーションデータとコンフィグレーションはこんな感じです。
ここまで読んできた方にはもう簡単ではないでしょうか。コンフィグレーションデータ内部で以下を行っています。
PSDscAllowPlainTextPassword
に$false
を指定CertificateFile
に 公開鍵.Cer
ファイル へのパスを指定Thumbprint
に、公開鍵のThumbprint
を指定
PSDscAllowPlainTextPassword = $false CertificateFile = "c:\test.cer" Thumbprint = (ls Cert:\LocalMachine\My | where Subject -eq "CN=test").Thumbprint
もう一点は、LCM を事前に設定していなかった前提として、コンフィグレーションのLocalConfigurationManager
セクションで、CertificateId
に ConfiguraionData で指定したThumbprint を渡しています。事前にLCMへ CertificateId
を指定してあれば、当然コンフィグレーションで一々指定する必要はなく省略してok です。むしろ事前にLCM設定しておきましょう。
LocalConfigurationManager { CertificateId = $AllNodes.ThumbPrint }
MOF の生成
さて、MOFを生成しましょう。当然ですが、コンフィグレーション実行時に コンフィグレーションデータを渡してください。
LCM用の、.meta.mof
とコンフィグレーション実態の.mof
が生成されましたね。
ディレクトリ: C:\test Mode LastWriteTime Length Name ---- ------------- ------ ---- -a--- 2014/12/16 4:25 2128 localhost.mof -a--- 2014/12/16 4:25 892 localhost.meta.mof
MOFを見てみよう
先ほど暗号化しなかったMOFには、パスワードが生でかかれていて怖気が走りましたね。今回は暗号化されているでしょうか。
問題ありませんね。無事暗号化されています。
では、これを適用してみましょう。
LCMを設定していなかった場合
今回のように事前にLCMを設定していなかった人は、コンフィグレーション設定前に対象ノードのLCMを設定します。久々にみた Set-DSCLocalConfigurationManager
ですね。
ちなみに、.meta.mof
の中身は ConfigurationId
の設定だけです。
コンフィグレーションの適用
では、ノードをPUSHであるべき状態にしましょう。
詳細: パラメーター ''methodName' = SendConfigurationApply,'className' = MSFT_DSCLocalConfigurationManager,'namespaceName ' = root/Microsoft/Windows/DesiredStateConfiguration' を使用して操作 'CimMethod の呼び出し' を実行します。 詳細: コンピューター GREENDSCSERVER、ユーザー SID S-1-5-21-2427780029-983018638-525960072-500 から LCM メソッドが呼び出されました。 詳細: [DSCSERVER]: LCM: [ 開始 設定 ] 詳細: [DSCSERVER]: LCM: [ 開始 リソース ] [[User]Encryption] 詳細: [DSCSERVER]: LCM: [ 開始 テスト ] [[User]Encryption] 詳細: [DSCSERVER]: [[User]Encryption] test という名前のユーザーが存在しません。 詳細: [DSCSERVER]: LCM: [ 終了 テスト ] [[User]Encryption] 2.3750 秒かかりました。 詳細: [DSCSERVER]: LCM: [ 開始 設定 ] [[User]Encryption] 詳細: [DSCSERVER]: [[User]Encryption] ユーザー test の構成が開始されました。 詳細: [DSCSERVER]: [[User]Encryption] ユーザー test が正常に作成されました。 詳細: [DSCSERVER]: [[User]Encryption] ユーザー test の構成が正常に完了しました。 詳細: [DSCSERVER]: LCM: [ 終了 設定 ] [[User]Encryption] 2.3130 秒かかりました。 詳細: [DSCSERVER]: LCM: [ 終了 リソース ] [[User]Encryption] 詳細: [DSCSERVER]: LCM: [ 終了 設定 ] 詳細: [DSCSERVER]: LCM: [ 終了 設定 ] (4.7190 秒)。 詳細: 操作 'CimMethod の呼び出し' が完了しました。 詳細: 構成ジョブが完了するまでにかかった時間は 4.722 秒です
完了ですね。簡単でしょ?
まとめ
公開鍵暗号は、Windows でデファクトスタンダードのようにそこかしこで使われています。
MOFを毎回処分することは困難でしょうから、LANだとしてもきっちり処理したいですね。