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
2 changes: 2 additions & 0 deletions .github/CODEOWNERS
Original file line number Diff line number Diff line change
Expand Up @@ -94,6 +94,8 @@ Tasks/AzureResourceGroupDeploymentV2/ @microsoft/release-management-task-te

Tasks/AzureResourceManagerTemplateDeploymentV3/ @microsoft/release-management-task-team @manolerazvan

Tasks/BicepDeployV0/ @azure/bicep-admins

# DRI rotation: App Service (Web Apps)
Tasks/AzureRmWebAppDeploymentV3/ @jvano @dannysongg @microsoft/azure-app-service-pipelines-tasks @microsoft/release-management-task-team @manolerazvan

Expand Down
230 changes: 230 additions & 0 deletions Tasks/BicepDeployV0/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,230 @@
# Bicep Deploy Task

## Overview

The Bicep Deploy task is used to deploy and manage Azure resources using [Bicep](https://learn.microsoft.com/azure/azure-resource-manager/bicep/overview) files. Bicep is a domain-specific language (DSL) that uses declarative syntax to deploy Azure resources. This task supports both standard Azure deployments and [Azure Deployment Stacks](https://learn.microsoft.com/azure/azure-resource-manager/bicep/deployment-stacks), providing a simplified and more maintainable way to manage your Azure infrastructure as code.

The task handles:
- Creating or updating Azure resources using Bicep templates
- Validating Bicep templates before deployment
- Previewing changes with What-If operations
- Managing deployment stacks with lifecycle policies
- Deleting deployments and deployment stacks
- Installing and managing Bicep CLI versions automatically

## What's New in Version 1.0

- **Native Bicep Support**: Direct deployment from `.bicep` and `.bicepparam` files without requiring pre-compilation to ARM templates
- **Deployment Stacks**: Full support for Azure Deployment Stacks with deny settings, unmanaged resource policies, and lifecycle management
- **Automatic Bicep CLI Management**: Automatically downloads and caches the specified version of Bicep CLI
- **Cross-Platform**: Works with Windows, Linux, and macOS agents
- **Multiple Deployment Scopes**: Supports Resource Group, Subscription, Management Group, and Tenant scopes
- **What-If Operations**: Preview changes before applying them to your Azure environment
- **Flexible Parameter Input**: Support for inline YAML/JSON parameters and traditional parameter files
- **Output Masking**: Automatically mask sensitive outputs like secrets and connection strings

## Prerequisites

### Azure Subscription

To deploy to Azure, an Azure subscription must be linked to Azure Pipelines using a service connection:

1. Navigate to **Project Settings** → **Service connections**
2. Create a new service connection of type **Azure Resource Manager**
3. Choose authentication method:
- **Service Principal (automatic)** - Recommended for most scenarios
- **Service Principal (manual)** - For advanced configurations
- **Managed Identity** - For Azure-hosted agents with managed identities
- **Workload Identity Federation** - For enhanced security without secrets

For troubleshooting service connections, refer to the [Azure RM endpoint documentation](https://learn.microsoft.com/azure/devops/pipelines/library/connect-to-azure).

### Agent Requirements

- **Minimum Agent Version**: 2.144.0
- **Supported OS**: Windows, Linux, macOS
- **Node.js**: Node.js 20 or higher (included in modern hosted agents)
- **Bicep CLI**: Automatically installed by the task (no manual installation required)

## Parameters

The table below lists all task inputs. Required inputs are marked with **\***.

### Core Parameters

| Input Name | Required | Description | Allowed Values |
|------------|----------|-------------|----------------|
| `executionType` | Yes | Deployment model to use | `Deployment` (standard ARM deployment)<br>`Deployment Stack` (with lifecycle management) |
| `operation` | Yes | Action to perform | `Create or update`<br>`Validate`<br>`What-If (preview changes)` (Deployment only)<br>`Delete` |
| `deploymentScope` | Yes | Scope for the deployment | `Resource Group`<br>`Subscription`<br>`Management Group`<br>`Tenant` |
| `deploymentName` | No | Name for the deployment or stack. Auto-generated if not provided. | Any valid string |
| `connectedServiceName` | Yes | Azure Resource Manager service connection | Service connection name |
| `subscriptionId` | Conditional | Target Azure subscription (required for Resource Group and Subscription scopes) | Subscription ID |
| `resourceGroupName` | Conditional | Target resource group name (required for Resource Group scope) | Resource group name |
| `location` | Conditional | Azure region for deployment metadata (required for Subscription, Management Group, and Tenant scopes) | Azure region name |
| `tenantId` | Conditional | Azure AD tenant ID (required for Tenant scope) | Tenant GUID |
| `managementGroupId` | Conditional | Management group identifier (required for Management Group scope) | Management group ID |

### Template Parameters

| Input Name | Required | Description | Allowed Values |
|------------|----------|-------------|----------------|
| `templateFile` | No | Path to the Bicep template file | File path (`.bicep`) |
| `parametersFile` | No | Path to the parameters file | File path (`.json` or `.bicepparam`) |
| `overrideParameters` | No | Inline parameter values that override parameters file. Accepts JSON or YAML format. | JSON or YAML object |

**Note**: Follow [Azure Naming Guidelines](https://learn.microsoft.com/azure/cloud-adoption-framework/ready/azure-best-practices/naming-and-tagging) when specifying resource names in parameters:

| Resource Type | Length | Casing | Valid Characters | Globally Unique |
|--------------|--------|--------|------------------|-----------------|
| Storage Account | 3-24 | lowercase | alphanumeric | Yes |
| Resource Group | 2-64 | case-insensitive | alphanumeric, periods, underscores, hyphens, parentheses (cannot end in period) | No |
| Key Vault | 3-24 | case-insensitive | alphanumeric and hyphens | Yes |
| DNS Name | 3-63 | lowercase | alphanumeric and hyphens | Yes |

### Deployment Stack Parameters

These inputs apply when `executionType` is set to `Deployment Stack`.

| Input Name | Required | Description | Allowed Values |
|------------|----------|-------------|----------------|
| `actionOnUnmanage` | Yes (for stacks) | Action for resources not in template | `Detach` (default - keep resources but remove from stack)<br>`Delete` (delete unmanaged resources) |
| `actionOnUnmanageResourceGroups` | No | Action for unmanaged resource groups (Subscription/Management Group/Tenant scopes only) | `Detach`<br>`Delete` |
| `actionOnUnmanageManagementGroups` | No | Action for unmanaged management groups (Tenant scope only) | `Detach`<br>`Delete` |
| `denySettingsMode` | Yes (for stacks) | Protection level against unauthorized changes | `None` (default - no protection)<br>`DenyDelete` (prevent deletion)<br>`DenyWriteAndDelete` (prevent modification and deletion) |
| `denySettingsExcludedActions` | No | Comma-separated list of Azure RBAC actions excluded from deny settings | e.g., `Microsoft.Compute/virtualMachines/write` |
| `denySettingsExcludedPrincipals` | No | Comma-separated list of Azure AD principal IDs excluded from deny settings | Azure AD principal GUIDs |
| `denySettingsApplyToChildScopes` | No | Apply deny settings to child resource scopes | `true`<br>`false` |
| `bypassStackOutOfSyncError` | No | Skip errors when stack is out of sync with Azure resources | `true`<br>`false` |

### Advanced Parameters

| Input Name | Required | Description | Allowed Values |
|------------|----------|-------------|----------------|
| `deploymentDescription` | No | Description text for the deployment or stack | Any string |
| `tags` | No | Tags as JSON or YAML object (Deployment Stack only) | JSON or YAML object |
| `bicepVersion` | No | Specific Bicep CLI version to use. Uses latest stable version if empty. | Version string (e.g., `0.30.23`) |
| `maskedOutputs` | No | Comma-separated list of output names to mask in logs for security | e.g., `connectionString,adminPassword` |
| `environment` | No | Target Azure cloud environment | `azureCloud` (default)<br>`azureChinaCloud`<br>`azureGermanCloud`<br>`azureUSGovernment` |
| `whatIfExcludeChangeTypes` | No | Comma-separated change types to exclude from What-If output (What-If operation only) | e.g., `NoChange,Ignore` |
| `validationLevel` | No | Template validation level (Validate and What-If operations only) | `provider`<br>`template`<br>`providerNoRbac` |

## Usage Examples

### Example 1: Basic Deployment

```yaml
- task: BicepDeploy@1
displayName: 'Deploy Bicep Template'
inputs:
azureResourceManagerConnection: 'Azure-Connection'
subscriptionId: '$(subscriptionId)'
resourceGroupName: 'my-resource-group'
templateFile: 'infra/main.bicep'
parametersFile: 'infra/main.bicepparam'
```

### Example 2: Deployment Stack

```yaml
- task: BicepDeploy@1
displayName: 'Deploy with Stack Protection'
inputs:
type: 'deploymentStack'
operation: 'create'
name: 'production-stack'
azureResourceManagerConnection: 'Azure-Connection'
subscriptionId: '$(subscriptionId)'
resourceGroupName: 'production-rg'
templateFile: 'infra/main.bicep'
parametersFile: 'infra/production.bicepparam'
actionOnUnmanageResources: 'delete'
denySettingsMode: 'denyWriteAndDelete'
```

### Example 3: Subscription-Level Deployment

```yaml
- task: BicepDeploy@1
displayName: 'Deploy Subscription Resources'
inputs:
scope: 'subscription'
azureResourceManagerConnection: 'Azure-Connection'
subscriptionId: '$(subscriptionId)'
location: 'eastus'
templateFile: 'infra/subscription.bicep'
parametersFile: 'infra/subscription.bicepparam'
```

## Deployment Outputs

The task automatically creates pipeline variables for all outputs defined in your Bicep template. These variables can be used in subsequent tasks.

**Defining Outputs in Bicep**

Outputs are defined in the Bicep template using the `output` keyword. For example:

```bicep
output storageAccountName string = storageAccount.name
output webAppUrl string = webApp.properties.defaultHostName
output intOutput int = 42
output objectOutput object = {
key1: 'value1'
key2: 'value2'
}
```

For detailed guidance, refer to the [Bicep Outputs documentation](https://learn.microsoft.com/azure/azure-resource-manager/bicep/outputs).

**How Outputs Become Available**

After the deployment completes successfully, all outputs are automatically converted to Azure Pipelines variables with the same names as defined in your Bicep template. These variables are created at the pipeline level and can be directly referenced in subsequent tasks using the standard variable syntax: `$(outputName)`.

### Accessing Outputs in PowerShell

```yaml
- task: BicepDeploy@1
displayName: 'Deploy Infrastructure'
inputs:
azureResourceManagerConnection: 'Azure-Connection'
subscriptionId: '$(subscriptionId)'
resourceGroupName: 'my-resource-group'
templateFile: 'infra/main.bicep'

- task: PowerShell@2
displayName: 'Use Deployment Outputs'
inputs:
targetType: 'inline'
script: |
Write-Host "Storage Account Name: $(storageAccountName)"
Write-Host "Web App URL: $(webAppUrl)"
```

### Accessing Outputs in Bash

```yaml
- task: BicepDeploy@1
displayName: 'Deploy Infrastructure'
inputs:
azureResourceManagerConnection: 'Azure-Connection'
subscriptionId: '$(subscriptionId)'
resourceGroupName: 'my-resource-group'
templateFile: 'infra/main.bicep'

- task: Bash@3
displayName: 'Use Deployment Outputs'
inputs:
targetType: 'inline'
script: |
echo "Storage Account Name: $(storageAccountName)"
echo "Web App URL: $(webAppUrl)"
```

## Feedback and Support

Please report issues or request features at [Developer Community Forum](https://developercommunity.visualstudio.com/spaces/21/index.html).

For Bicep-specific questions and issues, refer to:
- [Bicep Documentation](https://learn.microsoft.com/azure/azure-resource-manager/bicep/)
- [Bicep GitHub Repository](https://github.com/Azure/bicep)
- [Azure Deployment Stacks Documentation](https://learn.microsoft.com/azure/azure-resource-manager/bicep/deployment-stacks)
Original file line number Diff line number Diff line change
@@ -0,0 +1,87 @@
{
"loc.friendlyName": "Bicep Deploy",
"loc.helpMarkDown": "[Learn more about this task](https://aka.ms/bicepdeploytaskreadme)",
"loc.description": "Deploy and Manage Azure Resources using Bicep Files",
"loc.instanceNameFormat": "Bicep $(operation) $(name)",
"loc.group.displayName.AzureDetails": "Azure Details",
"loc.group.displayName.Template": "Template",
"loc.group.displayName.DeploymentStack": "Deployment Stack Options",
"loc.group.displayName.Advanced": "Advanced",
"loc.input.label.type": "Execution type",
"loc.input.help.type": "Specifies the execution type, deployment or deploymentStack.",
"loc.input.label.operation": "Operation",
"loc.input.help.operation": "Specifies the operation to perform.",
"loc.input.label.scope": "Deployment scope",
"loc.input.help.scope": "Specifies the scope at which resources are deployed.",
"loc.input.label.name": "Deployment name",
"loc.input.help.name": "Specifies the name of the deployment or deployment stack. If not provided, a default name will be generated.",
"loc.input.label.ConnectedServiceName": "Azure Resource Manager connection",
"loc.input.help.ConnectedServiceName": "Select the Azure Resource Manager service connection.",
"loc.input.label.subscriptionId": "Subscription",
"loc.input.help.subscriptionId": "Select the Azure subscription. Required if scope is subscription or resourceGroup.",
"loc.input.label.resourceGroupName": "Resource group",
"loc.input.help.resourceGroupName": "Provide the name of the resource group.",
"loc.input.label.location": "Location",
"loc.input.help.location": "Location to store deployment metadata. Required for subscription, managementGroup, and tenant scopes.",
"loc.input.label.tenantId": "Tenant ID",
"loc.input.help.tenantId": "Specifies the tenant ID. Required if scope is tenant.",
"loc.input.label.managementGroupId": "Management group ID",
"loc.input.help.managementGroupId": "Specifies the management group ID. Required if scope is managementGroup.",
"loc.input.label.templateFile": "Template file",
"loc.input.help.templateFile": "Specify the path to the Bicep template file (.bicep).",
"loc.input.label.parametersFile": "Parameters file",
"loc.input.help.parametersFile": "Specify the path to the parameters file (.json or .bicepparam).",
"loc.input.label.parameters": "Override parameters",
"loc.input.help.parameters": "Specify inline parameters as a JSON or YAML object. Example: {\"param1\": \"value1\", \"param2\": \"value2\"}",
"loc.input.label.actionOnUnmanageResources": "Action on unmanaged resources",
"loc.input.help.actionOnUnmanageResources": "Specifies the action to take on resources not defined in the template.",
"loc.input.label.actionOnUnmanageResourceGroups": "Action on unmanaged resource groups",
"loc.input.help.actionOnUnmanageResourceGroups": "Specifies the action to take on resource groups not defined in the template.",
"loc.input.label.actionOnUnmanageManagementGroups": "Action on unmanaged management groups",
"loc.input.help.actionOnUnmanageManagementGroups": "Specifies the action to take on management groups not defined in the template.",
"loc.input.label.denySettingsMode": "Deny settings mode",
"loc.input.help.denySettingsMode": "Specifies the mode of the deny settings to prevent unauthorized changes.",
"loc.input.label.denySettingsExcludedActions": "Deny settings excluded actions",
"loc.input.help.denySettingsExcludedActions": "Comma-separated list of actions to exclude from deny settings.",
"loc.input.label.denySettingsExcludedPrincipals": "Deny settings excluded principals",
"loc.input.help.denySettingsExcludedPrincipals": "Comma-separated list of principal IDs to exclude from deny settings.",
"loc.input.label.denySettingsApplyToChildScopes": "Apply deny settings to child scopes",
"loc.input.help.denySettingsApplyToChildScopes": "When enabled, deny settings also apply to child scopes of managed resources.",
"loc.input.label.bypassStackOutOfSyncError": "Bypass stack out of sync error",
"loc.input.help.bypassStackOutOfSyncError": "Bypass errors when the deployment stack is out of sync.",
"loc.input.label.description": "Description",
"loc.input.help.description": "Description for the deployment or deployment stack.",
"loc.input.label.tags": "Tags",
"loc.input.help.tags": "Tags as JSON or YAML object. Example: {\"Environment\": \"Development\", \"Owner\": \"TeamName\"}",
"loc.input.label.bicepVersion": "Bicep version",
"loc.input.help.bicepVersion": "Specify the version of Bicep to use (e.g., '0.38.5'). If not provided, the latest version will be used.",
"loc.input.label.maskedOutputs": "Masked outputs",
"loc.input.help.maskedOutputs": "Comma-separated list of output names to mask values for (e.g., secrets).",
"loc.input.label.environment": "Azure environment",
"loc.input.help.environment": "Specifies the Azure environment to use.",
"loc.input.label.whatIfExcludeChangeTypes": "What-If exclude change types",
"loc.input.help.whatIfExcludeChangeTypes": "Comma-separated list of change types to exclude from What-If operation (e.g., noChange, ignore).",
"loc.input.label.validationLevel": "Validation level",
"loc.input.help.validationLevel": "Validation level for deployment operations.",
"loc.messages.CreateFailed": "Create failed",
"loc.messages.ValidationFailed": "Validation failed",
"loc.messages.OperationFailed": "Operation failed",
"loc.messages.RequestFailedCorrelation": "Request failed. CorrelationId: %s",
"loc.messages.InputMustBeBoolean": "Input '%s' must be a boolean value",
"loc.messages.InputRequired": "Input '%s' is required but not provided",
"loc.messages.InputMustBeEnum": "Input '%s' must be one of the following values: '%s'",
"loc.messages.InputMustBeValidObject": "Input '%s' must be a valid JSON or YAML object",
"loc.messages.InputMustBeStringObject": "Input '%s' must be a valid JSON or YAML object containing only string values",
"loc.messages.LocationRequired": "Location is required",
"loc.messages.FailedToDetermineScope": "Failed to determine deployment scope from Bicep file.",
"loc.messages.UnsupportedParametersFile": "Unsupported parameters file type: %s",
"loc.messages.UnsupportedTemplateFile": "Unsupported template file type: %s",
"loc.messages.TemplateFileRequired": "Template file is required",
"loc.messages.InvalidChangeType": "Invalid ChangeType: %s",
"loc.messages.UnknownPropertyChangeType": "Unknown property change type: %s.",
"loc.messages.InvalidJsonValue": "Invalid JSON value: %s",
"loc.messages.DiagnosticsReturned": "Diagnostics returned by the API",
"loc.messages.BicepVersionInstalled": "Installed Bicep version %s to %s",
"loc.messages.TaskConfig": "Task config: %s",
"loc.messages.OperationSucceeded": "Operation completed successfully"
}
Loading