tech.guitarrapc.cóm

Technical updates

PowerShell DSC Advent Calendar 2014 : Day 11 Configurationに記述したパスワードの暗号化

これは、アドベントカレンダー11日目の記事です。

http://www.adventar.org/calendars/579

時空のゆがみ。

さて、前回まででシンプルなコンフィグレーションをプッシュで反映させる方法を見てきました。

今回は、センシティブな情報。そう、パスワードをどうやってリモート先に安全に伝搬するかです。

センシティブな情報とは

PowerShell DSCの中では、[PSCredential]です。つまり、パスワードなどの機密情報です。

PowerShellには[PSCredential]という型があるので、これがセンシティブな情報となります。

$Passwordのような平文、$Passwordのようなやり方はベストプラクティスからは大きくずれます。やってる人はすぐやめましょう。というレベルで本当に今すぐやめてください。当然DSCでもそれらは非推奨です。当然です。

どうやって暗号化するの

暗号化は、公開鍵暗号を用います。ざっくりとした詳細はこちらに。

http://technet.microsoft.com/en-us/library/dn781430.aspx

さくっと流れを抑えましょう。

ノード

DSCサーバーから取得したMOFファイルの暗号化データを自分の秘密鍵でデコードします。

  • 秘密鍵(*.pfx) を、Cert:\LocalMachine\My** にインポート
  • この秘密鍵から公開鍵(***.cer)をエキスポート
  • この鍵のThumbPrintをノードのLCMにてCertificateIdに指定

DSCサーバー

ノードでエキスポートした公開鍵を使って対称させます。

  • DSCサーバーの任意のパスに公開鍵ファイル(****.cer)を設置
  • DSCサーバーの Cert:\LocalMachine\My に公開鍵をインポート
  • インポートした公開鍵のThumbprintを取得

あとは、DSCサーバーの公開鍵をコンフィグレーション実行時に指定するだけです。

  • コンフィグレーションにPSCredentialでセンシティブ情報を渡す
  • コンフィグレーションの実行時に、コンフィグレーションデータで、公開鍵ファイルパスとThumbPrintを渡す

今回はわかりやすいようにローカルマシンで、ノード、DSCサーバー共に動かします。

暗号化をしない

暗号化しないやり方はBest Practiceではありません

先に、暗号化をしないでコンフィグレーションを扱ってみましょう。

さらっと書いてみます。

https://gist.github.com/guitarrapc/a3a93be20fa02fbb9133

コンフィグレーション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

コンフィグレーションデータを渡す

コンフィグレーションデータを使って、コンフィグレーションデータコンフィグレーションデータを渡して実行します。コンフィグレーションデータが何か忘れた人は8日目をどうぞ。

http://tech.guitarrapc.com/entry/2014/12/08/023134

コンフィグレーションデータを指定して書きなおします。

https://gist.github.com/guitarrapc/7a3670084974dc7ce145

MOFが出力されましたね。

    ディレクトリ: C:\test


Mode                LastWriteTime     Length Name
----                -------------     ------ ----
-a---        2014/12/16      4:09       1382 localhost.mof

MOF を見てみよう

生成されたMOFを見てみます。

https://gist.github.com/guitarrapc/778a2515b29f7dfea60a

あら、パスワードが丸見えですね。困ったものです。そう、Passw0rdsというのが今回指定したパスワードでした。

このままStart-DSCConfigurationを実行してみましょう。

https://gist.github.com/guitarrapc/4ecd12ee93d4fe2f83c5

設定されました。

詳細: パラメーター ''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 秒です

公開鍵暗号を行う

では証明書を使った公開鍵暗号を試しましょう。今回は、自己証明書でやりましょう。

手段はいろいろあります。好きな方法でどうぞ。

コンフィグレーションを書く

さて細かくいっても仕方ないでしょう。コンフィグレーションデータとコンフィグレーションはこんな感じです。

https://gist.github.com/guitarrapc/0ae11df89bb7c8db6420

ここまで読んできた方にはもう簡単ではないでしょうか。コンフィグレーションデータ内部で以下を行っています。

  • PSDscAllowPlainTextPasswordPSDscAllowPlainTextPasswordを指定
  • CertificateFileに公開鍵CertificateFileファイルへのパスを指定
  • Thumbprintに、公開鍵のThumbprintを指定
PSDscAllowPlainTextPassword = $false
CertificateFile = "c:\test.cer"
Thumbprint = (ls Cert:\LocalMachine\My | where Subject -eq "CN=test").Thumbprint

もう一点は、LCMを事前に設定していなかった前提として、コンフィグレーションのLocalConfigurationManagerセクションで、LocalConfigurationManagerにConfiguraionDataで指定したThumbprintを渡しています。事前にLCMへLocalConfigurationManagerを指定してあれば、当然コンフィグレーションで一々指定する必要はなく省略してokです。むしろ事前にLCM設定しておきましょう。

LocalConfigurationManager
{
    CertificateId =  $AllNodes.ThumbPrint
}

MOF の生成

さて、MOFを生成しましょう。当然ですが、コンフィグレーション実行時にコンフィグレーションデータを渡してください。

https://gist.github.com/guitarrapc/a7bdcbb90505e8e0c4ce

LCM用の、.meta.mofとコンフィグレーション実態の.meta.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には、パスワードが生でかかれていて怖気が走りましたね。今回は暗号化されているでしょうか。

https://gist.github.com/guitarrapc/6cc3fb9000e5fe772a66

問題ありませんね。無事暗号化されています。

では、これを適用してみましょう。

LCMを設定していなかった場合

今回のように事前にLCMを設定していなかった人は、コンフィグレーション設定前に対象ノードのLCMを設定します。久々にみたSet-DSCLocalConfigurationManagerですね。

https://gist.github.com/guitarrapc/ae3d60e9517587abda71

ちなみに、.meta.mofの中身は.meta.mofの設定だけです。

https://gist.github.com/guitarrapc/9c3eaaab8f1a491fe9d9

コンフィグレーションの適用

では、ノードをPUSHであるべき状態にしましょう。

https://gist.github.com/guitarrapc/e9be74af0f5c712f8ce7

詳細: パラメーター ''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だとしてもきっちり処理したいですね。