Skip to content

Commit b60da20

Browse files
Merge 47b4a32 into 9d21b2c
2 parents 9d21b2c + 47b4a32 commit b60da20

22 files changed

Lines changed: 320 additions & 92 deletions

CHANGELOG.md

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,8 @@
1+
2.3.0
2+
* Added support for Template Only Commits
3+
* Added support for Template Stack Commits
4+
* Added support for ingoring Trusted Default Certs on inventory to speed up the inventory job
5+
16
2.2.1
27
* Fixed URL Encoding on Palo Username and Pwd that caused invalid credentials error
38

PaloAlto.sln

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11

22
Microsoft Visual Studio Solution File, Format Version 12.00
3-
# Visual Studio Version 16
4-
VisualStudioVersion = 16.0.30717.126
3+
# Visual Studio Version 17
4+
VisualStudioVersion = 17.11.35222.181
55
MinimumVisualStudioVersion = 10.0.40219.1
66
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "PaloAlto", "PaloAlto\PaloAlto.csproj", "{33FBC5A1-3466-4F10-B9A6-7186F804A65A}"
77
EndProject

PaloAlto/Client/PaloAltoClient.cs

Lines changed: 37 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@
1818
using System.Net.Http.Headers;
1919
using System.Reflection;
2020
using System.Text.RegularExpressions;
21+
using System.Threading;
2122
using System.Threading.Tasks;
2223
using System.Xml;
2324
using System.Xml.Serialization;
@@ -99,6 +100,22 @@ public async Task<NamedListResponse> GetDeviceGroupList()
99100
_logger.LogError($"Error Occured in PaloAltoClient.GetDeviceGroupList: {e.Message}");
100101
throw;
101102
}
103+
}
104+
105+
public async Task<NamedListResponse> GetTemplateStackList()
106+
{
107+
try
108+
{
109+
var uri =
110+
$"/api/?type=config&action=get&xpath=/config/devices/entry[@name='localhost.localdomain']/template-stack/entry/@name&key={ApiKey}";
111+
var response = await GetXmlResponseAsync<NamedListResponse>(await HttpClient.GetAsync(uri));
112+
return response;
113+
}
114+
catch (Exception e)
115+
{
116+
_logger.LogError($"Error Occured in PaloAltoClient.GetDeviceGroupList: {e.Message}");
117+
throw;
118+
}
102119
}
103120

104121
public async Task<CommitResponse> GetCommitResponse()
@@ -118,15 +135,31 @@ public async Task<CommitResponse> GetCommitResponse()
118135
}
119136
}
120137

121-
public async Task<CommitResponse> GetCommitAllResponse(string deviceGroup)
138+
public async Task<CommitResponse> GetCommitAllResponse(string deviceGroup,string storePath,string templateStack)
122139
{
123140
try
124141
{
125142
//Palo alto claims this commented out line works for push to devices by userid but can't get this to work
126143
//var uri = $"/api/?&type=commit&action=all&cmd=<commit-all><shared-policy><admin><member>{ServerUserName}</member></admin><device-group><entry name=\"{deviceGroup}\"/></device-group></shared-policy></commit-all>&key={ApiKey}";
127-
var uri =
128-
$"/api/?&type=commit&action=all&cmd=<commit-all><shared-policy><device-group><entry name=\"{deviceGroup}\"/></device-group></shared-policy></commit-all>&key={ApiKey}";
129-
var response = await GetXmlResponseAsync<CommitResponse>(await HttpClient.GetAsync(uri));
144+
var uri = string.Empty;
145+
if (!String.IsNullOrEmpty(deviceGroup))
146+
{
147+
uri =
148+
$"/api/?&type=commit&action=all&cmd=<commit-all><shared-policy><device-group><entry name=\"{deviceGroup}\"/></device-group></shared-policy></commit-all>&key={ApiKey}";
149+
}
150+
else
151+
{
152+
uri =$"/api/?&type=commit&action=all&cmd=<commit-all><template><name>{GetTemplateName(storePath)}</name></template></commit-all>&key={ApiKey}";
153+
}
154+
155+
var response = await GetXmlResponseAsync<CommitResponse>(await HttpClient.GetAsync(uri));
156+
157+
if (!String.IsNullOrEmpty(templateStack))
158+
{
159+
uri = $"/api/?&type=commit&action=all&cmd=<commit-all><template-stack><name>{templateStack}</name></template-stack></commit-all>&key={ApiKey}";
160+
Thread.Sleep(60000); //Some delay built in so pushes to devices work
161+
response = await GetXmlResponseAsync<CommitResponse>(await HttpClient.GetAsync(uri));
162+
}
130163
return response;
131164
}
132165
catch (Exception e)

PaloAlto/JobProperties.cs

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,12 @@ public class JobProperties
2323
[DefaultValue("")]
2424
public string DeviceGroup { get; set; }
2525

26+
[JsonProperty("TemplateStack")]
27+
[DefaultValue("")]
28+
public string TemplateStack { get; set; }
2629

30+
[JsonProperty("InventoryTrustedCerts")]
31+
[DefaultValue(false)]
32+
public bool InventoryTrustedCerts { get; set; }
2733
}
2834
}

