Azure / Azure/PSRule.Rules.Azure
[BUG] Bicep expansion fails when AVM Web Site `managedIdentities.userAssignedResourceIds` contains a module output
- Dominant language
- PowerShell
- Stars
- 447
- Forks
- 109
- Avg merge
- 2d 19h
- Merged PRs (30d)
- 23
Description
### Existing rule
_No response_
### Description of the issue
# Bicep expansion fails when AVM Web Site `managedIdentities.userAssignedResourceIds` contains a module output
## Description
PSRule for Azure fails during Bicep parameter file expansion when a resource ID returned from another Bicep module is passed to the `managedIdentities.userAssignedResourceIds` parameter of the Azure Verified Module:
```bicep
br/public:avm/res/web/site:0.24.0
```
The Bicep itself is valid and the resource ID is provided through the normal Bicep module output mechanism.
The failure has been isolated specifically to the `managedIdentities` parameter. Removing `managedIdentities` allows PSRule expansion to complete.
The error returned by PSRule is:
```text
Invoke-PSRule: Failed to expand bicep source '\main.canary.bicepparam'. Exception calling "GetBicepParamResources" with "2" argument(s): "Cannot process argument because the value of argument "name" is not valid. Change the value of the "name" argument and run the operation again."
```
## Environment
Please let me know if additional environment information is required.
```text
PSRule version: 2.9.0
PSRule.Rules.Azure version: 1.47.0
PowerShell version: 7.6.4
Bicep CLI version: 0.42.1 (caea9302e8)
OS: Windows
AVM module: avm/res/web/site:0.24.0
Input type: .bicepparam
```
## PSRule configuration
Bicep/Bicepparam expansion is enabled.
Relevant configuration is approximately:
```yaml
configuration:
AZURE_BICEP_FILE_EXPANSION: true
AZURE_BICEP_PARAMS_FILE_EXPANSION: true
```
Other unrelated configuration has been omitted.
## Scenario
A user-assigned managed identity is created using a Bicep/AVM module.
The module exposes the identity resource ID as an output.
That output is then passed to the AVM Web Site module:
```bicep
module userAssignedIdentity 'br/public:avm/res/managed-identity/user-assigned-identity:0.6.0' = {
name: 'userAssignedIdentity'
scope: resourceGroup
params: {
// ...
}
}
module appService 'br/public:avm/res/web/site:0.24.0' = {
scope: resourceGroup
name: 'appService'
params: {
kind: 'app,linux'
name: appServiceName
serverFarmResourceId: appServicePlan.outputs.resourceId
location: location
managedIdentities: {
userAssignedResourceIds: [
userAssignedIdentity.outputs.resourceId
]
}
// ...
}
}
```
The important part of the reproduction is:
```bicep
managedIdentities: {
userAssignedResourceIds: [
userAssignedIdentity.outputs.resourceId
]
}
```
## Actual behavior
When PSRule expands the `.bicepparam` file, expansion fails with:
```text
Exception calling "GetBicepParamResources" with "2" argument(s):
"Cannot process argument because the value of argument "name" is not valid.
Change the value of the "name" argument and run the operation again."
```
Unlike some other Bicep expansion failures, the error does not identify:
* the deployment/resource that failed;
* the symbolic resource name;
* the ARM expression being evaluated;
* the JSON path; or
* the Bicep/ARM source location.
This makes the source of the failure difficult to identify.
## Expected behavior
PSRule should successfully expand the deployment when a valid resource ID from a module output is passed as an AVM module parameter.
In particular, passing:
```bicep
userAssignedIdentity.outputs.resourceId
```
as an item in:
```bicep
managedIdentities.userAssignedResourceIds
```
should be supported when the module output resolves to a valid user-assigned managed identity resource ID.
This pattern works as a normal Bicep/ARM deployment dependency.
## Isolation performed
The issue was isolated by progressively removing modules and parameters.
### 1. Removing the App Service module
Removing:
```bicep
module appService 'br/public:avm/res/web/site:0.24.0'
```
allows PSRule expansion to proceed.
### 2. Reducing the App Service module
The App Service module was reduced to a minimal configuration and its parameters were added back individually.
The failure was isolated specifically to:
```bicep
managedIdentities: {
userAssignedResourceIds: [
userAssignedIdentity.outputs.resourceId
]
}
```
Removing only `managedIdentities` allows expansion to succeed.
Adding it again causes:
```text
Cannot process argument because the value of argument "name" is not valid.
```
### 3. Other AVM parameters tested
Other App Service parameters were individually tested, including configuration related to:
* site configuration;
* VNet integration;
* private endpoints;
* diagnostic settings;
* App Service configuration/app settings;
* Key Vault access identity.
These were not responsible for this particular error.
The error follows the `managedIdentities` parameter.
### 4. PowerShell version
The PowerShell version is newer than the versions associated with the previously documented PowerShell 7.4.0/7.4.1 `"name" is not valid` issue.
Therefore this does not appear to be that PowerShell version issue.
## Suspected cause
This appears to be related to PSRule expansion of a module output when that output is subsequently used by the AVM Web Site module to construct the ARM `userAssignedIdentities` object.
The ARM representation of a user-assigned identity uses the resource ID as an object property name, conceptually:
```json
{
"identity": {
"type": "UserAssigned",
"userAssignedIdentities": {
"/subscriptions/.../resourceGroups/.../providers/Microsoft.ManagedIdentity/userAssignedIdentities/example": {}
}
}
}
```
The AVM input is an array of resource IDs:
```bicep
managedIdentities: {
userAssignedResourceIds: [
userAssignedIdentity.outputs.resourceId
]
}
```
The AVM module subsequently transforms those resource IDs into the keys of the `userAssignedIdentities` object.
My suspicion is therefore that PSRule's expansion engine is attempting to construct an object/property name before the module output has been materialized to a concrete string.
This would also be consistent with the exception referring specifically to an invalid `"name"` rather than reporting an invalid managed identity resource ID.
## Why this may be a PSRule expansion issue
The Bicep dependency itself is valid:
```bicep
userAssignedIdentity.outputs.resourceId
```
Using an output from one module as an input to another module is a standard Bicep pattern and also establishes the appropriate deployment dependency.
The issue appears only while PSRule is statically expanding the deployment.
It therefore appears that PSRule's ARM expansion/evaluation may not be preserving or resolving the module output correctly when the resulting value is used as an object property name.
## Minimal conceptual reproduction
The issue can be summarized as:
```bicep
module identity './identity.bicep' = {
name: 'identity'
params: {
// ...
}
}
module site 'br/public:avm/res/web/site:0.24.0' = {
name: 'site'
params: {
name: 'example-app'
location: location
serverFarmResourceId: serverFarmResourceId
managedIdentities: {
userAssignedResourceIds: [
identity.outputs.resourceId
]
}
}
}
```
Where `identity.bicep` exposes:
```bicep
output resourceId string = identity.id
```
PSRule expansion fails when processing the Web Site module.
## Workaround
A possible workaround is to provide PSRule with a resource ID that can be calculated statically instead of consuming the module output, for example by constructing the managed identity resource ID independently and adding an explicit dependency on the identity module.
However, this is undesirable because:
1. The identity resource ID is already exposed by the module.
2. Using the module output is the natural Bicep dependency pattern.
3. Reconstructing the resource ID duplicates information already known by the identity module.
4. An explicit `dependsOn` may then be required because the implicit dependency established by the module output has been removed.
5. The workaround changes otherwise valid Bicep specifically to accommodate static analysis.
An `existing` resource declaration can similarly be used to obtain the identity `.id`, but this also introduces a redundant declaration of a resource that is already created by another module in the same deployment.
## Additional observations
During investigation I encountered other PSRule expansion limitations involving AVM modules where values normally resolved by ARM at deployment time needed to be made explicit for PSRule.
For example:
* A Key Vault secret nested deployment required a placeholder for an unresolved `value` parameter via `AZURE_PARAMETER_DEFAULTS`.
* Private endpoint `location` needed to be supplied explicitly rather than allowing the AVM module to derive it from the subnet resource.
Those issues could be worked around by providing PSRule with static values.
The `managedIdentities` case is different because the value already comes from a valid Bicep module output and should naturally be resolvable through the deployment dependency graph.
## Questions
1. Is the use of a module output as an element of `managedIdentities.userAssignedResourceIds` expected to be supported during Bicep expansion?
2. Is there a known limitation when a module output ultimately becomes an ARM object property name/key?
3. Is the `"value of argument 'name' is not valid"` exception coming from PSRule's handling of the generated `userAssignedIdentities` object?
4. Is there a recommended PSRule configuration/workaround that preserves the normal Bicep module-output dependency rather than requiring the resource ID to be reconstructed?
5. Could the expansion error be enhanced to report the nested deployment, ARM expression, and JSON path that caused this exception?
### Error messages
_No response_
### Reproduction
See the issue report for reproduction steps
### Version of PSRule
2.9.0
### Version of PSRule for Azure
1.47.0
### Additional context
_No response_
Contributor guide
Research direction
Reproduce the failure with the minimal .bicepparam scenario and trace the Bicep parameter expansion path around GetBicepParamResources, especially where managedIdentities.userAssignedResourceIds becomes userAssignedIdentities object keys. Done means the module output expands successfully, the deployment completes expansion, and failures identify the relevant deployment or JSON path.
Written by the indexing model from the issue text.
Assessment
- Tech stack
- azure, powershell
- Domain
- devops, infrastructure, tooling
- Issue type
- Bug
- Difficulty
- 4/5
- Estimated time
- 3-5 days
- Activity status
- Active
- Clarity
- Mostly clear
- Newbie friendliness
- 52/100