Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
84 changes: 84 additions & 0 deletions docs/commandline-flags-and-env-variables.md
Original file line number Diff line number Diff line change
Expand Up @@ -124,6 +124,90 @@ azmpf terraform \
# ... other required flags
```

### Example: ARM with Known Permissions (Comma-separated)

When deploying ARM templates where you already know some of the required permissions (e.g., from a previous MPF run or from documentation), you can seed them upfront to reduce execution time:

```bash
export MPF_SUBSCRIPTIONID="YOUR_SUBSCRIPTION_ID"
export MPF_TENANTID="YOUR_TENANT_ID"
export MPF_SPCLIENTID="YOUR_SP_CLIENT_ID"
export MPF_SPCLIENTSECRET="YOUR_SP_CLIENT_SECRET"
export MPF_SPOBJECTID="YOUR_SP_OBJECT_ID"

azmpf arm \
--initialPermissions "Microsoft.Network/virtualNetworks/read,Microsoft.Network/virtualNetworks/write,Microsoft.Network/virtualNetworks/subnets/read,Microsoft.Network/virtualNetworks/subnets/write" \
--templateFilePath ./samples/templates/aks-private-subnet.json \
--parametersFilePath ./samples/templates/aks-private-subnet-parameters.json \
--verbose
```

Or using PowerShell on Windows:

```powershell
$env:MPF_SUBSCRIPTIONID = "YOUR_SUBSCRIPTION_ID"
$env:MPF_TENANTID = "YOUR_TENANT_ID"
$env:MPF_SPCLIENTID = "YOUR_SP_CLIENT_ID"
$env:MPF_SPCLIENTSECRET = "YOUR_SP_CLIENT_SECRET"
$env:MPF_SPOBJECTID = "YOUR_SP_OBJECT_ID"

.\azmpf.exe arm `
--initialPermissions "Microsoft.Network/virtualNetworks/read,Microsoft.Network/virtualNetworks/write,Microsoft.Network/virtualNetworks/subnets/read,Microsoft.Network/virtualNetworks/subnets/write" `
--templateFilePath .\samples\templates\aks-private-subnet.json `
--parametersFilePath .\samples\templates\aks-private-subnet-parameters.json `
--verbose
```

### Example: ARM with JSON File Format
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Should this be ARM with Known Permissions (JSON File format)

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hi @bgdnext64 once this nit is addressed, we are good to go


For ARM templates with many pre-requisite permissions, using a JSON file is cleaner. Create a file called `arm-initial-permissions.json`:

```json
{
"RequiredPermissions": {
"": [
"Microsoft.Network/virtualNetworks/read",
"Microsoft.Network/virtualNetworks/write",
"Microsoft.Network/virtualNetworks/subnets/read",
"Microsoft.Network/virtualNetworks/subnets/write",
"Microsoft.Network/virtualNetworks/subnets/join/action"
]
}
}
```

Then run MPF with:

```bash
export MPF_SUBSCRIPTIONID="YOUR_SUBSCRIPTION_ID"
export MPF_TENANTID="YOUR_TENANT_ID"
export MPF_SPCLIENTID="YOUR_SP_CLIENT_ID"
export MPF_SPCLIENTSECRET="YOUR_SP_CLIENT_SECRET"
export MPF_SPOBJECTID="YOUR_SP_OBJECT_ID"

azmpf arm \
--initialPermissions @arm-initial-permissions.json \
--templateFilePath ./samples/templates/aks-private-subnet.json \
--parametersFilePath ./samples/templates/aks-private-subnet-parameters.json \
--verbose
```

Or using PowerShell on Windows:

```powershell
$env:MPF_SUBSCRIPTIONID = "YOUR_SUBSCRIPTION_ID"
$env:MPF_TENANTID = "YOUR_TENANT_ID"
$env:MPF_SPCLIENTID = "YOUR_SP_CLIENT_ID"
$env:MPF_SPCLIENTSECRET = "YOUR_SP_CLIENT_SECRET"
$env:MPF_SPOBJECTID = "YOUR_SP_OBJECT_ID"

.\azmpf.exe arm `
--initialPermissions @arm-initial-permissions.json `
Copy link

Copilot AI Apr 10, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

