Skip to content

Commit 5b1f123

Browse files
authored
Secret Management Extension for AKV (#13506)
* secret management * update changelog.md * remove -AsHashtable from ConvertFrom-Json to compatible with windows powershell * try to set subscription to vault subscription
1 parent 1f2b689 commit 5b1f123

File tree

11 files changed

+329
-130
lines changed

11 files changed

+329
-130
lines changed
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
@{
22
ModuleVersion = '1.0'
3-
RootModule = '.\SecretManagementExtension.psm1'
3+
RootModule = '.\Az.KeyVault.Extension.psm1'
44
FunctionsToExport = @('Set-Secret','Get-Secret','Remove-Secret','Get-SecretInfo','Test-SecretVault')
55
}
Lines changed: 297 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,297 @@
1+
# Copyright (c) Microsoft Corporation. All rights reserved.
2+
# Licensed under the MIT License.
3+
4+
function Check-SubscriptionLogIn
5+
{
6+
param (
7+
[string] $SubscriptionId,
8+
[string] $AzKVaultName
9+
)
10+
11+
$azContext = Az.Accounts\Get-AzContext
12+
if (($azContext -eq $null) -or ($azContext.Subscription.Id -ne $SubscriptionId))
13+
{
14+
try
15+
{
16+
Set-AzContext -SubscriptionId ${SubscriptionId} -ErrorAction Stop
17+
}
18+
catch
19+
{
20+
throw "To use ${AzKVaultName} Azure vault, the current user must be logged into Azure account subscription ${SubscriptionId}. Run 'Connect-AzAccount -SubscriptionId ${SubscriptionId}'."
21+
}
22+
}
23+
}
24+
25+
function Get-Secret
26+
{
27+
param (
28+
[string] $Name,
29+
[string] $VaultName,
30+
[hashtable] $AdditionalParameters
31+
)
32+
33+
Check-SubscriptionLogIn $AdditionalParameters.SubscriptionId $AdditionalParameters.AZKVaultName
34+
35+
$secret = Az.KeyVault\Get-AzKeyVaultSecret -Name $Name -VaultName $AdditionalParameters.AZKVaultName
36+
if ($secret -ne $null)
37+
{
38+
switch ($secret.ContentType) {
39+
'ByteArray'
40+
{
41+
$SecretValue = Get-ByteArray $Secret
42+
}
43+
'String'
44+
{
45+
$SecretValue = Get-String $Secret
46+
}
47+
48+
'PSCredential'
49+
{
50+
Get-PSCredential $Secret
51+
}
52+
'Hashtable'
53+
{
54+
Get-Hashtable $Secret
55+
}
56+
Default
57+
{
58+
$SecretValue = Get-SecureString $Secret
59+
}
60+
}
61+
return $SecretValue
62+
}
63+
}
64+
65+
function Get-ByteArray
66+
{
67+
param (
68+
[Parameter(Mandatory=$true, Position=0)]
69+
[object] $Secret
70+
)
71+
$secretValueText = Get-String $Secret
72+
return [System.Text.Encoding]::ASCII.GetBytes($secretValueText)
73+
}
74+
75+
function Get-String
76+
{
77+
param (
78+
[Parameter(Mandatory=$true, Position=0)]
79+
[object] $Secret
80+
)
81+
82+
$ssPtr = [System.Runtime.InteropServices.Marshal]::SecureStringToBSTR($Secret.SecretValue)
83+
try {
84+
$secretValueText = [System.Runtime.InteropServices.Marshal]::PtrToStringBSTR($ssPtr)
85+
} finally {
86+
[System.Runtime.InteropServices.Marshal]::ZeroFreeBSTR($ssPtr)
87+
}
88+
return $secretValueText
89+
}
90+
91+
function Get-SecureString
92+
{
93+
param (
94+
[Parameter(Mandatory=$true, Position=0)]
95+
[object] $Secret
96+
)
97+
98+
return $Secret.SecretValue
99+
}
100+
101+
function Get-PSCredential
102+
{
103+
param (
104+
[Parameter(Mandatory=$true, Position=0)]
105+
[object] $Secret
106+
)
107+
108+
$secretHashTable = Get-Hashtable $Secret
109+
return [System.Management.Automation.PSCredential]::new($secretHashTable["UserName"], ($secretHashTable["Password"] | ConvertTo-SecureString -AsPlainText -Force))
110+
}
111+
112+
function Get-Hashtable
113+
{
114+
param (
115+
[Parameter(Mandatory=$true, Position=0)]
116+
[object] $Secret
117+
)
118+
119+
$jsonObject = Get-String $Secret | ConvertFrom-Json
120+
$hashtable = @{}
121+
$jsonObject.psobject.Properties | foreach { $hashtable[$_.Name] = $_.Value }
122+
return $hashtable
123+
}
124+
125+
function Set-Secret
126+
{
127+
param (
128+
[string] $Name,
129+
[object] $Secret,
130+
[string] $VaultName,
131+
[hashtable] $AdditionalParameters
132+
)
133+
134+
Check-SubscriptionLogIn $AdditionalParameters.SubscriptionId $AdditionalParameters.AZKVaultName
135+
136+
switch ($Secret.GetType().Name) {
137+
'Byte[]'
138+
{
139+
Set-ByteArray -Name $Name -Secret $Secret -AZKVaultName $AdditionalParameters.AZKVaultName -ContentType 'ByteArray'
140+
}
141+
'String'
142+
{
143+
Set-String -Name $Name -Secret $Secret -AZKVaultName $AdditionalParameters.AZKVaultName -ContentType 'String'
144+
}
145+
'SecureString'
146+
{
147+
Set-SecureString -Name $Name -Secret $Secret -AZKVaultName $AdditionalParameters.AZKVaultName -ContentType 'SecureString'
148+
}
149+
'PSCredential'
150+
{
151+
Set-PSCredential -Name $Name -Secret $Secret -AZKVaultName $AdditionalParameters.AZKVaultName -ContentType 'PSCredential'
152+
}
153+
'Hashtable'
154+
{
155+
Set-Hashtable -Name $Name -Secret $Secret -AZKVaultName $AdditionalParameters.AZKVaultName -ContentType 'Hashtable'
156+
}
157+
Default
158+
{
159+
throw "Invalid type. Types supported: byte[], string, SecureString, PSCredential, Hashtable";
160+
}
161+
}
162+
163+
return $?
164+
}
165+
166+
function Set-ByteArray
167+
{
168+
param (
169+
[string] $Name,
170+
[Byte[]] $Secret,
171+
[string] $AZKVaultName,
172+
[string] $ContentType
173+
)
174+
175+
$SecretString = [System.Text.Encoding]::ASCII.GetString($Secret)
176+
Set-String -Name $Name -Secret $SecretString -AZKVaultName $AZKVaultName -ContentType $ContentType
177+
}
178+
179+
function Set-String
180+
{
181+
param (
182+
[string] $Name,
183+
[string] $Secret,
184+
[string] $AZKVaultName,
185+
[string] $ContentType
186+
)
187+
$SecureSecret = ConvertTo-SecureString -String $Secret -AsPlainText -Force
188+
$null = Az.KeyVault\Set-AzKeyVaultSecret -Name $Name -SecretValue $SecureSecret -VaultName $AZKVaultName -ContentType $ContentType
189+
}
190+
191+
function Set-SecureString
192+
{
193+
param (
194+
[string] $Name,
195+
[SecureString] $Secret,
196+
[string] $AZKVaultName,
197+
[string] $ContentType
198+
)
199+
200+
$null = Az.KeyVault\Set-AzKeyVaultSecret -Name $Name -SecretValue $Secret -VaultName $AZKVaultName -ContentType $ContentType
201+
}
202+
203+
function Set-PSCredential
204+
{
205+
param (
206+
[string] $Name,
207+
[PSCredential] $Secret,
208+
[string] $AZKVaultName,
209+
[string] $ContentType
210+
)
211+
$secretHashTable = @{"UserName" = $Secret.UserName; "Password" = $Secret.GetNetworkCredential().Password}
212+
$SecretString = ConvertTo-Json $secretHashTable
213+
Set-String -Name $Name -Secret $SecretString -AZKVaultName $AZKVaultName -ContentType $ContentType
214+
}
215+
216+
function Set-Hashtable
217+
{
218+
param (
219+
[string] $Name,
220+
[Hashtable] $Secret,
221+
[string] $AZKVaultName,
222+
[string] $ContentType
223+
)
224+
$SecretString = ConvertTo-Json $Secret
225+
Set-String -Name $Name -Secret $SecretString -AZKVaultName $AZKVaultName -ContentType $ContentType
226+
}
227+
228+
function Remove-Secret
229+
{
230+
param (
231+
[string] $Name,
232+
[string] $VaultName,
233+
[hashtable] $AdditionalParameters
234+
)
235+
236+
Check-SubscriptionLogIn $AdditionalParameters.SubscriptionId $AdditionalParameters.AZKVaultName
237+
238+
$null = Az.KeyVault\Remove-AzKeyVaultSecret -Name $Name -VaultName $AdditionalParameters.AZKVaultName -Force
239+
return $?
240+
}
241+
242+
function Get-SecretInfo
243+
{
244+
param (
245+
[string] $Filter,
246+
[string] $VaultName,
247+
[hashtable] $AdditionalParameters
248+
)
249+
250+
Check-SubscriptionLogIn $AdditionalParameters.SubscriptionId $AdditionalParameters.AZKVaultName
251+
252+
if ([string]::IsNullOrEmpty($Filter))
253+
{
254+
$Filter = "*"
255+
}
256+
257+
$pattern = [WildcardPattern]::new($Filter)
258+
259+
$vaultSecretInfos = Az.KeyVault\Get-AzKeyVaultSecret -VaultName $AdditionalParameters.AZKVaultName
260+
261+
foreach ($vaultSecretInfo in $vaultSecretInfos)
262+
{
263+
if ($pattern.IsMatch($vaultSecretInfo.Name))
264+
{
265+
if($vaultSecretInfo.ContentType -eq $null)
266+
{
267+
$vaultSecretInfo.ContentType = 'Unknown'
268+
}
269+
Write-Output (
270+
[Microsoft.PowerShell.SecretManagement.SecretInformation]::new(
271+
$vaultSecretInfo.Name,
272+
[System.Enum]::Parse([Microsoft.PowerShell.SecretManagement.SecretType], $vaultSecretInfo.ContentType),
273+
$VaultName)
274+
)
275+
}
276+
}
277+
}
278+
279+
function Test-SecretVault
280+
{
281+
param (
282+
[string] $VaultName,
283+
[hashtable] $AdditionalParameters
284+
)
285+
286+
try
287+
{
288+
Check-SubscriptionLogIn $AdditionalParameters.SubscriptionId $AdditionalParameters.AZKVaultName
289+
}
290+
catch
291+
{
292+
Write-Error $_
293+
return $false
294+
}
295+
296+
return $true
297+
}

src/KeyVault/KeyVault/Az.KeyVault.psd1

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -73,7 +73,7 @@ RequiredAssemblies = 'Microsoft.Azure.KeyVault.dll',
7373
FormatsToProcess = 'KeyVault.format.ps1xml'
7474

7575
# Modules to import as nested modules of the module specified in RootModule/ModuleToProcess
76-
NestedModules = @('Microsoft.Azure.PowerShell.Cmdlets.KeyVault.dll')
76+
NestedModules = @('Microsoft.Azure.PowerShell.Cmdlets.KeyVault.dll', '.\Az.KeyVault.Extension')
7777

7878
# Functions to export from this module, for best performance, do not use wildcards and do not delete the entry, use an empty array if there are no functions to export.
7979
FunctionsToExport = @()

src/KeyVault/KeyVault/ChangeLog.md

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,8 @@
1818
- Additional information about change #1
1919
-->
2020
## Upcoming Release
21+
* Supported new version of SecretManagement module [#13366]
22+
* Supported ByteArray, String, PSCredential and Hashtable for `SecretValue` in SecretManagementModule [#12190]
2123

2224
## Version 3.1.0
2325
* Supported updating key vault tag

src/KeyVault/KeyVault/KeyVault.csproj

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -28,7 +28,7 @@
2828
</ItemGroup>
2929

3030
<ItemGroup>
31-
<None Update="SecretManagementExtension\*" CopyToOutputDirectory="PreserveNewest" />
31+
<None Update="Az.KeyVault.Extension\*" CopyToOutputDirectory="PreserveNewest" />
3232
</ItemGroup>
3333

3434
<ItemGroup>

0 commit comments

Comments
 (0)