PowerVault.psm1

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
$prefix = '/v1/'

<#
.Synopsis
   Return an Object containing Vault connection details.
.DESCRIPTION
   This is session variable required by all other Cmdlets.
.EXAMPLE
   PS C:\> $vault = Get-Vault -Address 127.0.0.1 -Token 46e231ee-49bb-189d-c58d-f276743ececa
#>

function Get-Vault
{
    [CmdletBinding()]
    [Alias()]
    [OutputType([PSCustomObject])]
    Param
    (
        # Server Address
        [Parameter(Position=0)]
        [String]
        $Address = $env:VAULT_ADDR,

        # Client token
        [Parameter(Position=1)]
        [String]
        $Token = $env:VAULT_TOKEN
    )


    [PSCustomObject]@{'uri'= $Address + $prefix
                      'auth_header' = @{'X-Vault-Token'=$Token}
                      } |
    Write-Output

}

<#
.Synopsis
   Test connectivity to the Vault server.
.DESCRIPTION
   This method returns the health of the server if it can connect.
.EXAMPLE
   PS C:\> Test-Vault $vault
 
   initialized sealed standby
   ----------- ------ -------
          True False False
#>

function Test-Vault
{
    [CmdletBinding()]
    [Alias()]
    [OutputType([Object])]
    Param
    (
        # The Object containing Vault access details.
        [Parameter(Mandatory, Position=0)]
        [PSCustomObject]
        $VaultObject

    )

    $uri = $VaultObject.uri + 'sys/health'

    Write-Debug $uri

    Invoke-RestMethod -Uri $uri -Headers $VaultObject.auth_header | Write-Output
}

<#
.Synopsis
   Access a Secret in the Vault
.DESCRIPTION
   This can return a [PSCustomObject] base don the raw Secret or attempt to return a [PSCredential] object.
.EXAMPLE
   PS C:\> Get-Secret -VaultObject $vault -Path secret/hello
 
   value
   -----
   world
.EXAMPLE
   PS C:\> Get-Secret -VaultObject $vault -Path secret/username -AsCredential
 
   UserName Password
   -------- --------
   username System.Security.SecureString
.LINK
   https://www.vaultproject.io/docs/http/index.html
   Get-Vault
.NOTES
   At the current version, Vault does not yet promise backwards compatibility even with the v1 prefix. We'll remove this warning when this policy changes. We expect we'll reach API stability by Vault 0.3.
#>

function Get-Secret
{
    [Diagnostics.CodeAnalysis.SuppressMessageAttribute("PSAvoidUsingConvertToSecureStringWithPlainText", "")]
    [CmdletBinding()]
    [Alias()]
    [OutputType([Object])]
    Param
    (
        # The Object containing Vault access details.
        [Parameter(Mandatory, Position=0)]
        [PSCustomObject]
        $VaultObject,

        # The Path to the secret as you would pass to Vault Read.
        [Parameter(Mandatory, Position=1)]
        [String]
        $Path,

        # Attempt to convert the Secret to a [PSCredential]. If the Secret contains a username property that will be used else the function will fall back to using the Secret name.
        [Parameter()]
        [switch]
        $AsCredential
    )

    $uri = $VaultObject.uri + $Path

    $result = [string]::Empty

    Write-Debug $uri

    try
    {
        $result = Invoke-RestMethod -Uri $uri -Headers $VaultObject.auth_header
    }
    catch
    {
        Throw ("Failed to get secret from " + $uri)
    }

    if ($result)
    {
        if ($result.GetType().Name -eq 'PSCustomObject')
        {
            if ($result | Get-Member -Name data)
            {
                $data = $result | Select-Object -ExpandProperty data

                if ($AsCredential)
                {
                    $username = [string]::Empty

                    if ($data | Get-Member -Name username)
                    {
                        $username = $data.username
                        Write-Verbose "Found a username property in the results. [$username]"
                    }
                    else
                    {
                        $username = $Path.Split('/')[-1]
                        Write-Verbose "Did not find a username property, parsing path. [$username]"
                    }

                    if ($data | Get-Member -Name password)
                    {
                        New-Object -TypeName System.Management.Automation.PSCredential `
                        -ArgumentList $username, ($data.password | ConvertTo-SecureString -AsPlainText -Force)
                    }
                    else
                    {
                        Write-Debug $result
                        throw "The data did not contain a password property."
                    }
                }
                else
                {
                    Write-Output -InputObject $data
                }
            }
        }
        else
        {
            throw $result
        }
    }
    else
    {
        Write-Debug $result
        Write-Verbose "No Secret found. [$Path]"
    }

}

<#
.Synopsis
   Create or update a Secret
.DESCRIPTION
   This will set the contents of a Secret.
.EXAMPLE
   PS C:\> Set-Secret -VaultObject $vault -Path secret/new -Secret @{value="secret"}
 
   PS C:\> Get-Secret $vault secret/new
 
   value
   -----
   secret
#>

function Set-Secret
{
    [CmdletBinding()]
    [Alias()]
    Param
    (
        # The Object containing Vault access details.
        [Parameter(Mandatory, Position=0)]
        [PSCustomObject]
        $VaultObject,

        # The Path to the Secret as you would pass to Vault Read.
        [Parameter(Mandatory, Position=1)]
        [String]
        $Path,

        # The Secret. This will be converted to JSON. A simple Hash works best.
        [Parameter(Mandatory, Position=2)]
        [Object]
        $Secret
    )

    $uri = $VaultObject.uri + $Path

    Write-Debug $uri

    try
    {
        $data = $Secret | ConvertTo-Json

        Write-Debug $data
    }
    catch
    {
        throw "Cannot convert Secret to JSON"
    }

    Invoke-RestMethod -Uri $uri -Method Post -Headers $VaultObject.auth_header -Body $data | Write-Output

}


<#
.Synopsis
   Delete a Secret
.DESCRIPTION
   This will set the delete of a Secret.
.EXAMPLE
   PS C:\> Remove-Secret $vault secret/new
 
   PS C:\> Get-Secret $vault secret/new -Verbose
 
   VERBOSE: No Secret found. [secret/new]
#>

function Remove-Secret
{
    [CmdletBinding()]
    [Alias()]
    Param
    (
        # The Object containing Vault access details.
        [Parameter(Mandatory, Position=0)]
        [PSCustomObject]
        $VaultObject,

        # The Path to the Secret as you would pass to Vault Read.
        [Parameter(Mandatory, Position=1)]
        [String]
        $Path
    )

    $uri = $VaultObject.uri + $Path

    Write-Debug $uri


    Invoke-RestMethod -Uri $uri -Method Delete -Headers $VaultObject.auth_header| Write-Output

}