|
| 1 | +function Invoke-CippTestZTNA21992 { |
| 2 | + param($Tenant) |
| 3 | + |
| 4 | + try { |
| 5 | + $Apps = New-CIPPDbRequest -TenantFilter $Tenant -Type 'Apps' |
| 6 | + $ServicePrincipals = New-CIPPDbRequest -TenantFilter $Tenant -Type 'ServicePrincipals' |
| 7 | + |
| 8 | + if (-not $Apps -and -not $ServicePrincipals) { |
| 9 | + Add-CippTestResult -TenantFilter $Tenant -TestId 'ZTNA21992' -TestType 'Identity' -Status 'Investigate' -ResultMarkdown 'Application and service principal data not found in database' -Risk 'High' -Name 'Application certificates must be rotated on a regular basis' -UserImpact 'Low' -ImplementationEffort 'High' -Category 'Application management' |
| 10 | + return |
| 11 | + } |
| 12 | + |
| 13 | + $RotationThresholdDays = 180 |
| 14 | + $ThresholdDate = (Get-Date).AddDays(-$RotationThresholdDays) |
| 15 | + |
| 16 | + $OldAppCerts = @() |
| 17 | + if ($Apps) { |
| 18 | + $OldAppCerts = $Apps | Where-Object { |
| 19 | + $_.keyCredentials -and $_.keyCredentials.Count -gt 0 |
| 20 | + } | ForEach-Object { |
| 21 | + $App = $_ |
| 22 | + $OldestCert = $App.keyCredentials | Where-Object { $_.startDateTime } | ForEach-Object { |
| 23 | + [DateTime]$_.startDateTime |
| 24 | + } | Sort-Object | Select-Object -First 1 |
| 25 | + |
| 26 | + if ($OldestCert -and $OldestCert -lt $ThresholdDate) { |
| 27 | + [PSCustomObject]@{ |
| 28 | + Type = 'Application' |
| 29 | + DisplayName = $App.displayName |
| 30 | + AppId = $App.appId |
| 31 | + Id = $App.id |
| 32 | + OldestCertDate = $OldestCert |
| 33 | + } |
| 34 | + } |
| 35 | + } |
| 36 | + } |
| 37 | + |
| 38 | + $OldSPCerts = @() |
| 39 | + if ($ServicePrincipals) { |
| 40 | + $OldSPCerts = $ServicePrincipals | Where-Object { |
| 41 | + $_.keyCredentials -and $_.keyCredentials.Count -gt 0 |
| 42 | + } | ForEach-Object { |
| 43 | + $SP = $_ |
| 44 | + $OldestCert = $SP.keyCredentials | Where-Object { $_.startDateTime } | ForEach-Object { |
| 45 | + [DateTime]$_.startDateTime |
| 46 | + } | Sort-Object | Select-Object -First 1 |
| 47 | + |
| 48 | + if ($OldestCert -and $OldestCert -lt $ThresholdDate) { |
| 49 | + [PSCustomObject]@{ |
| 50 | + Type = 'ServicePrincipal' |
| 51 | + DisplayName = $SP.displayName |
| 52 | + AppId = $SP.appId |
| 53 | + Id = $SP.id |
| 54 | + OldestCertDate = $OldestCert |
| 55 | + } |
| 56 | + } |
| 57 | + } |
| 58 | + } |
| 59 | + |
| 60 | + if ($OldAppCerts.Count -eq 0 -and $OldSPCerts.Count -eq 0) { |
| 61 | + Add-CippTestResult -TenantFilter $Tenant -TestId 'ZTNA21992' -TestType 'Identity' -Status 'Passed' -ResultMarkdown "Certificates for applications in your tenant have been issued within $RotationThresholdDays days" -Risk 'High' -Name 'Application certificates must be rotated on a regular basis' -UserImpact 'Low' -ImplementationEffort 'High' -Category 'Application management' |
| 62 | + return |
| 63 | + } |
| 64 | + |
| 65 | + $Status = 'Failed' |
| 66 | + |
| 67 | + $ResultLines = @( |
| 68 | + "Found $($OldAppCerts.Count) application(s) and $($OldSPCerts.Count) service principal(s) with certificates not rotated within $RotationThresholdDays days." |
| 69 | + '' |
| 70 | + "**Certificate rotation threshold:** $RotationThresholdDays days" |
| 71 | + '' |
| 72 | + ) |
| 73 | + |
| 74 | + if ($OldAppCerts.Count -gt 0) { |
| 75 | + $ResultLines += '**Applications with old certificates:**' |
| 76 | + $Top10Apps = $OldAppCerts | Select-Object -First 10 |
| 77 | + foreach ($App in $Top10Apps) { |
| 78 | + $DaysOld = [Math]::Round(((Get-Date) - $App.OldestCertDate).TotalDays, 0) |
| 79 | + $ResultLines += "- $($App.DisplayName) (Certificate age: $DaysOld days)" |
| 80 | + } |
| 81 | + if ($OldAppCerts.Count -gt 10) { |
| 82 | + $ResultLines += "- ... and $($OldAppCerts.Count - 10) more application(s)" |
| 83 | + } |
| 84 | + $ResultLines += '' |
| 85 | + } |
| 86 | + |
| 87 | + if ($OldSPCerts.Count -gt 0) { |
| 88 | + $ResultLines += '**Service principals with old certificates:**' |
| 89 | + $Top10SPs = $OldSPCerts | Select-Object -First 10 |
| 90 | + foreach ($SP in $Top10SPs) { |
| 91 | + $DaysOld = [Math]::Round(((Get-Date) - $SP.OldestCertDate).TotalDays, 0) |
| 92 | + $ResultLines += "- $($SP.DisplayName) (Certificate age: $DaysOld days)" |
| 93 | + } |
| 94 | + if ($OldSPCerts.Count -gt 10) { |
| 95 | + $ResultLines += "- ... and $($OldSPCerts.Count - 10) more service principal(s)" |
| 96 | + } |
| 97 | + $ResultLines += '' |
| 98 | + } |
| 99 | + |
| 100 | + $ResultLines += '**Recommendation:** Rotate certificates regularly to reduce the risk of credential compromise.' |
| 101 | + |
| 102 | + $Result = $ResultLines -join "`n" |
| 103 | + |
| 104 | + Add-CippTestResult -TenantFilter $Tenant -TestId 'ZTNA21992' -TestType 'Identity' -Status $Status -ResultMarkdown $Result -Risk 'High' -Name 'Application certificates must be rotated on a regular basis' -UserImpact 'Low' -ImplementationEffort 'High' -Category 'Application management' |
| 105 | + } catch { |
| 106 | + $ErrorMessage = Get-CippException -Exception $_ |
| 107 | + Write-LogMessage -API 'Tests' -tenant $Tenant -message "Failed to run test: $($ErrorMessage.NormalizedError)" -sev Error -LogData $ErrorMessage |
| 108 | + Add-CippTestResult -TenantFilter $Tenant -TestId 'ZTNA21992' -TestType 'Identity' -Status 'Failed' -ResultMarkdown "Test failed: $($ErrorMessage.NormalizedError)" -Risk 'High' -Name 'Application certificates must be rotated on a regular basis' -UserImpact 'Low' -ImplementationEffort 'High' -Category 'Application management' |
| 109 | + } |
| 110 | +} |
0 commit comments