Skip to content

Commit

Permalink
Merge 46518b8 into 9d21b2c
Browse files Browse the repository at this point in the history
  • Loading branch information
bhillkeyfactor authored Dec 6, 2024
2 parents 9d21b2c + 46518b8 commit ee1762b
Show file tree
Hide file tree
Showing 22 changed files with 324 additions and 96 deletions.
5 changes: 5 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,3 +1,8 @@
2.3.0
* Added support for Template Only Commits
* Added support for Template Stack Commits
* Added support for ingoring Trusted Default Certs on inventory to speed up the inventory job

2.2.1
* Fixed URL Encoding on Palo Username and Pwd that caused invalid credentials error

Expand Down
4 changes: 2 additions & 2 deletions PaloAlto.sln
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@

Microsoft Visual Studio Solution File, Format Version 12.00
# Visual Studio Version 16
VisualStudioVersion = 16.0.30717.126
# Visual Studio Version 17
VisualStudioVersion = 17.11.35222.181
MinimumVisualStudioVersion = 10.0.40219.1
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "PaloAlto", "PaloAlto\PaloAlto.csproj", "{33FBC5A1-3466-4F10-B9A6-7186F804A65A}"
EndProject
Expand Down
41 changes: 37 additions & 4 deletions PaloAlto/Client/PaloAltoClient.cs
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@
using System.Net.Http.Headers;
using System.Reflection;
using System.Text.RegularExpressions;
using System.Threading;
using System.Threading.Tasks;
using System.Xml;
using System.Xml.Serialization;
Expand Down Expand Up @@ -99,6 +100,22 @@ public async Task<NamedListResponse> GetDeviceGroupList()
_logger.LogError($"Error Occured in PaloAltoClient.GetDeviceGroupList: {e.Message}");
throw;
}
}

public async Task<NamedListResponse> GetTemplateStackList()
{
try
{
var uri =
$"/api/?type=config&action=get&xpath=/config/devices/entry[@name='localhost.localdomain']/template-stack/entry/@name&key={ApiKey}";
var response = await GetXmlResponseAsync<NamedListResponse>(await HttpClient.GetAsync(uri));
return response;
}
catch (Exception e)
{
_logger.LogError($"Error Occured in PaloAltoClient.GetDeviceGroupList: {e.Message}");
throw;
}
}

public async Task<CommitResponse> GetCommitResponse()
Expand All @@ -118,15 +135,31 @@ public async Task<CommitResponse> GetCommitResponse()
}
}

public async Task<CommitResponse> GetCommitAllResponse(string deviceGroup)
public async Task<CommitResponse> GetCommitAllResponse(string deviceGroup,string storePath,string templateStack)
{
try
{
//Palo alto claims this commented out line works for push to devices by userid but can't get this to work
//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}";
var uri =
$"/api/?&type=commit&action=all&cmd=<commit-all><shared-policy><device-group><entry name=\"{deviceGroup}\"/></device-group></shared-policy></commit-all>&key={ApiKey}";
var response = await GetXmlResponseAsync<CommitResponse>(await HttpClient.GetAsync(uri));
var uri = string.Empty;
if (!String.IsNullOrEmpty(deviceGroup))
{
uri =
$"/api/?&type=commit&action=all&cmd=<commit-all><shared-policy><device-group><entry name=\"{deviceGroup}\"/></device-group></shared-policy></commit-all>&key={ApiKey}";
}
else
{
uri =$"/api/?&type=commit&action=all&cmd=<commit-all><template><name>{GetTemplateName(storePath)}</name></template></commit-all>&key={ApiKey}";
}

var response = await GetXmlResponseAsync<CommitResponse>(await HttpClient.GetAsync(uri));

if (!String.IsNullOrEmpty(templateStack))
{
uri = $"/api/?&type=commit&action=all&cmd=<commit-all><template-stack><name>{templateStack}</name></template-stack></commit-all>&key={ApiKey}";
Thread.Sleep(60000); //Some delay built in so pushes to devices work
response = await GetXmlResponseAsync<CommitResponse>(await HttpClient.GetAsync(uri));
}
return response;
}
catch (Exception e)
Expand Down
6 changes: 6 additions & 0 deletions PaloAlto/JobProperties.cs
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,12 @@ public class JobProperties
[DefaultValue("")]
public string DeviceGroup { get; set; }

[JsonProperty("TemplateStack")]
[DefaultValue("")]
public string TemplateStack { get; set; }

[JsonProperty("InventoryTrustedCerts")]
[DefaultValue(false)]
public bool InventoryTrustedCerts { get; set; }
}
}
45 changes: 23 additions & 22 deletions PaloAlto/Jobs/Inventory.cs
Original file line number Diff line number Diff line change
Expand Up @@ -127,28 +127,29 @@ private JobResult PerformInventory(InventoryJobConfiguration config, SubmitInven
}
}).Where(acsii => acsii?.Certificates != null).ToList());