In PowerShell, --initialPermissions @arm-initial-permissions.json will be parsed as splatting syntax rather than a literal argument. Quote the @... value so the executable receives it as a string path.

Suggested change
--initialPermissions @arm-initial-permissions.json `
--initialPermissions "@arm-initial-permissions.json" `

Copilot uses AI. Check for mistakes.
--templateFilePath .\samples\templates\aks-private-subnet.json `
--parametersFilePath .\samples\templates\aks-private-subnet-parameters.json `
--verbose
```

### Example: Bicep with Pre-existing Storage Backend (Comma-separated)

When deploying Bicep templates that depend on pre-existing Azure Storage (for configuration, state, or secrets), you can use comma-separated permissions to speed up analysis:
Expand Down
51 changes: 22 additions & 29 deletions docs/display-options.MD
Original file line number Diff line number Diff line change
Expand Up @@ -117,7 +117,7 @@ export MPF_SPCLIENTID="YOUR_SP_CLIENT_ID"
export MPF_SPCLIENTSECRET="YOUR_SP_CLIENT_SECRET"
export MPF_SPOBJECTID="YOUR_SP_OBJECT_ID"

$ ./azmpf arm --templateFilePath ./samples/templates/aks-private-subnet.json --parametersFilePath ./samples/templates/aks-private-subnet-parameters.json --outputFormat json --verbose
$ ./azmpf arm --templateFilePath ./samples/templates/aks-private-subnet.json --parametersFilePath ./samples/templates/aks-private-subnet-parameters.json --jsonOutput --verbose
```

Or using PowerShell on Windows:
Expand All @@ -129,12 +129,12 @@ $env:MPF_SPCLIENTID = "YOUR_SP_CLIENT_ID"
$env:MPF_SPCLIENTSECRET = "YOUR_SP_CLIENT_SECRET"
$env:MPF_SPOBJECTID = "YOUR_SP_OBJECT_ID"

.\azmpf.exe arm --templateFilePath .\samples\templates\aks-private-subnet.json --parametersFilePath .\samples\templates\aks-private-subnet-parameters.json --outputFormat json --verbose
.\azmpf.exe arm --templateFilePath .\samples\templates\aks-private-subnet.json --parametersFilePath .\samples\templates\aks-private-subnet-parameters.json --jsonOutput --verbose
```

Output:

```
```text
INFO[0000] Executing MPF for ARM
INFO[0000] TemplateFilePath: .\samples\templates\aks-private-subnet.json
INFO[0000] ParametersFilePath: .\samples\templates\aks-private-subnet-parameters.json
Expand Down Expand Up @@ -163,7 +163,7 @@ INFO[0434] *************************
INFO[0447] Role definition deleted successfully
INFO[0452] Resource group deletion initiated successfully...
{
"permissions": [
"SSSSSSSS-SSSS-SSSS-SSSS-SSSSSSSSSSSS": [
"Microsoft.ContainerService/managedClusters/read",
"Microsoft.ContainerService/managedClusters/write",
"Microsoft.Network/virtualNetworks/read",
Expand All @@ -174,33 +174,25 @@ INFO[0452] Resource group deletion initiated successfully...
"Microsoft.Resources/deployments/read",
"Microsoft.Resources/deployments/write"
],
"permissionsByResourceScope": [
{
"resourceScope": "/subscriptions/SSSSSSSS-SSSS-SSSS-SSSS-SSSSSSSSSSSS/resourceGroups/testdeployrg-Uqc4z3E/providers/Microsoft.Network/virtualNetworks/azmpfakstestvnet",
"permissions": [
"Microsoft.Network/virtualNetworks/read",
"Microsoft.Network/virtualNetworks/write"
]
},
{
"resourceScope": "/subscriptions/SSSSSSSS-SSSS-SSSS-SSSS-SSSSSSSSSSSS/resourceGroups/testdeployrg-Uqc4z3E/providers/Microsoft.Network/virtualNetworks/azmpfakstestvnet/subnets/azmpfakstestsubnet",
"permissions": [
"Microsoft.Network/virtualNetworks/subnets/join/action",
"Microsoft.Network/virtualNetworks/subnets/read",
"Microsoft.Network/virtualNetworks/subnets/write"
]
},
{
"resourceScope": "/subscriptions/SSSSSSSS-SSSS-SSSS-SSSS-SSSSSSSSSSSS/resourceGroups/testdeployrg-Uqc4z3E/providers/Microsoft.ContainerService/managedClusters/azmpfakstestcluster",
"permissions": [
"Microsoft.ContainerService/managedClusters/read",
"Microsoft.ContainerService/managedClusters/write"
]
}
"/subscriptions/SSSSSSSS-SSSS-SSSS-SSSS-SSSSSSSSSSSS/resourceGroups/testdeployrg-Uqc4z3E/providers/Microsoft.ContainerService/managedClusters/azmpfakstestcluster": [
"Microsoft.ContainerService/managedClusters/read",
"Microsoft.ContainerService/managedClusters/write"
],
"/subscriptions/SSSSSSSS-SSSS-SSSS-SSSS-SSSSSSSSSSSS/resourceGroups/testdeployrg-Uqc4z3E/providers/Microsoft.Network/virtualNetworks/azmpfakstestvnet": [
"Microsoft.Network/virtualNetworks/read",
"Microsoft.Network/virtualNetworks/write"
],
"/subscriptions/SSSSSSSS-SSSS-SSSS-SSSS-SSSSSSSSSSSS/resourceGroups/testdeployrg-Uqc4z3E/providers/Microsoft.Network/virtualNetworks/azmpfakstestvnet/subnets/azmpfakstestsubnet": [
"Microsoft.Network/virtualNetworks/subnets/join/action",
"Microsoft.Network/virtualNetworks/subnets/read",
"Microsoft.Network/virtualNetworks/subnets/write"
]
}

```

