jborean93 / SecretManagement.DpapiNG

PowerShell SecretManagement module for DPAPI-NG
MIT License
16 stars 0 forks source link

Concurrent vault access under different identities #8

Open davehope opened 6 days ago

davehope commented 6 days ago

Concurrent access, from processes running under different user identities, results in a failure to retrieve the secret and an exception being thrown:

Get-Secret : The process cannot access the file 'C:\Scripts\Data\dpaping.vault' because it is being used by another process.
At line:3 char:10
+     $r = Get-Secret -Name 'demo' -Vault DPAPING
+          ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
    + CategoryInfo          : NotSpecified: (:) [Get-Secret], IOException
    + FullyQualifiedErrorId : System.IO.IOException,Microsoft.PowerShell.SecretManagement.GetSecretCommand

This can be reproduced by running the following code under two accounts at the same time, ensuring the vault "DPAPING" points to the same file and that the protection descriptor allows access.

while($true)
{
    $c = Get-Secret -Name 'demo' -Vault DPAPING
}
davehope commented 5 days ago

Exploring this issue a little further, it looks like LiteDB is used with the relevant section of code in DpapiNGSecretBase.ProcessRecord(), src/SecretManagement.DpapiNG.Module/DpapiNGSecretBase.cs

On that basis, the issue can be reproduced in an approach similar to my previous post but with:

Add-Type -Path 'C:\Program Files\WindowsPowerShell\Modules\SecretManagement.DpapiNG\0.3.0\SecretManagement.DpapiNG.Extension\bin\net472\LiteDB.dll'
$dbPath = 'C:\Scripts\Data\dpaping.vault'
while($true)
{
    [LiteDB.LiteDatabase]$db = [LiteDB.LiteDatabase]::new($dbPath)
    $secrets = $db.GetCollection('secrets')
    $db.Dispose()
}

If shared connection mode is used, the two processes happily execute at the same time.

[LiteDB.LiteDatabase]$db = [LiteDB.LiteDatabase]::new("Filename=$dbPath;connection=shared")

Unfortunately the validation in ProcessRecord() would prevent me just setting the path as a connection string in VaultParameters.

Perhaps one option could be to check for a connection property on VaultParameters, allowing people to set shared mode if needed?