Public/Invoke-PANKeyGen.ps1

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
Function Invoke-PANKeyGen {
<#
.SYNOPSIS
  This stores api keys tied to tags/addresses
  Remember, this is basically a encrypted representation of the username and password that a firewall with the same master key can decrypt and use, so if you change the password, this muct also change
 
.DESCRIPTION
  In pan-python, the keys are stored in the clear in a file called .panrc in the users home folder
  I like this idea, but windows allows me to store in a secure string format that allows only the user/pc combination to retrieve the key
    I want to allow users to colaborate/share keys it can be frustrating when using scheduled tasks and/or multiple PCs
 
  With this change in formatting, reusing the .panrc file would cause conflict, so I will use panrc.xml
 
.PARAMETER StorageMeathod
   API_Key - Clear key like pan-python
   SecureAPI_Key - Secured with Windows secure string tied to the user/pc
   <not implemented> SharedSecureAPI_Key - Secured, but using a shared secret that can be stored for the user/pc combination
 
.PARAMETER Addresses
    This is a set of addresses to run the command on, The firewalls must have the same master key for this to work
 
.PARAMETER Credential
    This is a user account to just use
 
.PARAMETER Tag
    This is the shortname to use to reference auth information and addresses
 
.PARAMETER Path
   Path to the file to store data, check current directory, otherwise use profile directory
 
.EXAMPLE
    The example below get a Key from 192.0.2.1 and stores it in a group called AllEdge along with the three addresses associated
    PS C:\> Invoke-PANKeyGen -Tag 'AllEdge' -Addresses @('192.0.2.1','198.51.100.1','203.0.113.1')
 
.NOTES
    Author: Steve Borba https://github.com/sjborbajr/PAN-Power
    Last Edit: 2019-04-05
    Version 1.0 - initial release
    Version 1.0.1 - Updating descriptions and formatting
    Version 1.0.3 - update manditory fields
    Version 1.0.4 - Update to use HOME on linux
    Version 1.0.5 - Add SkipCertificateCheck for pwsh 6+
    Version 1.0.6 - added Edit config and commit and cert check skip for 5
 
#>


  [CmdletBinding()]
  Param (
    [Parameter(Mandatory=$False)][ValidateSet('API_Key','SecureAPI_Key')]
                                   [string]    $StorageMeathod = 'SecureAPI_Key',
    [Parameter(Mandatory=$False)]  [Switch]    $SkipCertificateCheck,
    [Parameter(Mandatory=$False)]  [string]    $Tag = '',
    [Parameter(Mandatory=$False)]  [string]    $Path = '',
    [Parameter(Mandatory=$true)]   [string[]]  $Addresses,
    [Parameter(Mandatory=$True)]   [System.Management.Automation.PSCredential]   $Credential
  )

  #Make sure the addresses variable is an array of strings
  If ($Addresses.GetType().Name -eq 'String') {$Addresses = @($Addresses)}

  #Get the Path if not supplied
  if ($Path -eq '') {
    if (Test-Path "panrc.xml") {
      $Path = "panrc.xml"
    } else {
      if ($env:USERPROFILE) {
        $Path = $env:USERPROFILE+"\panrc.xml"
      } elseif ($env:HOME) {
        $Path = $env:HOME+"\panrc.xml"
      } else {
        $Path = (pwd).path+"\panrc.xml"
      }
    }
  }

  #Get the key
  $HashArguments = @{
    URI = "https://"+$Addresses[0]+"/api/?type=keygen&user="+[uri]::EscapeDataString($Credential.username)+"&password="+[uri]::EscapeDataString($Credential.GetNetworkCredential().password)
  }
    If ($SkipCertificateCheck) {
      If ($Host.Version.Major -ge 6) {
        $HashArguments += @{SkipCertificateCheck = $True}
      } else { Ignore-CertificateValidation }
    }
  $Response = Invoke-RestMethod @HashArguments
  if ( $Response.response.status -eq 'success' ) {
    $API_Key = $Response.response.result.key

    #Format
    Switch ($StorageMeathod){
      'API_Key' {
        $Data = @{$Tag = @{Type = 'API_Key'; Addresses=$Addresses; API_Key=$API_Key; TimeStamp=(Get-Date)}}
      }
      'SecureAPI_Key' {
        If ($env:COMPUTERNAME) {$ComputerName=$env:COMPUTERNAME} elseif ($env:HOSTNAME) {$ComputerName=$env:HOSTNAME} else {$ComputerName=''}
        $Data = @{$Tag = @{Type = 'SecureAPI_Key'; Addresses=$Addresses; API_Key=(New-Object System.Management.Automation.PSCredential -ArgumentList 'API_Key', ($API_Key | ConvertTo-SecureString -AsPlainText -Force)); TimeStamp=(Get-Date); Combo=@{USERNAME=$env:USERNAME;COMPUTERNAME=$ComputerName}}}
      }
      'SharedSecureAPI_Key' {
        #not implemented - notes on how I can do it
        #$plainText = "Some Super Secret Password"
        #$key = Set-Key "AGoodKeyThatNoOneElseWillKnow"
        #$encryptedTextThatIcouldSaveToFile = Set-EncryptedData -key $key -plainText $plaintext
        #$encryptedTextThatIcouldSaveToFile
        #507964ed3a197b26969adead0212743c378a478c64007c477efbb21be5748670a7543cb21135ec324e37f80f66d17c76c4a75f6783de126658bce09ef19d50da
        #$DecryptedText = Get-EncryptedData -data $encryptedTextThatIcouldSaveToFile -key $key
        #$DecryptedText
        #Some Super Secret Password
      }
    }

    #Store - Check to see if xml exists, then if entry exists, and create, replace, or add as appropriate
    If (Test-Path $Path) {
      $FileData = Import-Clixml $Path
      If ($FileData.Tags) {
        If ($FileData.Tags[$Tag]) {
          #remove to allow replace
          $FileData.Tags.Remove($Tag)
        }
        $FileData.Tags = $FileData.Tags + $Data
      } else {
        $FileData = $FileData + @{Tags=$Data}
      }
    } else {
      $FileData = @{Tags=$Data}
    }
    $FileData | Export-Clixml $Path
    $Response.response.status
    Return
  } else {
    $Response.response
    Return
  }
}