「スケジュールジョブ(PowerShell)でパスワードをセキュアに使う(セキュアストリング編)」で、セキュアストリングを使ってパスワードをセキュアにハンドリングして認証する方法を書きましたが、セキュアストリングは実行アカウントに紐づいているので、ワークグループで展開するには何かと面倒です。
良い方法がないかと思っていたら、MS エバンジェリストの安納さんが Blog で証明書を使ってパスワードハンドリングする方法を紹介していたので、これを下敷きにしてセキュアなパスワードのハンドリング方法です。
手順をざっくり説明すると...
暗号化準備
Windows SDK インストール
証明書作成
拇印の取得
展開準備
パスワード暗号化
証明書エクスポート
展開と活用
証明書インポート
パスワード復号
こんな流れになります。
証明書は コンピューター証明書にストアしているので、証明書アクセスには管理権限が必要ですが、実行アカウントをビルトインの「SYSTEM」にしても問題なくパスワードを取り出すことができます。
まずは使用する証明書ですが、AD CSで発行すると有効期限がどうしても限られるので、自己署名証明書で有効期限を2050/12/31って証明書を作ります。
自己署名証明書の作成は、makecat.exe を使います。
makecat.exe はVisual Studio に含まれていますが、Visual Studio をインストールしていない環境では Windows SDK をインストールします。
Windows Software Development Kit (SDK) for Windows 8.1
ダウンロードした sdksetup.exe を実行すると、何をインストールするのかを聞いてきますので「Windows Software Development Kit」のみをインストールします。
makecert.exe は以下にインストールされます。
C:\Program Files (x86)\Windows Kits\8.1\bin\x64\makecert.exe
C:\Program Files (x86)\Windows Kits\8.1\bin\x86\makecert.exe
C:\Program Files (x86)\Windows Kits\10\bin\10.0.15063.0\x64\makecert.exe
C:\Program Files (x86)\Windows Kits\10\bin\10.0.15063.0\x86\makecert.exe
makecat.exe のあるフォルダをカレントにして、以下のコマンドで証明書を作成します。(PowerShellプロンプトで実行する前提です)
証明書は、コンピューター証明書の個人に格納されます。
.\makecert -sky exchange -r -n "CN=Encpassword" -pe -a sha256 -len 2048 -e 12/31/2050 -sr LocalMachine -ss My "EncPassword.cer" |
関数にするとこんな感じになります
|
証明書は拇印をキーにハンドリングするので、証明書ができたら拇印を取得します。
$CertName = "YourCertName" $ThumbprintFile = "C:\Work\Thumbprint.txt" # 拇印の取得 $Thumbprint = (Get-ChildItem Cert:\LocalMachine\My | ? {$_.Subject -eq "CN=$CertName"}).Thumbprint # 拇印をファイルに出力 $Thumbprint | Set-Content $ThumbprintFile |
関数にするとこんな感じになります
|
それでは証明書を使ってパスワードを暗号化しましょう。(赤文字が暗号化するパスワード)
## パスワードの暗号化 $PlainPassword = "P@ssw0rdP@ssw0rd" $ThumbprintFile = "C:\Work\Thumbprint.txt" $PasswordFile = "C:\Work\Password.txt" # 証明書の拇印(Thumbprint)読み込み $Thumbprint = Get-Content $ThumbprintFile # パスワードの暗号化(暗号化してBase64で出力) $Cert = get-item cert:\LocalMachine\MY\$Thumbprint Add-type –AssemblyName System.Security $pass = [Text.Encoding]::UTF8.GetBytes($PlainPassword) $content = new-object Security.Cryptography.Pkcs.ContentInfo –argumentList (,$pass) $Enveloped = new-object Security.Cryptography.Pkcs.EnvelopedCms $content $Enveloped.Encrypt((new-object System.Security.Cryptography.Pkcs.CmsRecipient($Cert))) $Password = [Convert]::ToBase64String($Enveloped.Encode()) # 暗号化されたパスワードをファイルに出力 $Password | Set-Content $PasswordFile |
関数にするとこんな感じになります
|
出力された暗号化パスワードを別のコンピューターで使うには、復号用の証明書をインポートし、インポートした証明書を使ってパスワードを復号します。
まずは、証明書を持っているコンピューターから復号用証明書をエクスポートします。
GUI でエクスポートしても良いのですが、PowerShell でエクスポートするのならこんな感じです。
# 証明書のエクスポート(Windows Server 2012/ Windows 8以降の場合) $ThumbprintFile = "C:\Work\Thumbprint.txt" $CertFile = "C:\Work\EncPassword.pfx" # 証明書の拇印(Thumbprint)読み込み $Thumbprint = Get-Content $ThumbprintFile # パスワードを指定して証明書のエクスポート $Password = ConvertTo-SecureString -AsPlainText -Force "P@ssw0rd" $Cert = get-item cert:\LocalMachine\MY\$Thumbprint Export-PfxCertificate -Cert $Cert -FilePath $CertFile -Password $Password |
関数にするとこんな感じになります
|
# 証明書のエクスポート(Windows
Server 2008 R2 / Windows 7以前の場合) $ThumbprintFile = "C:\Work\Thumbprint.txt" $CertFile = "C:\Work\EncPassword.pfx" # 証明書の拇印(Thumbprint)読み込み $Thumbprint = Get-Content $ThumbprintFile # パスワードを指定して証明書のエクスポート $Cert = get-item cert:\LocalMachine\MY\$Thumbprint $bytes = $Cert.Export("Pfx","P@ssw0rd") [System.IO.File]::WriteAllBytes($CertFile, $bytes) |
関数にするとこんな感じになります
|
続いて、対象のコンピューターで証明書をインポートします。インポート先はコンピューター証明書の個人です。
GUIでインポートしても良いのですが、PowerShellでインポートするのならこんな感じです。
# 証明書のインポート(Windows Server 2012/ Windows 8以降の場合) $Password = ConvertTo-SecureString -AsPlainText -Force "P@ssw0rd" $CertFile = "C:\common\EncPassword.pfx" $Cert = "Cert:\LocalMachine\My" Import-PfxCertificate -FilePath $CertFile -CertStoreLocation $Cert -Password $Password |
# 証明書のインポート(Windows Server 2008 R2 / Windows
7以前の場合) $CertFile = "C:\common\EncPassword.pfx" certutil -p "P@ssw0rd" -importpfx $CertFile NoExport |
インポートしたら、EncPassword.pfx は不要なので削除します(パスワード保護がかかっているとはいえ、秘密鍵を持っているので必ず削除します)
インポートはよく使うので、ps1 にしておくと便利です。
InstallCertificate.ps1
|
拇印ファイルと、パスワードファイルを読み込んで、パスワードを証明書復号します。
# パスワードの復号 $PasswordFile = "C:\common\Password.txt" $ThumbprintFile = "C:\common\Thumbprint.txt" # 暗号化や復号化に必要な System.Security アセンブリを読み込む Add-type –AssemblyName System.Security # 証明書の拇印(Thumbprint)の読み込み $Thumbprint = Get-Content $ThumbprintFile # 証明書を取得 $Cert = get-item cert:\LocalMachine\MY\$Thumbprint # 暗号化したパスワードの読み込み $Password = Get-Content $PasswordFile # Base64でエンコードされたパスワードをデコードし、証明書を使って復号化(Decrypt) $Enveloped = new-object Security.Cryptography.Pkcs.EnvelopedCms $Enveloped.Decode([Convert]::FromBase64String( $Password )) $Enveloped.Decrypt( $Cert ) # バイト型からストリング型に変換 $PlainPassword = [Text.Encoding]::UTF8.GetString($Enveloped.ContentInfo.Content) # 平文に復号されたパスワード $PlainPassword |
このスクリプトを実行するバッチに組み込んで使います。
復号もよく使うので、関数化しておくと便利です。
|
PowerShell のコマンドレットで指定する -Credential オプションに引き渡す資格情報は ID /
Password の平文ではないので、資格情報を作成する必要があります。
その場合はこちらをどうぞ。
【PowerShell】証明書を使用してパスワードを暗号化する
【PowerShell】証明書を使用して暗号化したパスワードを復号する
AES 256 の PowerShell 実装
http://www.vwnet.jp/Windows/PowerShell/AES.htm
SHA-2(SHA256) の PowerShell 実装
http://www.vwnet.jp/Windows/PowerShell/SHA256.htm
RSA 公開鍵暗号の PowerShell 実装
http://www.vwnet.jp/Windows/PowerShell/RSACrypto.htm
RSA 電子署名(SHA256)の PowerShell 実装
http://www.vwnet.jp/Windows/PowerShell/RSASignature.htm
HMAC(SHA256) の PowerShell 実装
http://www.vwnet.jp/Windows/PowerShell/HMAC-SHA256.htm
関数を PowerShell プロンプトで実行する
http://www.vwnet.jp/Windows/PowerShell/2016100401/UseFunctionInPsPrompt.htm
Copyright © MURA All rights reserved.