PaloAlto/Jobs/Inventory.cs

Lines changed: 23 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -127,28 +127,29 @@ private JobResult PerformInventory(InventoryJobConfiguration config, SubmitInven
127127
}
128128
}).Where(acsii => acsii?.Certificates != null).ToList());
129129

130-
131-
foreach (var trustedRootCert in trustedRootPayload.TrustedRootResult.TrustedRootCa.Entry)
132-
try
133-
{
134-
_logger.LogTrace($"Building Trusted Root Inventory Item Alias: {trustedRootCert.Name}");
135-
var certificatePem = client.GetCertificateByName(trustedRootCert.Name);
136-
_logger.LogTrace($"Certificate String Back From Palo Pem: {certificatePem.Result}");
137-
var bytes = Encoding.ASCII.GetBytes(certificatePem.Result);
138-
var cert = new X509Certificate2(bytes);
139-
_logger.LogTrace(
140-
$"Building Trusted Root Inventory Item Pem: {certificatePem.Result} Has Private Key: {cert.HasPrivateKey}");
141-
inventoryItems.Add(BuildInventoryItem(trustedRootCert.Name, certificatePem.Result, cert.HasPrivateKey, true));
142-
}
143-
catch(Exception e)
144-
{
145-
_logger.LogWarning(
146-
$"Could not fetch the certificate: {trustedRootCert.Name} associated with issuer {trustedRootCert.Issuer} error {LogHandler.FlattenException(e)}.");
147-
sb.Append(
148-
$"Could not fetch the certificate: {trustedRootCert.Name} associated with issuer {trustedRootCert.Issuer}.{Environment.NewLine}");
149-
warningFlag = true;
150-
}
151-
130+
if (StoreProperties.InventoryTrustedCerts)
131+
{
132+
foreach (var trustedRootCert in trustedRootPayload.TrustedRootResult.TrustedRootCa.Entry)
133+
try
134+
{
135+
_logger.LogTrace($"Building Trusted Root Inventory Item Alias: {trustedRootCert.Name}");
136+
var certificatePem = client.GetCertificateByName(trustedRootCert.Name);
137+
_logger.LogTrace($"Certificate String Back From Palo Pem: {certificatePem.Result}");
138+
var bytes = Encoding.ASCII.GetBytes(certificatePem.Result);
139+
var cert = new X509Certificate2(bytes);
140+
_logger.LogTrace(
141+
$"Building Trusted Root Inventory Item Pem: {certificatePem.Result} Has Private Key: {cert.HasPrivateKey}");
142+
inventoryItems.Add(BuildInventoryItem(trustedRootCert.Name, certificatePem.Result, cert.HasPrivateKey, true));
143+
}
144+
catch (Exception e)
145+
{
146+
_logger.LogWarning(
147+
$"Could not fetch the certificate: {trustedRootCert.Name} associated with issuer {trustedRootCert.Issuer} error {LogHandler.FlattenException(e)}.");
148+
sb.Append(
149+
$"Could not fetch the certificate: {trustedRootCert.Name} associated with issuer {trustedRootCert.Issuer}.{Environment.NewLine}");
150+
warningFlag = true;
151+
}
152+
}
152153
_logger.LogTrace("Submitting Inventory To Keyfactor via submitInventory.Invoke");
153154
submitInventory.Invoke(inventoryItems);
154155
_logger.LogTrace("Submitted Inventory To Keyfactor via submitInventory.Invoke");