foreach (var trustedRootCert in trustedRootPayload.TrustedRootResult.TrustedRootCa.Entry)
try
{
_logger.LogTrace($"Building Trusted Root Inventory Item Alias: {trustedRootCert.Name}");
var certificatePem = client.GetCertificateByName(trustedRootCert.Name);
_logger.LogTrace($"Certificate String Back From Palo Pem: {certificatePem.Result}");
var bytes = Encoding.ASCII.GetBytes(certificatePem.Result);
var cert = new X509Certificate2(bytes);
_logger.LogTrace(
$"Building Trusted Root Inventory Item Pem: {certificatePem.Result} Has Private Key: {cert.HasPrivateKey}");
inventoryItems.Add(BuildInventoryItem(trustedRootCert.Name, certificatePem.Result, cert.HasPrivateKey, true));
}
catch(Exception e)
{
_logger.LogWarning(
$"Could not fetch the certificate: {trustedRootCert.Name} associated with issuer {trustedRootCert.Issuer} error {LogHandler.FlattenException(e)}.");
sb.Append(
$"Could not fetch the certificate: {trustedRootCert.Name} associated with issuer {trustedRootCert.Issuer}.{Environment.NewLine}");
warningFlag = true;
}

if (StoreProperties.InventoryTrustedCerts)
{
foreach (var trustedRootCert in trustedRootPayload.TrustedRootResult.TrustedRootCa.Entry)
try
{
_logger.LogTrace($"Building Trusted Root Inventory Item Alias: {trustedRootCert.Name}");
var certificatePem = client.GetCertificateByName(trustedRootCert.Name);
_logger.LogTrace($"Certificate String Back From Palo Pem: {certificatePem.Result}");
var bytes = Encoding.ASCII.GetBytes(certificatePem.Result);
var cert = new X509Certificate2(bytes);
_logger.LogTrace(
$"Building Trusted Root Inventory Item Pem: {certificatePem.Result} Has Private Key: {cert.HasPrivateKey}");
inventoryItems.Add(BuildInventoryItem(trustedRootCert.Name, certificatePem.Result, cert.HasPrivateKey, true));
}
catch (Exception e)
{
_logger.LogWarning(
$"Could not fetch the certificate: {trustedRootCert.Name} associated with issuer {trustedRootCert.Issuer} error {LogHandler.FlattenException(e)}.");
sb.Append(
$"Could not fetch the certificate: {trustedRootCert.Name} associated with issuer {trustedRootCert.Issuer}.{Environment.NewLine}");
warningFlag = true;
}
}
_logger.LogTrace("Submitting Inventory To Keyfactor via submitInventory.Invoke");
submitInventory.Invoke(inventoryItems);
_logger.LogTrace("Submitted Inventory To Keyfactor via submitInventory.Invoke");
Expand Down
7 changes: 5 additions & 2 deletions PaloAlto/Jobs/Management.cs
Original file line number Diff line number Diff line change
Expand Up @@ -615,13 +615,16 @@ private string CommitChanges(ManagementJobConfiguration config, PaloAltoClient c
var deviceGroup = StoreProperties?.DeviceGroup;
_logger.LogTrace($"Device Group {deviceGroup}");

var templateStack = StoreProperties?.TemplateStack;
_logger.LogTrace($"Template Stack {templateStack}");

//If there is a template and device group then push to all firewall devices because it is Panorama
if (IsPanoramaDevice(config) && deviceGroup?.Length > 0)
if (Validators.IsValidPanoramaVsysFormat(config.CertificateStoreDetails.StorePath) || Validators.IsValidPanoramaFormat(config.CertificateStoreDetails.StorePath))
{
_logger.LogTrace("It is a panorama device, build some delay in there so it works, pan issue.");
Thread.Sleep(120000); //Some delay built in so pushes to devices work
_logger.LogTrace("Done sleeping");
var commitAllResponse = client.GetCommitAllResponse(deviceGroup).Result;
var commitAllResponse = client.GetCommitAllResponse(deviceGroup,config.CertificateStoreDetails.StorePath,templateStack).Result;
_logger.LogTrace("Logging commit response from panorama.");
LogResponse(commitAllResponse);
if (commitAllResponse.Status != "success")
Expand Down
32 changes: 24 additions & 8 deletions PaloAlto/Validators.cs
Original file line number Diff line number Diff line change
Expand Up @@ -50,14 +50,14 @@ private static string GetTemplateName(string storePath)
return templateName;
}

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

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

// If it is a firewall (store path of /) then you don't need the Group Name
if (!storePath.Contains("template",System.StringComparison.CurrentCultureIgnoreCase))
if (!storePath.Contains("template", System.StringComparison.CurrentCultureIgnoreCase))
{
if (!string.IsNullOrEmpty(storeProperties?.DeviceGroup))
{
errors +=
"You do not need a device group with a Palo Alto Firewall. It is only required for Panorama.";
}
}
if (!string.IsNullOrEmpty(storeProperties?.TemplateStack))
{
errors +=
"You do not need a Template Stack with a Palo Alto Firewall. It is only required for Panorama.";
}
}


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

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

