tech.guitarrapc.cóm

C#, PowerShell, Unity, Cloud, Serverless Technical Update and Features

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

これは、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
コンフィグレーションデータを渡す

ではどうやるか。コンフィグレーションデータを使って、PSDscAllowPlainTextPasswordtrueを渡して実行します。コンフィグレーションデータが何か忘れた人は 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だとしてもきっちり処理したいですね。