powershell-security について
資格情報の管理、スクリプトの強化、管理制御を扱う PowerShell セキュリティスキルです。スクリプト作成者や管理者向けに、SecretManagement、JEA、WDAC、署名、ログ記録を解説します。
主な機能
- 01SecretManagement とボールトプロバイダーの指針
- 02資格情報の管理と Azure 認証
- 03JEA のロール制限と監査ログ
- 04WDAC と制限付き言語モード
- 05スクリプト署名と実行ポリシー
- 06入力検証とセキュリティチェックリスト
活用シーン
- 01スクリプトから平文の資格情報を除去
- 02委任する PowerShell 管理権限の制限
- 03特権自動化セッションの監査
- 04本番用スクリプトのセキュリティ強化
インストール
コマンドをコピーしてターミナルで実行します。
$
npx skills add https:/ / github.com/ josiahsiegel/ claude-plugin-marketplace --skill powershell-securityインストール後、Claude Code で/powershell-securityを入力して読み込まれたか確認します。
詳細
PowerShell のセキュリティに関するベストプラクティス(2025)
PowerShell スクリプトと自動化における最新のセキュリティ対策。資格情報の管理、SecretManagement モジュール、強化の手法を含みます。
SecretManagement モジュール(2025 年推奨標準)
概要
Microsoft.PowerShell.SecretManagement は、PowerShell で資格情報を安全に保存するための公式ソリューションです。
SecretManagement を使用する理由:
- スクリプトに平文の資格情報を保存しません
- クロスプラットフォームのシークレットストレージ
- 複数のボールトプロバイダーをサポート
- Azure Key Vault、1Password、KeePass などとの統合
インストール
# Install SecretManagement module
Install-Module -Name Microsoft.PowerShell.SecretManagement -Scope CurrentUser
# Install vault provider (choose one or more)
Install-Module -Name Microsoft.PowerShell.SecretStore # Local encrypted vault
Install-Module -Name Az.KeyVault # Azure Key Vault
Install-Module -Name SecretManagement.KeePass # KeePass integration
基本的な使い方
# Register a vault
Register-SecretVault -Name LocalVault -ModuleName Microsoft.PowerShell.SecretStore
# Store a secret
$password = Read-Host -AsSecureString -Prompt "Enter password"
Set-Secret -Name "DatabasePassword" -Secret $password -Vault LocalVault
# Retrieve a secret
$dbPassword = Get-Secret -Name "DatabasePassword" -Vault LocalVault -AsPlainText
# Or as SecureString
$dbPasswordSecure = Get-Secret -Name "DatabasePassword" -Vault LocalVault
# List secrets
Get-SecretInfo
# Remove a secret
Remove-Secret -Name "DatabasePassword" -Vault LocalVault
Azure Key Vault との統合
# Install and import Az.KeyVault
Install-Module -Name Az.KeyVault -Scope CurrentUser
Import-Module Az.KeyVault
# Authenticate to Azure
Connect-AzAccount
# Register Azure Key Vault as secret vault
Register-SecretVault -Name AzureKV `
-ModuleName Az.KeyVault `
-VaultParameters @{
AZKVaultName = 'MyKeyVault'
SubscriptionId = 'your-subscription-id'
}
# Store secret in Azure Key Vault
Set-Secret -Name "ApiKey" -Secret "your-api-key" -Vault AzureKV
# Retrieve from Azure Key Vault
$apiKey = Get-Secret -Name "ApiKey" -Vault AzureKV -AsPlainText
SecretManagement を使用した自動化スクリプト
<#
.SYNOPSIS
Secure automation script using SecretManagement
.DESCRIPTION
Demonstrates secure credential handling without hardcoded secrets
#>
#Requires -Modules Microsoft.PowerShell.SecretManagement
[CmdletBinding()]
param()
# Retrieve credentials from vault
$dbConnectionString = Get-Secret -Name "SQLConnectionString" -AsPlainText
$apiToken = Get-Secret -Name "APIToken" -AsPlainText
# Use credentials securely
try {
# Database operation
$connection = New-Object System.Data.SqlClient.SqlConnection($dbConnectionString)
$connection.Open()
# API call with token
$headers = @{ Authorization = "Bearer $apiToken" }
$response = Invoke-RestMethod -Uri "https://api.example.com/data" -Headers $headers
# Process results
Write-Host "Operation completed successfully"
}
catch {
Write-Error "Operation failed: $_"
}
finally {
if ($connection) { $connection.Close() }
}
資格情報管理のベストプラクティス
資格情報をハードコードしない
# ❌ WRONG - Hardcoded credentials
$password = "MyPassword123"
$username = "admin"
# ❌ WRONG - Plaintext in script
$cred = New-Object System.Management.Automation.PSCredential("admin", "password")
# ✅ CORRECT - SecretManagement
$password = Get-Secret -Name "AdminPassword" -AsPlainText
$securePassword = ConvertTo-SecureString $password -AsPlainText -Force
$cred = New-Object System.Management.Automation.PSCredential("admin", $securePassword)
# ✅ CORRECT - Interactive prompt (for manual runs)
$cred = Get-Credential -Message "Enter admin credentials"
# ✅ CORRECT - Managed Identity (Azure automation)
Connect-AzAccount -Identity
サービスプリンシパル認証(Azure)
# Store service principal credentials in vault
Set-Secret -Name "AzureAppId" -Secret "app-id-guid"
Set-Secret -Name "AzureAppSecret" -Secret "app-secret-value"
Set-Secret -Name "AzureTenantId" -Secret "tenant-id-guid"
# Retrieve and authenticate
$appId = Get-Secret -Name "AzureAppId" -AsPlainText
$appSecret = Get-Secret -Name "AzureAppSecret" -AsPlainText
$tenantId = Get-Secret -Name "AzureTenantId" -AsPlainText
$secureSecret = ConvertTo-SecureString $appSecret -AsPlainText -Force
$credential = New-Object System.Management.Automation.PSCredential($appId, $secureSecret)
Connect-AzAccount -ServicePrincipal -Credential $credential -Tenant $tenantId
Just Enough Administration(JEA)
JEA とは?
Just Enough Administration は、PowerShell リモート処理セッションで使用できるコマンドレットとパラメーターを制限します。
ユースケース
- 管理者権限をすべて付与せずに、管理タスクを委任する
- コンプライアンス要件(SOC 2、HIPAA、PCI-DSS)
- 本番環境の強化
- 特権操作の監査証跡
JEA エンドポイントの作成
# 1. Create role capability file
New-PSRoleCapabilityFile -Path "C:\JEA\RestartServices.psrc" `
-VisibleCmdlets @{
Name = 'Restart-Service'
Parameters = @{
Name = 'Name'
ValidateSet = 'Spooler', 'W32Time', 'WinRM'
}
}, 'Get-Service'
# 2. Create session configuration file
New-PSSessionConfigurationFile -Path "C:\JEA\RestartServices.pssc" `
-SessionType RestrictedRemoteServer `
-RoleDefinitions @{
'DOMAIN\ServiceAdmins' = @{ RoleCapabilities = 'RestartServices' }
} `
-LanguageMode NoLanguage
# 3. Register JEA endpoint
Register-PSSessionConfiguration -Name RestartServices `
-Path "C:\JEA\RestartServices.pssc" `
-Force
# 4. Connect to JEA endpoint (as delegated user)
Enter-PSSession -ComputerName Server01 -ConfigurationName RestartServices
# User can ONLY run allowed commands
Restart-Service -Name Spooler # ✅ Allowed
Restart-Service -Name DNS # ❌ Denied (not in ValidateSet)
Get-Process # ❌ Denied (not visible)
JEA 監査ログ
# Enable transcription and logging
New-PSSessionConfigurationFile -Path "C:\JEA\AuditedSession.pssc" `
-SessionType RestrictedRemoteServer `
-TranscriptDirectory "C:\JEA\Transcripts" `
-RunAsVirtualAccount
# All JEA sessions are transcribed to C:\JEA\Transcripts
# Review audit logs
Get-ChildItem "C:\JEA\Transcripts" | Get-Content
Windows Defender Application Control(WDAC)
PowerShell スクリプトの制御
WDAC は、実行可能な PowerShell スクリプトを制御するために AppLocker を置き換えます。
# Create WDAC policy for signed scripts only
New-CIPolicy -FilePath "C:\WDAC\PowerShellPolicy.xml" `
-ScanPath "C:\Scripts" `
-Level FilePublisher `
-Fallback Hash `
-UserPEs
# Allow only signed scripts
Set-RuleOption -FilePath "C:\WDAC\PowerShellPolicy.xml" `
-Option 3 # Required WHQL
# Convert to binary policy
ConvertFrom-CIPolicy -XmlFilePath "C:\WDAC\PowerShellPolicy.xml" `
-BinaryFilePath "C:\Windows\System32\CodeIntegrity\SIPolicy.p7b"
# Reboot to apply policy
Restart-Computer
コード署名
スクリプトに署名する理由
- スクリプトの整合性を検証する
- 組織のセキュリティポリシーを満たす
- WDAC の適用を可能にする
- 改ざんを防止する
スクリプトへの署名
# Get code signing certificate
$cert = Get-ChildItem Cert:\CurrentUser\My -CodeSigningCert
# Sign script
Set-AuthenticodeSignature -FilePath "C:\Scripts\MyScript.ps1" -Certificate $cert
# Verify signature
$signature = Get-AuthenticodeSignature -FilePath "C:\Scripts\MyScript.ps1"
$signature.Status # Should be "Valid"
実行ポリシー
# Check current execution policy
Get-ExecutionPolicy
# Set execution policy (requires admin)
Set-ExecutionPolicy RemoteSigned -Scope LocalMachine
# Bypass for single script (testing only)
PowerShell.exe -ExecutionPolicy Bypass -File "script.ps1"
制約付き言語モード
制約付き言語モードとは?
悪意のあるコードの実行を防ぐため、PowerShell の言語機能を制限します。
# Check current language mode
$ExecutionContext.SessionState.LanguageMode
# Output: FullLanguage (admin) or ConstrainedLanguage (standard user)
# Set system-wide constrained language mode
# Via Environment Variable or Group Policy
# Set: __PSLockdownPolicy = 4
# Test constrained mode behavior
# FullLanguage allows:
[System.Net.WebClient]::new() # ✅ Allowed
# ConstrainedLanguage blocks:
[System.Net.WebClient]::new() # ❌ Blocked
Add-Type -TypeDefinition "..." # ❌ Blocked
スクリプトブロックのログ記録
ログ記録を有効にする
# Enable via Group Policy or Registry
# HKLM:\Software\Policies\Microsoft\Windows\PowerShell\ScriptBlockLogging
New-ItemProperty -Path "HKLM:\Software\Policies\Microsoft\Windows\PowerShell\ScriptBlockLogging" `
-Name "EnableScriptBlockLogging" -Value 1 -PropertyType DWord
# Log location: Windows Event Log
# Event Viewer > Applications and Services Logs > Microsoft > Windows > PowerShell > Operational
ログを確認する
# Query script block logs
Get-WinEvent -LogName "Microsoft-Windows-PowerShell/Operational" |
Where-Object { $_.Id -eq 4104 } | # Script Block Logging event
Select-Object TimeCreated, Message |
Out-GridView
入力の検証
インジェクション攻撃を防ぐ
# ❌ WRONG - No validation
function Get-UserData {
param($Username)
Invoke-Sqlcmd -Query "SELECT * FROM Users WHERE Username = '$Username'"
}
# Vulnerable to SQL injection
# ✅ CORRECT - Parameterized queries
function Get-UserData {
param(
[ValidatePattern('^[a-zA-Z0-9_-]+$')]
[string]$Username
)
Invoke-Sqlcmd -Query "SELECT * FROM Users WHERE Username = @Username" `
-Variable @{Username=$Username}
}
# ✅ CORRECT - ValidateSet for known values
function Restart-AppService {
param(
[ValidateSet('Web', 'API', 'Worker')]
[string]$ServiceName
)
Restart-Service -Name "App${ServiceName}Service"
}
セキュリティチェックリスト
スクリプト開発
- 資格情報をハードコードしない(SecretManagement を使用する)
- SQL 操作にはパラメーター化クエリを使用する
-
[ValidatePattern]、[ValidateSet]などを使って、すべてのユーザー入力を検証する -
Set-StrictMode -Version Latestを有効にする - エラー処理には
try/catchを使用する - ユーザー入力を伴う
Invoke-Expressionの使用を避ける - 本番環境のスクリプトに署名する
- スクリプトブロックのログ記録を有効にする
自動化
- マネージド ID またはサービスプリンシパルを使用する(パスワードは使用しない)
- シークレットを SecretManagement または Azure Key Vault に保存する
- 管理タスクの委任に JEA を導入する
- すべての特権操作で監査ログを有効にする
- 最小権限の原則を適用する
- 資格情報を定期的にローテーションする
- 認証失敗の試行を監視する
本番環境
- スクリプト制御のために WDAC ポリシーを導入する
- 管理者以外のユーザーには制約付き言語モードを使用する
- PowerShell のログ記録(スクリプトブロックとトランスクリプション)を有効にする
- 署名済みスクリプトを必須にする(実行ポリシーを使用)
- セキュリティ監査を定期的に実施する
- PowerShell を最新の状態に保つ(7.5 以降)
- リモート管理に JEA を使用する
リソース
コメント
Markdown 対応