The JSON output is a map where the subscription ID key contains all aggregate permissions, and each resource scope key contains permissions specific to that resource.

### Bicep JSON Output

Similar to ARM templates, Bicep deployments can produce JSON output which shows detailed permission breakdowns. The following is a sample of JSON output:
Comment on lines 196 to 198
Copy link

Copilot AI Apr 10, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The Bicep --jsonOutput section still contains a description later in the section referring to the old JSON structure ("permissions" / "permissionsByResourceScope"). Please update the Bicep JSON Output text so it matches the current --jsonOutput format (flat map of scope → permissions), consistent with the ARM JSON example above.

Copilot uses AI. Check for mistakes.
Expand Down Expand Up @@ -234,6 +226,7 @@ azmpf bicep --bicepFilePath ./samples/bicep/storage-account-simple.bicep --param
```

Output shows permissions aggregated and broken down by resource scope (similar to ARM detailed output example above).

### Viewing info, warn, or debug level logs

By default, the log level is error. More verbose logs can be viewed by setting the LOG_LEVEL environment variable to info, warn, or debug. Additionally, the global flag --verbose can be used to view info level logging and --debug can be used to view debug level logging. The following is a sample of default logging (error level only):
Expand Down Expand Up @@ -262,7 +255,7 @@ $env:MPF_SPOBJECTID = "YOUR_SP_OBJECT_ID"

Output:

```
```text
Permissions Required:
------------------------------------------------------------------------------------------------------------------------------------------
Microsoft.ContainerService/managedClusters/read
Expand Down Expand Up @@ -305,7 +298,7 @@ $env:MPF_SPOBJECTID = "YOUR_SP_OBJECT_ID"

Output:

```
```text
Permissions Required:
------------------------------------------------------------------------------------------------------------------------------------------
Microsoft.Authorization/roleAssignments/read
Expand Down
139 changes: 139 additions & 0 deletions docs/installation-and-quickstart.md
Original file line number Diff line number Diff line change
Expand Up @@ -132,6 +132,145 @@ Microsoft.Resources/deployments/write

```

#### ARM with JSON Output

To get the output in JSON format (which includes per-resource permission details by default), use the `--jsonOutput` flag:

```shell
export MPF_SUBSCRIPTIONID="YOUR_SUBSCRIPTION_ID"
export MPF_TENANTID="YOUR_TENANT_ID"
export MPF_SPCLIENTID="YOUR_SP_CLIENT_ID"
export MPF_SPCLIENTSECRET="YOUR_SP_CLIENT_SECRET"
export MPF_SPOBJECTID="YOUR_SP_OBJECT_ID"

$ ./azmpf arm --templateFilePath ./samples/templates/aks-private-subnet.json --parametersFilePath ./samples/templates/aks-private-subnet-parameters.json --jsonOutput --verbose
```

