Skip to content

Commit

Permalink
feat: Add private-endpoint e2e (#2687)
Browse files Browse the repository at this point in the history
## Description

Added e2e test with private-endpoint to reflect
https://learn.microsoft.com/en-us/azure/azure-resource-manager/bicep/deployment-script-vnet-private-endpoint.

## Pipeline Reference

<!-- Insert your Pipeline Status Badge below -->

| Pipeline |
| -------- |
|
[![avm.res.resources.deployment-script](https://github.com/Azure/bicep-registry-modules/actions/workflows/avm.res.resources.deployment-script.yml/badge.svg?branch=userrs%2Fsegraef%2Fds-pe)](https://github.com/Azure/bicep-registry-modules/actions/workflows/avm.res.resources.deployment-script.yml)
|

## Type of Change

<!-- Use the checkboxes [x] on the options that are relevant. -->

- [ ] Update to CI Environment or utilities (Non-module affecting
changes)
- [x] Azure Verified Module updates:
- [ ] Bugfix containing backwards-compatible bug fixes, and I have NOT
bumped the MAJOR or MINOR version in `version.json`:
- [ ] Someone has opened a bug report issue, and I have included "Closes
#{bug_report_issue_number}" in the PR description.
- [ ] The bug was found by the module author, and no one has opened an
issue to report it yet.
- [x] Feature update backwards compatible feature updates, and I have
bumped the MINOR version in `version.json`.
- [ ] Breaking changes and I have bumped the MAJOR version in
`version.json`.
  - [x] Update to documentation

## Checklist

- [x] I'm sure there are no other open Pull Requests for the same
update/change
- [x] I have run `Set-AVMModule` locally to generate the supporting
module files.
- [x] My corresponding pipelines / checks run clean and green without
any errors or warnings

<!-- Please keep up to date with the contribution guide at
https://aka.ms/avm/contribute/bicep -->

---------

Co-authored-by: Alexander Sehr <ASehr@hotmail.de>
  • Loading branch information
segraef and AlexanderSehr authored Jul 29, 2024
1 parent 2a48a03 commit 1533f62
Show file tree
Hide file tree
Showing 3 changed files with 334 additions and 6 deletions.
113 changes: 107 additions & 6 deletions avm/res/resources/deployment-script/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -30,9 +30,10 @@ The following section provides usage examples for the module, which were used to
- [Using Azure CLI](#example-1-using-azure-cli)
- [Using only defaults](#example-2-using-only-defaults)
- [Using large parameter set](#example-3-using-large-parameter-set)
- [Using Private Networking](#example-4-using-private-networking)
- [Using Azure PowerShell](#example-5-using-azure-powershell)
- [WAF-aligned](#example-6-waf-aligned)
- [Using Private Endpoint](#example-4-using-private-endpoint)
- [Using Private Networking](#example-5-using-private-networking)
- [Using Azure PowerShell](#example-6-using-azure-powershell)
- [WAF-aligned](#example-7-waf-aligned)

### Example 1: _Using Azure CLI_

Expand Down Expand Up @@ -386,7 +387,107 @@ module deploymentScript 'br/public:avm/res/resources/deployment-script:<version>
</details>
<p>

### Example 4: _Using Private Networking_
### Example 4: _Using Private Endpoint_

This instance deploys the module with access to a private endpoint.


<details>

<summary>via Bicep module</summary>

```bicep
module deploymentScript 'br/public:avm/res/resources/deployment-script:<version>' = {
name: 'deploymentScriptDeployment'
params: {
// Required parameters
kind: 'AzureCLI'
name: 'rdspe001'
// Non-required parameters
azCliVersion: '2.9.1'
cleanupPreference: 'Always'
location: '<location>'
managedIdentities: {
userAssignedResourcesIds: [
'<managedIdentityResourceId>'
]
}
retentionInterval: 'P1D'
runOnce: true
scriptContent: 'echo \'AVM Deployment Script test!\''
storageAccountResourceId: '<storageAccountResourceId>'
subnetResourceIds: [
'<subnetResourceId>'
]
timeout: 'PT1H'
}
}
```

</details>
<p>

<details>

<summary>via JSON Parameter file</summary>

```json
{
"$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentParameters.json#",
"contentVersion": "1.0.0.0",
"parameters": {
// Required parameters
"kind": {
"value": "AzureCLI"
},
"name": {
"value": "rdspe001"
},
// Non-required parameters
"azCliVersion": {
"value": "2.9.1"
},
"cleanupPreference": {
"value": "Always"
},
"location": {
"value": "<location>"
},
"managedIdentities": {
"value": {
"userAssignedResourcesIds": [
"<managedIdentityResourceId>"
]
}
},
"retentionInterval": {
"value": "P1D"
},
"runOnce": {
"value": true
},
"scriptContent": {
"value": "echo \"AVM Deployment Script test!\""
},
"storageAccountResourceId": {
"value": "<storageAccountResourceId>"
},
"subnetResourceIds": {
"value": [
"<subnetResourceId>"
]
},
"timeout": {
"value": "PT1H"
}
}
}
```

</details>
<p>

### Example 5: _Using Private Networking_

This instance deploys the module with access to a private network.

Expand Down Expand Up @@ -486,7 +587,7 @@ module deploymentScript 'br/public:avm/res/resources/deployment-script:<version>
</details>
<p>

### Example 5: _Using Azure PowerShell_
### Example 6: _Using Azure PowerShell_

This instance deploys the module with an Azure PowerShell script.

Expand Down Expand Up @@ -570,7 +671,7 @@ module deploymentScript 'br/public:avm/res/resources/deployment-script:<version>
</details>
<p>

### Example 6: _WAF-aligned_
### Example 7: _WAF-aligned_

This instance deploys the module in alignment with the best-practices of the Well-Architected Framework.

Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,154 @@
@description('Optional. The location to deploy resources to.')
param location string = resourceGroup().location

@description('Required. The name of the managed identity to create.')
param managedIdentityName string

@description('Required. The name of the Virtual Network to create.')
param virtualNetworkName string

@description('Required. The name of the Storage Account to create.')
param storageAccountName string

@description('Required. The name of the private endpoint to create.')
param privateEndpointName string

var addressPrefix = '10.0.0.0/16'

// Role required for deployment script to be able to use a storage account via private networking
resource storageFileDataPrivilegedContributor 'Microsoft.Authorization/roleDefinitions@2022-04-01' existing = {
name: '69566ab7-960f-475b-8e7c-b3118f30c6bd'
scope: tenant()
}

resource managedIdentity 'Microsoft.ManagedIdentity/userAssignedIdentities@2023-01-31' = {
name: managedIdentityName
location: location
}

resource storageFileSharePermissions 'Microsoft.Authorization/roleAssignments@2022-04-01' = {
name: guid('storageFileDataPrivilegedContributorRole', managedIdentity.id, storageAccount.id)
scope: storageAccount
properties: {
principalId: managedIdentity.properties.principalId
roleDefinitionId: storageFileDataPrivilegedContributor.id
principalType: 'ServicePrincipal'
}
}

resource storageAccount 'Microsoft.Storage/storageAccounts@2023-04-01' = {
name: storageAccountName
location: location
sku: {
name: 'Standard_LRS'
}
kind: 'StorageV2'
properties: {
publicNetworkAccess: 'Disabled'
allowSharedKeyAccess: true // Cannot be set to false when using a private network for the deployment script
networkAcls: {
defaultAction: 'Deny'
bypass: 'AzureServices'
}
}
}

resource privateEndpoint 'Microsoft.Network/privateEndpoints@2023-11-01' = {
name: privateEndpointName
location: location
properties: {
subnet: {
id: virtualNetwork.properties.subnets[1].id
}
privateLinkServiceConnections: [
{
name: '${privateEndpointName}-storageConnection'
properties: {
privateLinkServiceId: storageAccount.id
groupIds: [
'file'
]
}
}
]
}
}

resource privateDnsZone 'Microsoft.Network/privateDnsZones@2020-06-01' = {
name: 'privatelink.file.${environment().suffixes.storage}'
location: 'global'

resource virtualNetworkLink 'virtualNetworkLinks' = {
name: uniqueString(virtualNetwork.name)
location: 'global'
properties: {
registrationEnabled: false
virtualNetwork: {
id: virtualNetwork.id
}
}
}

resource resRecord 'A' = {
name: storageAccount.name
properties: {
ttl: 10
aRecords: [
{
ipv4Address: first(first(privateEndpoint.properties.customDnsConfigs)!.ipAddresses)
}
]
}
}
}

resource virtualNetwork 'Microsoft.Network/virtualNetworks@2023-04-01' = {
name: virtualNetworkName
location: location
properties: {
addressSpace: {
addressPrefixes: [
addressPrefix
]
}
subnets: [
{
name: 'defaultSubnet'
properties: {
addressPrefix: cidrSubnet(addressPrefix, 24, 0)
serviceEndpoints: [
{
service: 'Microsoft.Storage'
}
]
delegations: [
{
name: 'Microsoft.ContainerInstance.containerGroups'
properties: {
serviceName: 'Microsoft.ContainerInstance/containerGroups'
}
}
]
}
}
{
name: 'peSubnet'
properties: {
addressPrefix: cidrSubnet(addressPrefix, 24, 1)
}
}
]
}
}

@description('The principal ID of the created Managed Identity.')
output managedIdentityPrincipalId string = managedIdentity.properties.principalId

@description('The resource ID of the created Managed Identity.')
output managedIdentityResourceId string = managedIdentity.id

@description('The resource ID of the created storage account.')
output storageAccountResourceId string = storageAccount.id

@description('The resource ID of the created Virtual Network Subnet.')
output subnetResourceId string = virtualNetwork.properties.subnets[0].id
Original file line number Diff line number Diff line change
@@ -0,0 +1,73 @@
targetScope = 'subscription'

metadata name = 'Using Private Endpoint'
metadata description = 'This instance deploys the module with access to a private endpoint.'

// ========== //
// Parameters //
// ========== //

@description('Optional. The name of the resource group to deploy for testing purposes.')
@maxLength(90)
param resourceGroupName string = 'avm-${namePrefix}-resources.deploymentscripts-${serviceShort}-rg'

@description('Optional. The location to deploy resources to.')
param resourceLocation string = deployment().location

@description('Optional. A short identifier for the kind of deployment. Should be kept short to not run into resource-name length-constraints.')
param serviceShort string = 'rdspe'

@description('Optional. A token to inject into the name of each resource.')
param namePrefix string = '#_namePrefix_#'

// ============ //
// Dependencies //
// ============ //

// General resources
// =================
resource resourceGroup 'Microsoft.Resources/resourceGroups@2021-04-01' = {
name: resourceGroupName
location: resourceLocation
}

module nestedDependencies 'dependencies.bicep' = {
scope: resourceGroup
name: '${uniqueString(deployment().name, resourceLocation)}-nestedDependencies'
params: {
managedIdentityName: 'dep-${namePrefix}-msi-${serviceShort}'
storageAccountName: 'dep${namePrefix}sa${serviceShort}'
virtualNetworkName: 'dep-${namePrefix}-vnet-${serviceShort}'
privateEndpointName: 'dep-${namePrefix}-pe-${serviceShort}'
location: resourceLocation
}
}

// ============== //
// Test Execution //
// ============== //

module testDeployment '../../../main.bicep' = {
scope: resourceGroup
name: '${uniqueString(deployment().name, resourceLocation)}-test-${serviceShort}'
params: {
name: '${namePrefix}${serviceShort}001'
location: resourceLocation
azCliVersion: '2.9.1'
kind: 'AzureCLI'
retentionInterval: 'P1D'
cleanupPreference: 'Always'
subnetResourceIds: [
nestedDependencies.outputs.subnetResourceId
]
managedIdentities: {
userAssignedResourcesIds: [
nestedDependencies.outputs.managedIdentityResourceId
]
}
timeout: 'PT1H'
runOnce: true
scriptContent: 'echo \'AVM Deployment Script test!\''
storageAccountResourceId: nestedDependencies.outputs.storageAccountResourceId
}
}

0 comments on commit 1533f62

Please sign in to comment.