if (!string.IsNullOrEmpty(storeProperties?.DeviceGroup))
{
Expand All @@ -105,8 +109,20 @@ public static (bool valid, JobResult result) ValidateStoreProperties(JobProperti
errors +=
$"Could not find your Device Group In Panorama. Valid Device Groups are {string.Join(",", deviceList.Result.Result.Entry.Select(d => d.Name))}";
}
}

if (!string.IsNullOrEmpty(storeProperties?.TemplateStack))
{
var templateStackList = client.GetTemplateStackList();
var templateStacks = templateStackList.Result.Result.Entry.Where(d => d.Name == storeProperties?.TemplateStack);
if (!templateStacks.Any())
{
errors +=
$"Could not find your Template Stacks In Panorama. Valid Device Groups are {string.Join(",", templateStackList.Result.Result.Entry.Select(d => d.Name))}";
}
}


//Validate Template Exists in Panorama, required for Panorama
var templateList = client.GetTemplateList();
var templates = templateList.Result.Result.Entry.Where(d => d.Name == GetTemplateName(storePath));
Expand Down
2 changes: 1 addition & 1 deletion PaloAltoTestConsole/FirewallInventory.json
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@
"ClientMachine": "ClientMachineGoesHere",
"StorePath": "/",
"StorePassword": "",
"Properties": "{\"ServerUsername\":\"UserNameGoesHere\",\"ServerPassword\":\"PasswordGoesHere\",\"ServerUseSsl\":\"true\",\"DeviceGroup\":\"\"}",
"Properties": "{\"ServerUsername\":\"UserNameGoesHere\",\"ServerPassword\":\"PasswordGoesHere\",\"ServerUseSsl\":\"true\",\"DeviceGroup\":\"\",\"InventoryTrustedCerts\": false,\"TemplateStack\":\"TemplateStackGoesHere\"}",
"Type": 105
},
"JobCancelled": false,
Expand Down
2 changes: 1 addition & 1 deletion PaloAltoTestConsole/KeyfactorClient.cs
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,7 @@ public async Task<KeyfactorEnrollmentResult> EnrollCertificate(string commonName
var request = new RestRequest("/KeyfactorAPI/Enrollment/PFX", Method.Post);
request.AddHeader("X-Keyfactor-Requested-With", "APIClient");
request.AddHeader("x-certificateformat", "PFX");
request.AddHeader("Authorization", "Basic Q29tbWFuZFxLRkFkbWluOldoNUcyVGM2VkJZalNNcEM=");
request.AddHeader("Authorization", "Basic Authtoken");
request.AddHeader("Content-Type", "application/json");
var enrollRequest = new KeyfactorEnrollmentRequest
{
Expand Down
2 changes: 1 addition & 1 deletion PaloAltoTestConsole/ManagementRemove.json
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@
"ClientMachine": "ClientMachineGoesHere",
"StorePath": "TemplateNameGoesHere",
"StorePassword": null,
"Properties": "{\"ServerUsername\":\"UserNameGoesHere\",\"ServerPassword\":\"PasswordGoesHere\",\"ServerUseSsl\":\"true\",\"DeviceGroup\":\"DeviceGroupGoesHere\"}",
"Properties": "{\"ServerUsername\":\"UserNameGoesHere\",\"ServerPassword\":\"PasswordGoesHere\",\"ServerUseSsl\":\"true\",\"DeviceGroup\":\"DeviceGroupGoesHere\",\"InventoryTrustedCerts\": false,\"TemplateStack\":\"TemplateStackGoesHere\"}",
"Type": 105
},
"OperationType": 3,
Expand Down
2 changes: 1 addition & 1 deletion PaloAltoTestConsole/PanoramaInventory.json
Original file line number Diff line number Diff line change
Expand Up @@ -243,7 +243,7 @@
"ClientMachine": "ClientMachineGoesHere",
"StorePath": "TemplateNameGoesHere",
"StorePassword": "",
"Properties": "{\"ServerUsername\":\"UserNameGoesHere\",\"ServerPassword\":\"PasswordGoesHere\",\"ServerUseSsl\":\"true\",\"DeviceGroup\":\"DeviceGroupGoesHere\"}",
"Properties": "{\"ServerUsername\":\"UserNameGoesHere\",\"ServerPassword\":\"PasswordGoesHere\",\"ServerUseSsl\":\"true\",\"DeviceGroup\":\"DeviceGroupGoesHere\",\"InventoryTrustedCerts\": false,\"TemplateStack\":\"TemplateStackGoesHere\"}",
"Type": 105
},
"JobCancelled": false,
Expand Down
2 changes: 1 addition & 1 deletion PaloAltoTestConsole/PanoramaMgmt.json
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@
"ClientMachine": "ClientMachineGoesHere",
"StorePath": "TemplateNameGoesHere",
"StorePassword": null,
"Properties": "{\"ServerUsername\":\"UserNameGoesHere\",\"ServerPassword\":\"PasswordGoesHere\",\"ServerUseSsl\":\"true\",\"DeviceGroup\":\"DeviceGroupGoesHere\"}",
"Properties": "{\"ServerUsername\":\"UserNameGoesHere\",\"ServerPassword\":\"PasswordGoesHere\",\"ServerUseSsl\":\"true\",\"DeviceGroup\":\"DeviceGroupGoesHere\",\"InventoryTrustedCerts\": false,\"TemplateStack\":\"TemplateStackGoesHere\"}",
"Type": 105
},
"OperationType": 2,
Expand Down
Loading

0 comments on commit ee1762b

Please sign in to comment.