Or using PowerShell on Windows:

```powershell
$env:MPF_SUBSCRIPTIONID = "YOUR_SUBSCRIPTION_ID"
$env:MPF_TENANTID = "YOUR_TENANT_ID"
$env:MPF_SPCLIENTID = "YOUR_SP_CLIENT_ID"
$env:MPF_SPCLIENTSECRET = "YOUR_SP_CLIENT_SECRET"
$env:MPF_SPOBJECTID = "YOUR_SP_OBJECT_ID"

.\azmpf.exe arm --templateFilePath .\samples\templates\aks-private-subnet.json --parametersFilePath .\samples\templates\aks-private-subnet-parameters.json --jsonOutput --verbose
```

Output (verbose INFO lines omitted for brevity):

```json
{
"SSSSSSSS-SSSS-SSSS-SSSS-SSSSSSSSSSSS": [
"Microsoft.ContainerService/managedClusters/read",
"Microsoft.ContainerService/managedClusters/write",
"Microsoft.Network/virtualNetworks/read",
"Microsoft.Network/virtualNetworks/subnets/join/action",
"Microsoft.Network/virtualNetworks/subnets/read",
"Microsoft.Network/virtualNetworks/subnets/write",
"Microsoft.Network/virtualNetworks/write",
"Microsoft.Resources/deployments/read",
"Microsoft.Resources/deployments/write"
],
"/subscriptions/SSSSSSSS-SSSS-SSSS-SSSS-SSSSSSSSSSSS/resourceGroups/testdeployrg-OJ2zCNA/providers/Microsoft.ContainerService/managedClusters/azmpfakstestcluster": [
"Microsoft.ContainerService/managedClusters/read",
"Microsoft.ContainerService/managedClusters/write"
],
"/subscriptions/SSSSSSSS-SSSS-SSSS-SSSS-SSSSSSSSSSSS/resourceGroups/testdeployrg-OJ2zCNA/providers/Microsoft.Network/virtualNetworks/azmpfakstestvnet": [
"Microsoft.Network/virtualNetworks/read",
"Microsoft.Network/virtualNetworks/write"
],
"/subscriptions/SSSSSSSS-SSSS-SSSS-SSSS-SSSSSSSSSSSS/resourceGroups/testdeployrg-OJ2zCNA/providers/Microsoft.Network/virtualNetworks/azmpfakstestvnet/subnets/azmpfakstestsubnet": [
"Microsoft.Network/virtualNetworks/subnets/join/action",
"Microsoft.Network/virtualNetworks/subnets/read",
"Microsoft.Network/virtualNetworks/subnets/write"
]
}
```

The JSON output is a map where the subscription ID key contains all aggregate permissions, and each resource scope key contains permissions specific to that resource. The `--showDetailedOutput` flag is not needed with `--jsonOutput` (they are mutually exclusive). For more display options, see [display options](display-options.MD).

#### ARM with Initial Permissions

The `--initialPermissions` flag allows you to seed known permissions before MPF starts its analysis. This can reduce execution time by avoiding extra permission-discovery iterations. It accepts either a comma-separated list or a JSON file reference (prefixed with `@`).

##### Comma-separated format

```shell
export MPF_SUBSCRIPTIONID="YOUR_SUBSCRIPTION_ID"
export MPF_TENANTID="YOUR_TENANT_ID"
export MPF_SPCLIENTID="YOUR_SP_CLIENT_ID"
export MPF_SPCLIENTSECRET="YOUR_SP_CLIENT_SECRET"
export MPF_SPOBJECTID="YOUR_SP_OBJECT_ID"

$ ./azmpf arm --templateFilePath ./samples/templates/aks-private-subnet.json --parametersFilePath ./samples/templates/aks-private-subnet-parameters.json \
--initialPermissions "Microsoft.Network/virtualNetworks/read,Microsoft.Network/virtualNetworks/write,Microsoft.Network/virtualNetworks/subnets/read,Microsoft.Network/virtualNetworks/subnets/write" \
--verbose
```

