mirror of
https://github.com/prowler-cloud/prowler.git
synced 2026-10-13 23:14:16 +00:00
fix(azure): stabilize deployment role assignments
This commit is contained in:
9 files changed
+41
-29
No files matched your search
@@ -62,3 +62,6 @@ jobs:
|
||||
env:
|
||||
pnpm_config_ignore_scripts: 'true'
|
||||
run: git ls-files -z '*.md' | xargs -0 -r pnpm dlx markdownlint-cli@0.45.0 --
|
||||
|
||||
- name: Check Azure ARM documentation assets
|
||||
run: python3 permissions/templates/azure/bicep/sync_docs_template.py --check
|
||||
@@ -5,7 +5,7 @@
|
||||
"_generator": {
|
||||
"name": "bicep",
|
||||
"version": "0.46.1.21595",
|
||||
"templateHash": "4092263301802395344"
|
||||
"templateHash": "16146816613430830317"
|
||||
}
|
||||
},
|
||||
"parameters": {
|
||||
@@ -19,7 +19,7 @@
|
||||
"type": "string",
|
||||
"defaultValue": "Prowler",
|
||||
"metadata": {
|
||||
"description": "Cosmetic label used inside the role assignment names so multiple deployments do not collide. Free text; keep the default unless you need to distinguish multiple Prowler deployments."
|
||||
"description": "Cosmetic label included in the custom role description. Free text; keep the default unless you need to distinguish multiple Prowler deployments."
|
||||
}
|
||||
},
|
||||
"customRoleName": {
|
||||
@@ -41,7 +41,7 @@
|
||||
"name": "[variables('customRoleDefinitionName')]",
|
||||
"properties": {
|
||||
"roleName": "[parameters('customRoleName')]",
|
||||
"description": "Role used by Prowler for checks that require Azure actions beyond the built-in Reader role.",
|
||||
"description": "[format('Role used by {0} for Prowler checks that require Azure actions beyond the built-in Reader role.', parameters('deploymentLabel'))]",
|
||||
"type": "CustomRole",
|
||||
"assignableScopes": [
|
||||
"[subscription().id]"
|
||||
@@ -62,7 +62,7 @@
|
||||
{
|
||||
"type": "Microsoft.Authorization/roleAssignments",
|
||||
"apiVersion": "2022-04-01",
|
||||
"name": "[guid(subscription().id, parameters('servicePrincipalObjectId'), parameters('deploymentLabel'), 'Reader')]",
|
||||
"name": "[guid(subscription().id, parameters('servicePrincipalObjectId'), variables('readerRoleDefinitionId'))]",
|
||||
"properties": {
|
||||
"principalId": "[parameters('servicePrincipalObjectId')]",
|
||||
"principalType": "ServicePrincipal",
|
||||
@@ -72,7 +72,7 @@
|
||||
{
|
||||
"type": "Microsoft.Authorization/roleAssignments",
|
||||
"apiVersion": "2022-04-01",
|
||||
"name": "[guid(subscription().id, parameters('servicePrincipalObjectId'), parameters('deploymentLabel'), parameters('customRoleName'))]",
|
||||
"name": "[guid(subscription().id, parameters('servicePrincipalObjectId'), subscriptionResourceId('Microsoft.Authorization/roleDefinitions', variables('customRoleDefinitionName')))]",
|
||||
"properties": {
|
||||
"principalId": "[parameters('servicePrincipalObjectId')]",
|
||||
"principalType": "ServicePrincipal",
|
||||
|
||||
@@ -8,7 +8,7 @@
|
||||
"_generator": {
|
||||
"name": "bicep",
|
||||
"version": "0.46.1.21595",
|
||||
"templateHash": "4092263301802395344"
|
||||
"templateHash": "16146816613430830317"
|
||||
}
|
||||
},
|
||||
"parameters": {
|
||||
@@ -22,7 +22,7 @@
|
||||
"type": "string",
|
||||
"defaultValue": "Prowler",
|
||||
"metadata": {
|
||||
"description": "Cosmetic label used inside the role assignment names so multiple deployments do not collide. Free text; keep the default unless you need to distinguish multiple Prowler deployments."
|
||||
"description": "Cosmetic label included in the custom role description. Free text; keep the default unless you need to distinguish multiple Prowler deployments."
|
||||
}
|
||||
},
|
||||
"customRoleName": {
|
||||
@@ -44,7 +44,7 @@
|
||||
"name": "[variables('customRoleDefinitionName')]",
|
||||
"properties": {
|
||||
"roleName": "[parameters('customRoleName')]",
|
||||
"description": "Role used by Prowler for checks that require Azure actions beyond the built-in Reader role.",
|
||||
"description": "[format('Role used by {0} for Prowler checks that require Azure actions beyond the built-in Reader role.', parameters('deploymentLabel'))]",
|
||||
"type": "CustomRole",
|
||||
"assignableScopes": [
|
||||
"[subscription().id]"
|
||||
@@ -65,7 +65,7 @@
|
||||
{
|
||||
"type": "Microsoft.Authorization/roleAssignments",
|
||||
"apiVersion": "2022-04-01",
|
||||
"name": "[guid(subscription().id, parameters('servicePrincipalObjectId'), parameters('deploymentLabel'), 'Reader')]",
|
||||
"name": "[guid(subscription().id, parameters('servicePrincipalObjectId'), variables('readerRoleDefinitionId'))]",
|
||||
"properties": {
|
||||
"principalId": "[parameters('servicePrincipalObjectId')]",
|
||||
"principalType": "ServicePrincipal",
|
||||
@@ -75,7 +75,7 @@
|
||||
{
|
||||
"type": "Microsoft.Authorization/roleAssignments",
|
||||
"apiVersion": "2022-04-01",
|
||||
"name": "[guid(subscription().id, parameters('servicePrincipalObjectId'), parameters('deploymentLabel'), parameters('customRoleName'))]",
|
||||
"name": "[guid(subscription().id, parameters('servicePrincipalObjectId'), subscriptionResourceId('Microsoft.Authorization/roleDefinitions', variables('customRoleDefinitionName')))]",
|
||||
"properties": {
|
||||
"principalId": "[parameters('servicePrincipalObjectId')]",
|
||||
"principalType": "ServicePrincipal",
|
||||
|
||||
@@ -267,7 +267,7 @@ $cert = New-SelfSignedCertificate -Subject "CN=Prowler" `
|
||||
|
||||
Export-Certificate -Cert $cert -FilePath prowler.cer
|
||||
|
||||
# Export a PKCS#12 bundle for Prowler. Keep this value secret.
|
||||
# Export an unencrypted PKCS#12/PFX bundle for Prowler. Keep this value secret.
|
||||
$pfxBytes = $cert.Export('Pfx', '')
|
||||
[Convert]::ToBase64String($pfxBytes)
|
||||
```
|
||||
@@ -311,7 +311,7 @@ Paste the following into the Certificate Authentication form of the Azure add-pr
|
||||
|
||||
- **Tenant ID** — copy the Directory (tenant) ID from the App Registration overview.
|
||||
- **Client ID** — copy the Application (client) ID from the App Registration overview.
|
||||
- **Certificate Content** — provide the base64-encoded **PEM bundle** (certificate + private key) or PKCS#12 export. Prowler needs both parts to sign the token request.
|
||||
- **Certificate Content** — provide the base64-encoded **PEM bundle** (certificate + private key) or an unencrypted PKCS#12/PFX export. Prowler needs both parts to sign the token request and does not accept password-protected PKCS#12/PFX input.
|
||||
|
||||
### Prowler CLI
|
||||
|
||||
@@ -325,7 +325,7 @@ export AZURE_CERTIFICATE_CONTENT="<base64-encoded certificate and private key bu
|
||||
prowler azure --certificate-auth
|
||||
```
|
||||
|
||||
Alternatively, provide a PEM or PKCS#12 file that contains both the certificate and matching private key:
|
||||
Alternatively, provide a PEM file or an unencrypted PKCS#12/PFX file that contains both the certificate and matching private key. Password-protected PKCS#12/PFX input is not supported:
|
||||
|
||||
```console
|
||||
prowler azure --certificate-auth --certificate-path /path/to/prowler-bundle.pem
|
||||
|
||||
@@ -156,8 +156,8 @@ $cert = New-SelfSignedCertificate -Subject "CN=Prowler" `
|
||||
# Save the .cer to upload in the Portal
|
||||
Export-Certificate -Cert $cert -FilePath prowler.cer
|
||||
|
||||
# Certificate and private key bundle (PKCS#12), base64-encoded — paste into
|
||||
# Prowler. Keep secret.
|
||||
# Unencrypted certificate and private key bundle (PKCS#12/PFX), base64-encoded
|
||||
# for Prowler. Password-protected PKCS#12/PFX input is not supported. Keep secret.
|
||||
$pfxBytes = $cert.Export('Pfx', '')
|
||||
$keyBase64 = [Convert]::ToBase64String($pfxBytes)
|
||||
|
||||
|
||||
@@ -38,7 +38,7 @@ targetScope = 'subscription'
|
||||
@description('Object ID of the Service Principal for the App Registration Prowler will use. Find it in Azure Portal → Microsoft Entra ID → Enterprise applications → your app → Overview → Object ID. This is NOT the same as the App Registration\'s Object ID; the Service Principal has its own separate Object ID.')
|
||||
param servicePrincipalObjectId string
|
||||
|
||||
@description('Cosmetic label used inside the role assignment names so multiple deployments do not collide. Free text; keep the default unless you need to distinguish multiple Prowler deployments.')
|
||||
@description('Cosmetic label included in the custom role description. Free text; keep the default unless you need to distinguish multiple Prowler deployments.')
|
||||
param deploymentLabel string = 'Prowler'
|
||||
|
||||
@description('Name of the extra role Prowler creates. Keep the default unless your org already uses this name.')
|
||||
@@ -60,7 +60,7 @@ resource prowlerRole 'Microsoft.Authorization/roleDefinitions@2022-05-01-preview
|
||||
name: customRoleDefinitionName
|
||||
properties: {
|
||||
roleName: customRoleName
|
||||
description: 'Role used by Prowler for checks that require Azure actions beyond the built-in Reader role.'
|
||||
description: 'Role used by ${deploymentLabel} for Prowler checks that require Azure actions beyond the built-in Reader role.'
|
||||
type: 'CustomRole'
|
||||
assignableScopes: [
|
||||
subscription().id
|
||||
@@ -80,7 +80,7 @@ resource prowlerRole 'Microsoft.Authorization/roleDefinitions@2022-05-01-preview
|
||||
}
|
||||
|
||||
resource readerAssignment 'Microsoft.Authorization/roleAssignments@2022-04-01' = {
|
||||
name: guid(subscription().id, servicePrincipalObjectId, deploymentLabel, 'Reader')
|
||||
name: guid(subscription().id, servicePrincipalObjectId, readerRoleDefinitionId)
|
||||
properties: {
|
||||
principalId: servicePrincipalObjectId
|
||||
principalType: 'ServicePrincipal'
|
||||
@@ -89,7 +89,7 @@ resource readerAssignment 'Microsoft.Authorization/roleAssignments@2022-04-01' =
|
||||
}
|
||||
|
||||
resource prowlerRoleAssignment 'Microsoft.Authorization/roleAssignments@2022-04-01' = {
|
||||
name: guid(subscription().id, servicePrincipalObjectId, deploymentLabel, customRoleName)
|
||||
name: guid(subscription().id, servicePrincipalObjectId, prowlerRole.id)
|
||||
properties: {
|
||||
principalId: servicePrincipalObjectId
|
||||
principalType: 'ServicePrincipal'
|
||||
|
||||
@@ -5,7 +5,7 @@
|
||||
"_generator": {
|
||||
"name": "bicep",
|
||||
"version": "0.46.1.21595",
|
||||
"templateHash": "4092263301802395344"
|
||||
"templateHash": "16146816613430830317"
|
||||
}
|
||||
},
|
||||
"parameters": {
|
||||
@@ -19,7 +19,7 @@
|
||||
"type": "string",
|
||||
"defaultValue": "Prowler",
|
||||
"metadata": {
|
||||
"description": "Cosmetic label used inside the role assignment names so multiple deployments do not collide. Free text; keep the default unless you need to distinguish multiple Prowler deployments."
|
||||
"description": "Cosmetic label included in the custom role description. Free text; keep the default unless you need to distinguish multiple Prowler deployments."
|
||||
}
|
||||
},
|
||||
"customRoleName": {
|
||||
@@ -41,7 +41,7 @@
|
||||
"name": "[variables('customRoleDefinitionName')]",
|
||||
"properties": {
|
||||
"roleName": "[parameters('customRoleName')]",
|
||||
"description": "Role used by Prowler for checks that require Azure actions beyond the built-in Reader role.",
|
||||
"description": "[format('Role used by {0} for Prowler checks that require Azure actions beyond the built-in Reader role.', parameters('deploymentLabel'))]",
|
||||
"type": "CustomRole",
|
||||
"assignableScopes": [
|
||||
"[subscription().id]"
|
||||
@@ -62,7 +62,7 @@
|
||||
{
|
||||
"type": "Microsoft.Authorization/roleAssignments",
|
||||
"apiVersion": "2022-04-01",
|
||||
"name": "[guid(subscription().id, parameters('servicePrincipalObjectId'), parameters('deploymentLabel'), 'Reader')]",
|
||||
"name": "[guid(subscription().id, parameters('servicePrincipalObjectId'), variables('readerRoleDefinitionId'))]",
|
||||
"properties": {
|
||||
"principalId": "[parameters('servicePrincipalObjectId')]",
|
||||
"principalType": "ServicePrincipal",
|
||||
@@ -72,7 +72,7 @@
|
||||
{
|
||||
"type": "Microsoft.Authorization/roleAssignments",
|
||||
"apiVersion": "2022-04-01",
|
||||
"name": "[guid(subscription().id, parameters('servicePrincipalObjectId'), parameters('deploymentLabel'), parameters('customRoleName'))]",
|
||||
"name": "[guid(subscription().id, parameters('servicePrincipalObjectId'), subscriptionResourceId('Microsoft.Authorization/roleDefinitions', variables('customRoleDefinitionName')))]",
|
||||
"properties": {
|
||||
"principalId": "[parameters('servicePrincipalObjectId')]",
|
||||
"principalType": "ServicePrincipal",
|
||||
|
||||
@@ -3,12 +3,9 @@ import json
|
||||
import sys
|
||||
from pathlib import Path
|
||||
|
||||
|
||||
REPOSITORY_ROOT = Path(__file__).resolve().parents[4]
|
||||
DEFAULT_SOURCE = Path(__file__).with_name("prowler-scan.json")
|
||||
DEFAULT_ASSET = (
|
||||
REPOSITORY_ROOT / "docs/assets/templates/azure/prowler-scan.json"
|
||||
)
|
||||
DEFAULT_ASSET = REPOSITORY_ROOT / "docs/assets/templates/azure/prowler-scan.json"
|
||||
DEFAULT_SNIPPET = REPOSITORY_ROOT / "docs/snippets/azure-prowler-scan-template.mdx"
|
||||
SNIPPET_PREFIX = (
|
||||
b"{/* AUTO-GENERATED from permissions/templates/azure/bicep/"
|
||||
|
||||
@@ -1,10 +1,10 @@
|
||||
import json
|
||||
import subprocess
|
||||
import sys
|
||||
import tempfile
|
||||
import unittest
|
||||
from pathlib import Path
|
||||
|
||||
|
||||
SCRIPT = Path(__file__).with_name("sync_docs_template.py")
|
||||
|
||||
|
||||
@@ -74,6 +74,18 @@ class SyncDocsTemplateTest(unittest.TestCase):
|
||||
self.assertEqual(result.returncode, 1)
|
||||
self.assertIn("Azure documentation template drift detected", result.stderr)
|
||||
|
||||
def test_role_assignment_ids_ignore_cosmetic_deployment_label(self):
|
||||
template = json.loads(Path(__file__).with_name("prowler-scan.json").read_text())
|
||||
role_assignments = [
|
||||
resource
|
||||
for resource in template["resources"]
|
||||
if resource["type"] == "Microsoft.Authorization/roleAssignments"
|
||||
]
|
||||
|
||||
self.assertEqual(len(role_assignments), 2)
|
||||
for assignment in role_assignments:
|
||||
self.assertNotIn("deploymentLabel", assignment["name"])
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
unittest.main()
|
||||
Reference in new issue
Block a user