Powershellスクリプトの署名と証明書の操作
Powershell、とっても便利じゃないですか。
便利、それは危険ということ。
セキュリティホールつかれてスクリプトが実行されたら大変ですよね!
利便性のためにすぐRemoteSignedにしがちですが、せめてAllSignedにしましょう。
ということで、方法を考えてみました。
方針を考える
署名用の使える証明書を取得するのも面倒なので、自己証明書にする。
スクリプト編集モードでは、Watcherで自動的に署名する。
スクリプト編集モードを解除したら、Watcherを止める。
ついでに、署名用の証明書も、出し入れする。
あと、自己証明書で署名したスクリプトを他のPCで実行する方法の確認。
スクリプト
とりあえず完成したもの
function Enable-ScriptEdit() { # 署名用自己証明書のインポート $x509store = New-Object System.Security.Cryptography.X509Certificates.X509Store('My', 'CurrentUser') $x509store.Open('ReadWrite') $x509store.Add((New-Object System.Security.Cryptography.X509Certificates.X509Certificate2([Convert]::FromBase64String(@" ここに、貴方の署名用自己証明書をエクスポート・Base64文字列化したものを書く エクスポート方法は「help about_signing」を見てね(.pfxファイルです) Base64文字列化は「[Convert]::ToBase64String([System.IO.File]::ReadAllBytes($path))」 "@), (Read-Host 'Password' -AsSecureString)))) $x509store.Close() # 署名Watcherの起動 Start-Watcher { Param($sender, $ev) if($ev.ChangeType -ne 'Deleted') { $f = Get-Item $ev.FullPath $SignedFilePath = "$($f.BaseName).Signed$($f.Extension)" if((Test-Path $SignedFilePath) -and ($f.LastWriteTime -gt (Get-Item $SignedFilePath).LastWriteTime)) { Save-SignedScript -FileInfo $f } } } (Get-Location) '*.ps1' } function Disable-ScriptEdit() { #署名Watcherの停止 Remove-Watcher (Get-Location) '*.ps1' #署名用自己証明書の削除 $x509store = New-Object System.Security.Cryptography.X509Certificates.X509Store('My', 'CurrentUser') $x509store.Open('ReadWrite') $tar = Get-ChildItem Cert:\CurrentUser\My -CodeSigningCert if($tar -ne $null) { $x509store.Remove($tar) } $x509store.Close() }
Save-SignedScript依存。
Enable-ScriptEdit/Disable-ScriptEditが現在のディレクトリーに依存してますが、私の手元では固定にしてます。
(未署名のスクリプト置き場と実行する場所を別にしているので。なので微妙に変えています)
自己証明書の削除も1件しかない想定のスクリプトですが、手元はWhere使って1件にしてたりします。
そんなこんなでAllSignedでもストレスフリー!
自己証明書署名のスクリプトを他のPCで
自己のルート証明書を入れないといけません。
.cerファイルを叩けばインポートの選択肢が出ますが、ウイザードに付き合わないといけなくなります。
以下のスクリプトなら、確認ダイアログが一枚出るだけ!
$x509store = New-Object System.Security.Cryptography.X509Certificates.X509Store('Root', 'CurrentUser') $x509store.Open('ReadWrite') $x509store.Add([System.Security.Cryptography.X509Certificates.X509Certificate2][Convert]::FromBase64String(@" ここに、貴方の自己ルート証明書をBase64文字列化したものを書く 「help about_signing」通りやっているなら「root.cer」です。 "@)) $x509store.Close()
そうそう、引数一つのコンストラクターは、キャストで呼べるみたいよ!
X509Certificate2をNew-Objectで、byte渡したら、そんなたくさん引数のコンストラクターはないって怒られた。
@(,byte)でもよかったけど、キャストでいいよ、とかどこかに書いてあったのでやってみたところ上手くいった!