Or using PowerShell on Windows:

```powershell
$env:MPF_SUBSCRIPTIONID = "YOUR_SUBSCRIPTION_ID"
$env:MPF_TENANTID = "YOUR_TENANT_ID"
$env:MPF_SPCLIENTID = "YOUR_SP_CLIENT_ID"
$env:MPF_SPCLIENTSECRET = "YOUR_SP_CLIENT_SECRET"
$env:MPF_SPOBJECTID = "YOUR_SP_OBJECT_ID"

.\azmpf.exe arm --templateFilePath .\samples\templates\aks-private-subnet.json --parametersFilePath .\samples\templates\aks-private-subnet-parameters.json `
--initialPermissions "Microsoft.Network/virtualNetworks/read,Microsoft.Network/virtualNetworks/write,Microsoft.Network/virtualNetworks/subnets/read,Microsoft.Network/virtualNetworks/subnets/write" `
--verbose
```

##### JSON file format

For many permissions, a JSON file is cleaner. Create a file (e.g., `arm-initial-permissions.json`):

```json
{
"RequiredPermissions": {
"": [
"Microsoft.Network/virtualNetworks/read",
"Microsoft.Network/virtualNetworks/write",
"Microsoft.Network/virtualNetworks/subnets/read",
"Microsoft.Network/virtualNetworks/subnets/write",
"Microsoft.Network/virtualNetworks/subnets/join/action"
]
}
}
```

Then reference it with the `@` prefix:

```shell
export MPF_SUBSCRIPTIONID="YOUR_SUBSCRIPTION_ID"
export MPF_TENANTID="YOUR_TENANT_ID"
export MPF_SPCLIENTID="YOUR_SP_CLIENT_ID"
export MPF_SPCLIENTSECRET="YOUR_SP_CLIENT_SECRET"
export MPF_SPOBJECTID="YOUR_SP_OBJECT_ID"

$ ./azmpf arm --templateFilePath ./samples/templates/aks-private-subnet.json --parametersFilePath ./samples/templates/aks-private-subnet-parameters.json \
--initialPermissions @arm-initial-permissions.json \
--verbose
```

Or using PowerShell on Windows:

```powershell
$env:MPF_SUBSCRIPTIONID = "YOUR_SUBSCRIPTION_ID"
$env:MPF_TENANTID = "YOUR_TENANT_ID"
$env:MPF_SPCLIENTID = "YOUR_SP_CLIENT_ID"
$env:MPF_SPCLIENTSECRET = "YOUR_SP_CLIENT_SECRET"
$env:MPF_SPOBJECTID = "YOUR_SP_OBJECT_ID"

.\azmpf.exe arm --templateFilePath .\samples\templates\aks-private-subnet.json --parametersFilePath .\samples\templates\aks-private-subnet-parameters.json `
--initialPermissions @arm-initial-permissions.json `
Copy link

Copilot AI Apr 10, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

In PowerShell, an unquoted argument starting with @ is parsed as splatting/hashtable syntax and will fail here. Quote the value so it’s passed through to the CLI (e.g., use a quoted string that starts with @...).

Suggested change
--initialPermissions @arm-initial-permissions.json `
--initialPermissions "@arm-initial-permissions.json" `

Copilot uses AI. Check for mistakes.
--verbose
```

For full details on the `--initialPermissions` flag, see [Initial Permissions](commandline-flags-and-env-variables.md#initial-permissions).

### Bicep

```shell
Expand Down
2 changes: 1 addition & 1 deletion go.mod
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
module github.com/Azure/mpf

go 1.26.1
go 1.26.2
Comment thread
maniSbindra marked this conversation as resolved.

require (
github.com/Azure/azure-sdk-for-go/sdk/azcore v1.21.0
Expand Down
11 changes: 11 additions & 0 deletions samples/templates/arm-initial-permissions.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
{
"RequiredPermissions": {
"": [
"Microsoft.Network/virtualNetworks/read",
"Microsoft.Network/virtualNetworks/write",
"Microsoft.Network/virtualNetworks/subnets/read",
"Microsoft.Network/virtualNetworks/subnets/write",
"Microsoft.Network/virtualNetworks/subnets/join/action"
]
}
}
Loading