PaloAlto/Jobs/Management.cs

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -615,13 +615,16 @@ private string CommitChanges(ManagementJobConfiguration config, PaloAltoClient c
615615
var deviceGroup = StoreProperties?.DeviceGroup;
616616
_logger.LogTrace($"Device Group {deviceGroup}");
617617

618+
var templateStack = StoreProperties?.TemplateStack;
619+
_logger.LogTrace($"Template Stack {templateStack}");
620+
618621
//If there is a template and device group then push to all firewall devices because it is Panorama
619-
if (IsPanoramaDevice(config) && deviceGroup?.Length > 0)
622+
if (Validators.IsValidPanoramaVsysFormat(config.CertificateStoreDetails.StorePath) || Validators.IsValidPanoramaFormat(config.CertificateStoreDetails.StorePath))
620623
{
621624
_logger.LogTrace("It is a panorama device, build some delay in there so it works, pan issue.");
622625
Thread.Sleep(120000); //Some delay built in so pushes to devices work
623626
_logger.LogTrace("Done sleeping");
624-
var commitAllResponse = client.GetCommitAllResponse(deviceGroup).Result;
627+
var commitAllResponse = client.GetCommitAllResponse(deviceGroup,config.CertificateStoreDetails.StorePath,templateStack).Result;
625628
_logger.LogTrace("Logging commit response from panorama.");
626629
LogResponse(commitAllResponse);
627630
if (commitAllResponse.Status != "success")

PaloAlto/Validators.cs

Lines changed: 24 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -50,14 +50,14 @@ private static string GetTemplateName(string storePath)
5050
return templateName;
5151
}
5252

53-
static bool IsValidPanoramaFormat(string input)
53+
public static bool IsValidPanoramaFormat(string input)
5454
{
5555
string pattern = @"^/config/devices/entry\[@name='[^\]]+'\]/template/entry\[@name='[^']+'\]/config/shared$";
5656
Regex regex = new Regex(pattern);
5757
return regex.IsMatch(input);
5858
}
5959

60-
static bool IsValidFirewallVsysFormat(string input)
60+
public static bool IsValidFirewallVsysFormat(string input)
6161
{
6262
string pattern = @"^/config/devices/entry\[@name='localhost\.localdomain'\]/vsys/entry\[@name='[^']+'\]$";
6363
return Regex.IsMatch(input, pattern);
@@ -77,12 +77,20 @@ public static (bool valid, JobResult result) ValidateStoreProperties(JobProperti
7777
}
7878

7979
// If it is a firewall (store path of /) then you don't need the Group Name
80-
if (!storePath.Contains("template",System.StringComparison.CurrentCultureIgnoreCase))
80+
if (!storePath.Contains("template", System.StringComparison.CurrentCultureIgnoreCase))
81+
{
8182
if (!string.IsNullOrEmpty(storeProperties?.DeviceGroup))
8283
{
8384
errors +=
8485
"You do not need a device group with a Palo Alto Firewall. It is only required for Panorama.";
85-
}
86+
}
87+
if (!string.IsNullOrEmpty(storeProperties?.TemplateStack))
88+
{
89+
errors +=
90+
"You do not need a Template Stack with a Palo Alto Firewall. It is only required for Panorama.";
91+
}
92+
}
93+
8694

8795
// Considered Panorama device if store path is not "/" and there is a valid value for store path
8896
if (storePath.Contains("template", System.StringComparison.CurrentCultureIgnoreCase))
@@ -91,10 +99,6 @@ public static (bool valid, JobResult result) ValidateStoreProperties(JobProperti
9199
new PaloAltoClient(clientMachine,
92100
serverUserName, serverPassword); //Api base URL Plus Key
93101

94-
if (string.IsNullOrEmpty(storeProperties?.DeviceGroup))
95-
{
96-
errors += "You need to specify a device group when working with Panorama.";
97-
}
98102

99103
if (!string.IsNullOrEmpty(storeProperties?.DeviceGroup))
100104
{
@@ -105,8 +109,20 @@ public static (bool valid, JobResult result) ValidateStoreProperties(JobProperti
105109
errors +=
106110
$"Could not find your Device Group In Panorama. Valid Device Groups are {string.Join(",", deviceList.Result.Result.Entry.Select(d => d.Name))}";
107111
}
112+
}
113+
114+
if (!string.IsNullOrEmpty(storeProperties?.TemplateStack))
115+
{
116+
var templateStackList = client.GetTemplateStackList();
117+
var templateStacks = templateStackList.Result.Result.Entry.Where(d => d.Name == storeProperties?.TemplateStack);
118+
if (!templateStacks.Any())
119+
{
120+
errors +=
121+
$"Could not find your Template Stacks In Panorama. Valid Device Groups are {string.Join(",", templateStackList.Result.Result.Entry.Select(d => d.Name))}";
122+
}
108123
}
109124

125+
110126
//Validate Template Exists in Panorama, required for Panorama
111127
var templateList = client.GetTemplateList();
112128
var templates = templateList.Result.Result.Entry.Where(d => d.Name == GetTemplateName(storePath));

PaloAltoTestConsole/FirewallInventory.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@
44
"ClientMachine": "ClientMachineGoesHere",
55
"StorePath": "/",
66
"StorePassword": "",
7-
"Properties": "{\"ServerUsername\":\"UserNameGoesHere\",\"ServerPassword\":\"PasswordGoesHere\",\"ServerUseSsl\":\"true\",\"DeviceGroup\":\"\"}",
7+
"Properties": "{\"ServerUsername\":\"UserNameGoesHere\",\"ServerPassword\":\"PasswordGoesHere\",\"ServerUseSsl\":\"true\",\"DeviceGroup\":\"\",\"InventoryTrustedCerts\": false,\"TemplateStack\":\"TemplateStackGoesHere\"}",
88
"Type": 105
99
},
1010
"JobCancelled": false,

PaloAltoTestConsole/KeyfactorClient.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -29,7 +29,7 @@ public async Task<KeyfactorEnrollmentResult> EnrollCertificate(string commonName
2929
var request = new RestRequest("/KeyfactorAPI/Enrollment/PFX", Method.Post);
3030
request.AddHeader("X-Keyfactor-Requested-With", "APIClient");
3131
request.AddHeader("x-certificateformat", "PFX");
32-
request.AddHeader("Authorization", "Basic Q29tbWFuZFxLRkFkbWluOldoNUcyVGM2VkJZalNNcEM=");
32+
request.AddHeader("Authorization", "Basic Authtoken");
3333
request.AddHeader("Content-Type", "application/json");
3434
var enrollRequest = new KeyfactorEnrollmentRequest
3535
{

PaloAltoTestConsole/ManagementRemove.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@
44
"ClientMachine": "ClientMachineGoesHere",
55
"StorePath": "TemplateNameGoesHere",
66
"StorePassword": null,
7-
"Properties": "{\"ServerUsername\":\"UserNameGoesHere\",\"ServerPassword\":\"PasswordGoesHere\",\"ServerUseSsl\":\"true\",\"DeviceGroup\":\"DeviceGroupGoesHere\"}",
7+
"Properties": "{\"ServerUsername\":\"UserNameGoesHere\",\"ServerPassword\":\"PasswordGoesHere\",\"ServerUseSsl\":\"true\",\"DeviceGroup\":\"DeviceGroupGoesHere\",\"InventoryTrustedCerts\": false,\"TemplateStack\":\"TemplateStackGoesHere\"}",
88
"Type": 105
99
},
1010
"OperationType": 3,

0 commit comments

Comments
 (0)