From a3570237fa64cdb345a29910e1b1b42da55487a4 Mon Sep 17 00:00:00 2001 From: Alexander Sehr Date: Thu, 28 Nov 2024 10:22:36 +0100 Subject: [PATCH] feat: Updated Container-Instance CMK Implementation (#3733) ## Description - Updated Container-Instance CMK Implementation - Implemented AVM-Common-Types Linked to - Update CMK implementations as per https://github.com/Azure/bicep-registry-modules/issues/2842#issuecomment-2423679879 - Docs Update: https://github.com/Azure/Azure-Verified-Modules/pull/1683 - UDT update: https://github.com/Azure/bicep-registry-modules/pull/3724 ## Pipeline Reference | Pipeline | | -------- | | [![avm.res.container-instance.container-group](https://github.com/AlexanderSehr/bicep-registry-modules/actions/workflows/avm.res.container-instance.container-group.yml/badge.svg?branch=users%2Falsehr%2FcmkUpdateContainerInstance&event=workflow_dispatch)](https://github.com/AlexanderSehr/bicep-registry-modules/actions/workflows/avm.res.container-instance.container-group.yml) | ## Type of Change - [ ] 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. - [ ] 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`. - [ ] Update to documentation --- .../container-group/README.md | 167 ++-- .../container-group/main.bicep | 70 +- .../container-group/main.json | 740 +++++++++--------- .../tests/e2e/private/main.test.bicep | 2 +- .../tests/e2e/waf-aligned/main.test.bicep | 4 - .../container-group/version.json | 4 +- 6 files changed, 502 insertions(+), 485 deletions(-) diff --git a/avm/res/container-instance/container-group/README.md b/avm/res/container-instance/container-group/README.md index e73e13b51e..1545fb232b 100644 --- a/avm/res/container-instance/container-group/README.md +++ b/avm/res/container-instance/container-group/README.md @@ -8,6 +8,7 @@ This module deploys a Container Instance Container Group. - [Usage examples](#Usage-examples) - [Parameters](#Parameters) - [Outputs](#Outputs) +- [Cross-referenced modules](#Cross-referenced-modules) - [Data Collection](#Data-Collection) ## Resource Types @@ -65,14 +66,14 @@ module containerGroup 'br/public:avm/res/container-instance/container-group:' } } @@ -113,6 +114,10 @@ module containerGroup 'br/public:avm/res/container-instance/container-group:" } @@ -163,14 +164,14 @@ param containers = [ } } ] +param name = 'cicgmin001' +// Non-required parameters param ipAddressPorts = [ { port: 443 protocol: 'Tcp' } ] -param name = 'cicgmin001' -// Non-required parameters param location = '' ``` @@ -237,6 +238,13 @@ module containerGroup 'br/public:avm/res/container-instance/container-group:' + keyVaultResourceId: '' + userAssignedIdentityResourceId: '' + } ipAddressPorts: [ { port: 80 @@ -247,13 +255,6 @@ module containerGroup 'br/public:avm/res/container-instance/container-group:' - keyVaultResourceId: '' - userAssignedIdentityResourceId: '' - } location: '' lock: { kind: 'CanNotDelete' @@ -330,6 +331,17 @@ module containerGroup 'br/public:avm/res/container-instance/container-group:", + "keyVaultResourceId": "", + "userAssignedIdentityResourceId": "" + } + }, "ipAddressPorts": { "value": [ { @@ -342,17 +354,6 @@ module containerGroup 'br/public:avm/res/container-instance/container-group:", - "keyVaultResourceId": "", - "userAssignedIdentityResourceId": "" - } - }, "location": { "value": "" }, @@ -431,6 +432,13 @@ param containers = [ } } ] +param name = 'cicgencr001' +// Non-required parameters +param customerManagedKey = { + keyName: '' + keyVaultResourceId: '' + userAssignedIdentityResourceId: '' +} param ipAddressPorts = [ { port: 80 @@ -441,13 +449,6 @@ param ipAddressPorts = [ protocol: 'Tcp' } ] -param name = 'cicgencr001' -// Non-required parameters -param customerManagedKey = { - keyName: '' - keyVaultResourceId: '' - userAssignedIdentityResourceId: '' -} param location = '' param lock = { kind: 'CanNotDelete' @@ -533,6 +534,8 @@ module containerGroup 'br/public:avm/res/container-instance/container-group:' lock: { kind: 'CanNotDelete' @@ -635,6 +636,10 @@ module containerGroup 'br/public:avm/res/container-instance/container-group:" }, @@ -745,6 +746,8 @@ param containers = [ } } ] +param name = 'cicgmax001' +// Non-required parameters param ipAddressPorts = [ { port: 80 @@ -755,8 +758,6 @@ param ipAddressPorts = [ protocol: 'Tcp' } ] -param name = 'cicgmax001' -// Non-required parameters param location = '' param lock = { kind: 'CanNotDelete' @@ -838,6 +839,8 @@ module containerGroup 'br/public:avm/res/container-instance/container-group:' lock: { kind: 'CanNotDelete' name: 'myCustomLockName' } - subnetId: '' + subnetResourceId: '' } } ``` @@ -926,6 +927,10 @@ module containerGroup 'br/public:avm/res/container-instance/container-group:" + "subnetResourceId": { + "value": "" } } } @@ -1022,6 +1023,8 @@ param containers = [ } } ] +param name = 'cicgprivate001' +// Non-required parameters param ipAddressPorts = [ { port: 80 @@ -1036,15 +1039,13 @@ param ipAddressPorts = [ protocol: 'Tcp' } ] -param name = 'cicgprivate001' -// Non-required parameters param ipAddressType = 'Private' param location = '' param lock = { kind: 'CanNotDelete' name: 'myCustomLockName' } -param subnetId = '' +param subnetResourceId = '' ``` @@ -1110,6 +1111,8 @@ module containerGroup 'br/public:avm/res/container-instance/container-group:' - lock: { - kind: 'CanNotDelete' - name: 'myCustomLockName' - } tags: { Environment: 'Non-Prod' 'hidden-title': 'This is visible in the resource name' @@ -1197,6 +1194,10 @@ module containerGroup 'br/public:avm/res/container-instance/container-group:" }, - "lock": { - "value": { - "kind": "CanNotDelete", - "name": "myCustomLockName" - } - }, "tags": { "value": { "Environment": "Non-Prod", @@ -1290,6 +1281,8 @@ param containers = [ } } ] +param name = 'cicgwaf001' +// Non-required parameters param ipAddressPorts = [ { port: 80 @@ -1300,13 +1293,7 @@ param ipAddressPorts = [ protocol: 'Tcp' } ] -param name = 'cicgwaf001' -// Non-required parameters param location = '' -param lock = { - kind: 'CanNotDelete' - name: 'myCustomLockName' -} param tags = { Environment: 'Non-Prod' 'hidden-title': 'This is visible in the resource name' @@ -1351,7 +1338,7 @@ param tags = { | [`osType`](#parameter-ostype) | string | The operating system type required by the containers in the container group. - Windows or Linux. | | [`restartPolicy`](#parameter-restartpolicy) | string | Restart policy for all containers within the container group. - Always: Always restart. OnFailure: Restart on failure. Never: Never restart. - Always, OnFailure, Never. | | [`sku`](#parameter-sku) | string | The container group SKU. | -| [`subnetId`](#parameter-subnetid) | string | Resource ID of the subnet. Only specify when ipAddressType is Private. | +| [`subnetResourceId`](#parameter-subnetresourceid) | string | Resource ID of the subnet. Only specify when ipAddressType is Private. | | [`tags`](#parameter-tags) | object | Tags of the resource. | | [`volumes`](#parameter-volumes) | array | Specify if volumes (emptyDir, AzureFileShare or GitRepo) shall be attached to your containergroup. | @@ -1783,7 +1770,7 @@ Name for the container group. Ports to open on the public IP address. Must include all ports assigned on container level. Required if `ipAddressType` is set to `public`. -- Required: Yes +- Required: No - Type: array **Required parameters** @@ -1843,7 +1830,8 @@ The customer managed key definition. | Parameter | Type | Description | | :-- | :-- | :-- | -| [`keyVersion`](#parameter-customermanagedkeykeyversion) | string | The version of the customer managed key to reference for encryption. If not provided, using 'latest'. | +| [`autoRotationEnabled`](#parameter-customermanagedkeyautorotationenabled) | bool | Enable or disable auto-rotating to the latest key version. Default is `true`. If set to `false`, the latest key version at the time of the deployment is used. | +| [`keyVersion`](#parameter-customermanagedkeykeyversion) | string | The version of the customer managed key to reference for encryption. If not provided, using version as per 'autoRotationEnabled' setting. | | [`userAssignedIdentityResourceId`](#parameter-customermanagedkeyuserassignedidentityresourceid) | string | User assigned identity to use when fetching the customer managed key. Required if no system assigned identity is available for use. | ### Parameter: `customerManagedKey.keyName` @@ -1860,9 +1848,16 @@ The resource ID of a key vault to reference a customer managed key for encryptio - Required: Yes - Type: string +### Parameter: `customerManagedKey.autoRotationEnabled` + +Enable or disable auto-rotating to the latest key version. Default is `true`. If set to `false`, the latest key version at the time of the deployment is used. + +- Required: No +- Type: bool + ### Parameter: `customerManagedKey.keyVersion` -The version of the customer managed key to reference for encryption. If not provided, using 'latest'. +The version of the customer managed key to reference for encryption. If not provided, using version as per 'autoRotationEnabled' setting. - Required: No - Type: string @@ -2038,7 +2033,7 @@ The managed identity definition for this resource. | Parameter | Type | Description | | :-- | :-- | :-- | | [`systemAssigned`](#parameter-managedidentitiessystemassigned) | bool | Enables system assigned managed identity on the resource. | -| [`userAssignedResourceIds`](#parameter-managedidentitiesuserassignedresourceids) | array | The resource ID(s) to assign to the resource. | +| [`userAssignedResourceIds`](#parameter-managedidentitiesuserassignedresourceids) | array | The resource ID(s) to assign to the resource. Required if a user assigned identity is used for encryption. | ### Parameter: `managedIdentities.systemAssigned` @@ -2049,7 +2044,7 @@ Enables system assigned managed identity on the resource. ### Parameter: `managedIdentities.userAssignedResourceIds` -The resource ID(s) to assign to the resource. +The resource ID(s) to assign to the resource. Required if a user assigned identity is used for encryption. - Required: No - Type: array @@ -2093,7 +2088,7 @@ The container group SKU. ] ``` -### Parameter: `subnetId` +### Parameter: `subnetResourceId` Resource ID of the subnet. Only specify when ipAddressType is Private. @@ -2125,6 +2120,14 @@ Specify if volumes (emptyDir, AzureFileShare or GitRepo) shall be attached to yo | `resourceId` | string | The resource ID of the container group. | | `systemAssignedMIPrincipalId` | string | The principal ID of the system assigned identity. | +## Cross-referenced modules + +This section gives you an overview of all local-referenced module files (i.e., other modules that are referenced in this module) and all remote-referenced files (i.e., Bicep modules that are referenced from a Bicep Registry or Template Specs). + +| Reference | Type | +| :-- | :-- | +| `br/public:avm/utl/types/avm-common-types:0.4.0` | Remote reference | + ## Data Collection The software may collect information about you and your use of the software and send it to Microsoft. Microsoft may use this information to provide services and improve our products and services. You may turn off the telemetry as described in the [repository](https://aka.ms/avm/telemetry). There are also some features in the software that may enable you and Microsoft to collect data from users of your applications. If you use these features, you must comply with applicable law, including providing appropriate notices to users of your applications together with a copy of Microsoft’s privacy statement. Our privacy statement is located at . You can learn more about data collection and use in the help documentation and our privacy statement. Your use of the software operates as your consent to these practices. diff --git a/avm/res/container-instance/container-group/main.bicep b/avm/res/container-instance/container-group/main.bicep index 2baee0b1d1..6e90154817 100644 --- a/avm/res/container-instance/container-group/main.bicep +++ b/avm/res/container-instance/container-group/main.bicep @@ -6,10 +6,10 @@ metadata owner = 'Azure/module-maintainers' param name string @description('Required. The containers and their respective config within the container group.') -param containers containerType +param containers containerType[] @description('Conditional. Ports to open on the public IP address. Must include all ports assigned on container level. Required if `ipAddressType` is set to `public`.') -param ipAddressPorts ipAddressPortsType +param ipAddressPorts ipAddressPortsType[]? @description('Optional. The operating system type required by the containers in the container group. - Windows or Linux.') param osType string = 'Linux' @@ -30,7 +30,7 @@ param restartPolicy string = 'Always' param ipAddressType string = 'Public' @description('Optional. The image registry credentials by which the container group is created from.') -param imageRegistryCredentials imageRegistryCredentialType +param imageRegistryCredentials imageRegistryCredentialType[]? @description('Optional. Location for all Resources.') param location string = resourceGroup().location @@ -58,16 +58,18 @@ param dnsSearchDomains string? param initContainers array? @description('Optional. Resource ID of the subnet. Only specify when ipAddressType is Private.') -param subnetId string? +param subnetResourceId string? @description('Optional. Specify if volumes (emptyDir, AzureFileShare or GitRepo) shall be attached to your containergroup.') param volumes array? +import { lockType } from 'br/public:avm/utl/types/avm-common-types:0.4.0' @description('Optional. The lock settings of the service.') -param lock lockType +param lock lockType? +import { managedIdentityAllType } from 'br/public:avm/utl/types/avm-common-types:0.4.0' @description('Optional. The managed identity definition for this resource.') -param managedIdentities managedIdentitiesType +param managedIdentities managedIdentityAllType? @description('Optional. Tags of the resource.') param tags object? @@ -82,8 +84,9 @@ param enableTelemetry bool = true ]) param sku string = 'Standard' +import { customerManagedKeyWithAutoRotateType } from 'br/public:avm/utl/types/avm-common-types:0.4.0' @description('Optional. The customer managed key definition.') -param customerManagedKey customerManagedKeyType +param customerManagedKey customerManagedKeyWithAutoRotateType? var formattedUserAssignedIdentities = reduce( map((managedIdentities.?userAssignedResourceIds ?? []), (id) => { '${id}': {} }), @@ -155,7 +158,9 @@ resource containergroup 'Microsoft.ContainerInstance/containerGroups@2023-05-01' keyName: customerManagedKey!.keyName keyVersion: !empty(customerManagedKey.?keyVersion ?? '') ? customerManagedKey!.keyVersion - : last(split(cMKKeyVault::cMKKey.properties.keyUriWithVersion, '/')) + : (customerManagedKey.?autoRotationEnabled ?? true) + ? null + : last(split(cMKKeyVault::cMKKey.properties.keyUriWithVersion, '/')) vaultBaseUrl: cMKKeyVault.properties.vaultUri } : null @@ -170,10 +175,10 @@ resource containergroup 'Microsoft.ContainerInstance/containerGroups@2023-05-01' ports: ipAddressPorts } sku: sku - subnetIds: !empty(subnetId) + subnetIds: !empty(subnetResourceId) ? [ { - id: subnetId + id: subnetResourceId } ] : null @@ -214,7 +219,7 @@ output resourceGroupName string = resourceGroup().name output iPv4Address string = containergroup.properties.ipAddress.ip @description('The principal ID of the system assigned identity.') -output systemAssignedMIPrincipalId string = containergroup.?identity.?principalId ?? '' +output systemAssignedMIPrincipalId string? = containergroup.?identity.?principalId @description('The location the resource was deployed into.') output location string = containergroup.location @@ -223,36 +228,7 @@ output location string = containergroup.location // Definitions // // =============== // -type managedIdentitiesType = { - @description('Optional. Enables system assigned managed identity on the resource.') - systemAssigned: bool? - - @description('Optional. The resource ID(s) to assign to the resource.') - userAssignedResourceIds: string[]? -}? - -type lockType = { - @description('Optional. Specify the name of lock.') - name: string? - - @description('Optional. Specify the type of lock.') - kind: ('CanNotDelete' | 'ReadOnly' | 'None')? -}? - -type customerManagedKeyType = { - @description('Required. The resource ID of a key vault to reference a customer managed key for encryption from.') - keyVaultResourceId: string - - @description('Required. The name of the customer managed key to use for encryption.') - keyName: string - - @description('Optional. The version of the customer managed key to reference for encryption. If not provided, using \'latest\'.') - keyVersion: string? - - @description('Optional. User assigned identity to use when fetching the customer managed key. Required if no system assigned identity is available for use.') - userAssignedIdentityResourceId: string? -}? - +@export() type containerType = { @description('Required. The name of the container instance.') name: string @@ -356,8 +332,9 @@ type containerType = { value: string? }[]? } -}[] +} +@export() type imageRegistryCredentialType = { @description('Required. The Docker image registry server without a protocol such as "http" and "https".') server: string @@ -374,21 +351,24 @@ type imageRegistryCredentialType = { @description('Optional. The password for the private registry.') @secure() password: string? -}[]? +} +@export() type ipAddressPortsType = { @description('Required. The port number exposed on the container instance.') port: int @description('Required. The protocol associated with the port number.') protocol: string -}[] +} // will be removed in future. For more information see https://learn.microsoft.com/en-us/azure/container-instances/container-instances-gpu + +@export() type containerGpuType = { @description('Required. The count of the GPU resource.') count: int @description('Required. The SKU of the GPU resource.') sku: ('K80' | 'P100' | 'V100') -}? +} diff --git a/avm/res/container-instance/container-group/main.json b/avm/res/container-instance/container-group/main.json index 7b1c128ccd..fad260c188 100644 --- a/avm/res/container-instance/container-group/main.json +++ b/avm/res/container-instance/container-group/main.json @@ -5,426 +5,345 @@ "metadata": { "_generator": { "name": "bicep", - "version": "0.30.23.60470", - "templateHash": "14261370383859328082" + "version": "0.31.92.45157", + "templateHash": "11653767368737977029" }, "name": "Container Instances Container Groups", "description": "This module deploys a Container Instance Container Group.", "owner": "Azure/module-maintainers" }, "definitions": { - "managedIdentitiesType": { - "type": "object", - "properties": { - "systemAssigned": { - "type": "bool", - "nullable": true, - "metadata": { - "description": "Optional. Enables system assigned managed identity on the resource." - } - }, - "userAssignedResourceIds": { - "type": "array", - "items": { - "type": "string" - }, - "nullable": true, - "metadata": { - "description": "Optional. The resource ID(s) to assign to the resource." - } - } - }, - "nullable": true - }, - "lockType": { + "containerType": { "type": "object", "properties": { "name": { "type": "string", - "nullable": true, "metadata": { - "description": "Optional. Specify the name of lock." + "description": "Required. The name of the container instance." } }, - "kind": { - "type": "string", - "allowedValues": [ - "CanNotDelete", - "None", - "ReadOnly" - ], - "nullable": true, - "metadata": { - "description": "Optional. Specify the type of lock." - } - } - }, - "nullable": true - }, - "customerManagedKeyType": { - "type": "object", - "properties": { - "keyVaultResourceId": { - "type": "string", - "metadata": { - "description": "Required. The resource ID of a key vault to reference a customer managed key for encryption from." - } - }, - "keyName": { - "type": "string", - "metadata": { - "description": "Required. The name of the customer managed key to use for encryption." - } - }, - "keyVersion": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The version of the customer managed key to reference for encryption. If not provided, using 'latest'." - } - }, - "userAssignedIdentityResourceId": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. User assigned identity to use when fetching the customer managed key. Required if no system assigned identity is available for use." - } - } - }, - "nullable": true - }, - "containerType": { - "type": "array", - "items": { - "type": "object", "properties": { - "name": { - "type": "string", - "metadata": { - "description": "Required. The name of the container instance." - } - }, + "type": "object", "properties": { - "type": "object", - "properties": { - "image": { - "type": "string", - "metadata": { - "description": "Required. The name of the container source image." - } - }, - "livenessProbe": { + "image": { + "type": "string", + "metadata": { + "description": "Required. The name of the container source image." + } + }, + "livenessProbe": { + "type": "object", + "properties": {}, + "nullable": true, + "metadata": { + "description": "Optional. The liveness probe." + } + }, + "ports": { + "type": "array", + "items": { "type": "object", - "properties": {}, - "nullable": true, - "metadata": { - "description": "Optional. The liveness probe." + "properties": { + "port": { + "type": "int", + "metadata": { + "description": "Required. The port number exposed on the container instance." + } + }, + "protocol": { + "type": "string", + "metadata": { + "description": "Required. The protocol associated with the port number." + } + } } }, - "ports": { - "type": "array", - "items": { + "nullable": true, + "metadata": { + "description": "Optional. The exposed ports on the container instance." + } + }, + "resources": { + "type": "object", + "properties": { + "requests": { "type": "object", "properties": { - "port": { + "cpu": { "type": "int", "metadata": { - "description": "Required. The port number exposed on the container instance." + "description": "Required. The CPU request of this container instance." } }, - "protocol": { - "type": "string", + "gpu": { + "$ref": "#/definitions/containerGpuType", + "nullable": true, + "metadata": { + "description": "Optional. The GPU request of this container instance." + } + }, + "memoryInGB": { + "type": "int", + "nullable": true, "metadata": { - "description": "Required. The protocol associated with the port number." + "description": "Optional. The memory request in GB of this container instance. To specify a decimal value, use the json() function." } } + }, + "metadata": { + "description": "Required. The resource requests of this container instance." } }, - "nullable": true, - "metadata": { - "description": "Optional. The exposed ports on the container instance." - } - }, - "resources": { - "type": "object", - "properties": { - "requests": { - "type": "object", - "properties": { - "cpu": { - "type": "int", - "metadata": { - "description": "Required. The CPU request of this container instance." - } - }, - "gpu": { - "$ref": "#/definitions/containerGpuType", - "nullable": true, - "metadata": { - "description": "Optional. The GPU request of this container instance." - } - }, - "memoryInGB": { - "type": "int", - "nullable": true, - "metadata": { - "description": "Optional. The memory request in GB of this container instance. To specify a decimal value, use the json() function." - } + "limits": { + "type": "object", + "properties": { + "cpu": { + "type": "int", + "metadata": { + "description": "Required. The CPU limit of this container instance." } }, - "metadata": { - "description": "Required. The resource requests of this container instance." - } - }, - "limits": { - "type": "object", - "properties": { - "cpu": { - "type": "int", - "metadata": { - "description": "Required. The CPU limit of this container instance." - } - }, - "gpu": { - "$ref": "#/definitions/containerGpuType", - "nullable": true, - "metadata": { - "description": "Optional. The GPU limit of this container instance." - } - }, - "memoryInGB": { - "type": "int", - "nullable": true, - "metadata": { - "description": "Optional. The memory limit in GB of this container instance. To specify a decimal value, use the json() function." - } + "gpu": { + "$ref": "#/definitions/containerGpuType", + "nullable": true, + "metadata": { + "description": "Optional. The GPU limit of this container instance." } }, - "nullable": true, - "metadata": { - "description": "Optional. The resource limits of this container instance." - } - }, - "securityContext": { - "type": "object", - "properties": { - "allowPrivilegeEscalation": { - "type": "bool", - "nullable": true, - "metadata": { - "description": "Optional. Whether privilege escalation is allowed for the container." - } - }, - "capabilities": { - "type": "object", - "properties": { - "add": { - "type": "array", - "items": { - "type": "string" - }, - "nullable": true, - "metadata": { - "description": "Optional. The list of capabilities to add." - } - }, - "drop": { - "type": "array", - "items": { - "type": "string" - }, - "nullable": true, - "metadata": { - "description": "Optional. The list of capabilities to drop." - } - } - }, - "nullable": true, - "metadata": { - "description": "Optional. The capabilities to add or drop for the container." - } - }, - "privileged": { - "type": "bool", - "nullable": true, - "metadata": { - "description": "Optional. Whether the container is run in privileged mode." - } - }, - "runAsGroup": { - "type": "int", - "nullable": true, - "metadata": { - "description": "Optional. The GID to run the container as." - } - }, - "runAsUser": { - "type": "int", - "nullable": true, - "metadata": { - "description": "Optional. The UID to run the container as." - } - }, - "seccompProfile": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The seccomp profile to use for the container." - } + "memoryInGB": { + "type": "int", + "nullable": true, + "metadata": { + "description": "Optional. The memory limit in GB of this container instance. To specify a decimal value, use the json() function." } - }, - "nullable": true, - "metadata": { - "description": "Optional. The security context of the container instance." } + }, + "nullable": true, + "metadata": { + "description": "Optional. The resource limits of this container instance." } }, - "metadata": { - "description": "Required. The resource requirements of the container instance." - } - }, - "volumeMounts": { - "type": "array", - "items": { + "securityContext": { "type": "object", "properties": { - "name": { - "type": "string", + "allowPrivilegeEscalation": { + "type": "bool", + "nullable": true, "metadata": { - "description": "Required. The name of the volume mount." + "description": "Optional. Whether privilege escalation is allowed for the container." } }, - "mountPath": { - "type": "string", + "capabilities": { + "type": "object", + "properties": { + "add": { + "type": "array", + "items": { + "type": "string" + }, + "nullable": true, + "metadata": { + "description": "Optional. The list of capabilities to add." + } + }, + "drop": { + "type": "array", + "items": { + "type": "string" + }, + "nullable": true, + "metadata": { + "description": "Optional. The list of capabilities to drop." + } + } + }, + "nullable": true, "metadata": { - "description": "Required. The path within the container where the volume should be mounted. Must not contain colon (:)." + "description": "Optional. The capabilities to add or drop for the container." } }, - "readOnly": { + "privileged": { "type": "bool", "nullable": true, "metadata": { - "description": "Optional. The flag indicating whether the volume mount is read-only." + "description": "Optional. Whether the container is run in privileged mode." } - } - } - }, - "nullable": true, - "metadata": { - "description": "Optional. The volume mounts within the container instance." - } - }, - "command": { - "type": "array", - "items": { - "type": "string" - }, - "nullable": true, - "metadata": { - "description": "Optional. The command to execute within the container instance." - } - }, - "environmentVariables": { - "type": "array", - "items": { - "type": "object", - "properties": { - "name": { - "type": "string", + }, + "runAsGroup": { + "type": "int", + "nullable": true, "metadata": { - "description": "Required. The name of the environment variable." + "description": "Optional. The GID to run the container as." } }, - "secureValue": { - "type": "securestring", + "runAsUser": { + "type": "int", "nullable": true, "metadata": { - "description": "Optional. The value of the secure environment variable." + "description": "Optional. The UID to run the container as." } }, - "value": { + "seccompProfile": { "type": "string", "nullable": true, "metadata": { - "description": "Optional. The value of the environment variable." + "description": "Optional. The seccomp profile to use for the container." } } + }, + "nullable": true, + "metadata": { + "description": "Optional. The security context of the container instance." } - }, - "nullable": true, - "metadata": { - "description": "Optional. The environment variables to set in the container instance." } + }, + "metadata": { + "description": "Required. The resource requirements of the container instance." } }, - "metadata": { - "description": "Required. The properties of the container instance." + "volumeMounts": { + "type": "array", + "items": { + "type": "object", + "properties": { + "name": { + "type": "string", + "metadata": { + "description": "Required. The name of the volume mount." + } + }, + "mountPath": { + "type": "string", + "metadata": { + "description": "Required. The path within the container where the volume should be mounted. Must not contain colon (:)." + } + }, + "readOnly": { + "type": "bool", + "nullable": true, + "metadata": { + "description": "Optional. The flag indicating whether the volume mount is read-only." + } + } + } + }, + "nullable": true, + "metadata": { + "description": "Optional. The volume mounts within the container instance." + } + }, + "command": { + "type": "array", + "items": { + "type": "string" + }, + "nullable": true, + "metadata": { + "description": "Optional. The command to execute within the container instance." + } + }, + "environmentVariables": { + "type": "array", + "items": { + "type": "object", + "properties": { + "name": { + "type": "string", + "metadata": { + "description": "Required. The name of the environment variable." + } + }, + "secureValue": { + "type": "securestring", + "nullable": true, + "metadata": { + "description": "Optional. The value of the secure environment variable." + } + }, + "value": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The value of the environment variable." + } + } + } + }, + "nullable": true, + "metadata": { + "description": "Optional. The environment variables to set in the container instance." + } } + }, + "metadata": { + "description": "Required. The properties of the container instance." } } + }, + "metadata": { + "__bicep_export!": true } }, "imageRegistryCredentialType": { - "type": "array", - "items": { - "type": "object", - "properties": { - "server": { - "type": "string", - "metadata": { - "description": "Required. The Docker image registry server without a protocol such as \"http\" and \"https\"." - } - }, - "identity": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The identity for the private registry." - } - }, - "identityUrl": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The identity URL for the private registry." - } - }, - "username": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The username for the private registry." - } - }, - "password": { - "type": "securestring", - "nullable": true, - "metadata": { - "description": "Optional. The password for the private registry." - } + "type": "object", + "properties": { + "server": { + "type": "string", + "metadata": { + "description": "Required. The Docker image registry server without a protocol such as \"http\" and \"https\"." + } + }, + "identity": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The identity for the private registry." + } + }, + "identityUrl": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The identity URL for the private registry." + } + }, + "username": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The username for the private registry." + } + }, + "password": { + "type": "securestring", + "nullable": true, + "metadata": { + "description": "Optional. The password for the private registry." } } }, - "nullable": true + "metadata": { + "__bicep_export!": true + } }, "ipAddressPortsType": { - "type": "array", - "items": { - "type": "object", - "properties": { - "port": { - "type": "int", - "metadata": { - "description": "Required. The port number exposed on the container instance." - } - }, - "protocol": { - "type": "string", - "metadata": { - "description": "Required. The protocol associated with the port number." - } + "type": "object", + "properties": { + "port": { + "type": "int", + "metadata": { + "description": "Required. The port number exposed on the container instance." + } + }, + "protocol": { + "type": "string", + "metadata": { + "description": "Required. The protocol associated with the port number." } } + }, + "metadata": { + "__bicep_export!": true } }, "containerGpuType": { @@ -448,7 +367,111 @@ } } }, - "nullable": true + "metadata": { + "__bicep_export!": true + } + }, + "customerManagedKeyWithAutoRotateType": { + "type": "object", + "properties": { + "keyVaultResourceId": { + "type": "string", + "metadata": { + "description": "Required. The resource ID of a key vault to reference a customer managed key for encryption from." + } + }, + "keyName": { + "type": "string", + "metadata": { + "description": "Required. The name of the customer managed key to use for encryption." + } + }, + "keyVersion": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The version of the customer managed key to reference for encryption. If not provided, using version as per 'autoRotationEnabled' setting." + } + }, + "autoRotationEnabled": { + "type": "bool", + "nullable": true, + "metadata": { + "description": "Optional. Enable or disable auto-rotating to the latest key version. Default is `true`. If set to `false`, the latest key version at the time of the deployment is used." + } + }, + "userAssignedIdentityResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. User assigned identity to use when fetching the customer managed key. Required if no system assigned identity is available for use." + } + } + }, + "metadata": { + "description": "An AVM-aligned type for a customer-managed key. To be used if the resource type supports auto-rotation of the customer-managed key.", + "__bicep_imported_from!": { + "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.4.0" + } + } + }, + "lockType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Specify the name of lock." + } + }, + "kind": { + "type": "string", + "allowedValues": [ + "CanNotDelete", + "None", + "ReadOnly" + ], + "nullable": true, + "metadata": { + "description": "Optional. Specify the type of lock." + } + } + }, + "metadata": { + "description": "An AVM-aligned type for a lock.", + "__bicep_imported_from!": { + "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.4.0" + } + } + }, + "managedIdentityAllType": { + "type": "object", + "properties": { + "systemAssigned": { + "type": "bool", + "nullable": true, + "metadata": { + "description": "Optional. Enables system assigned managed identity on the resource." + } + }, + "userAssignedResourceIds": { + "type": "array", + "items": { + "type": "string" + }, + "nullable": true, + "metadata": { + "description": "Optional. The resource ID(s) to assign to the resource. Required if a user assigned identity is used for encryption." + } + } + }, + "metadata": { + "description": "An AVM-aligned type for a managed identity configuration. To be used if both a system-assigned & user-assigned identities are supported by the resource provider.", + "__bicep_imported_from!": { + "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.4.0" + } + } } }, "parameters": { @@ -459,13 +482,20 @@ } }, "containers": { - "$ref": "#/definitions/containerType", + "type": "array", + "items": { + "$ref": "#/definitions/containerType" + }, "metadata": { "description": "Required. The containers and their respective config within the container group." } }, "ipAddressPorts": { - "$ref": "#/definitions/ipAddressPortsType", + "type": "array", + "items": { + "$ref": "#/definitions/ipAddressPortsType" + }, + "nullable": true, "metadata": { "description": "Conditional. Ports to open on the public IP address. Must include all ports assigned on container level. Required if `ipAddressType` is set to `public`." } @@ -501,7 +531,11 @@ } }, "imageRegistryCredentials": { - "$ref": "#/definitions/imageRegistryCredentialType", + "type": "array", + "items": { + "$ref": "#/definitions/imageRegistryCredentialType" + }, + "nullable": true, "metadata": { "description": "Optional. The image registry credentials by which the container group is created from." } @@ -558,7 +592,7 @@ "description": "Optional. A list of container definitions which will be executed before the application container starts." } }, - "subnetId": { + "subnetResourceId": { "type": "string", "nullable": true, "metadata": { @@ -574,12 +608,14 @@ }, "lock": { "$ref": "#/definitions/lockType", + "nullable": true, "metadata": { "description": "Optional. The lock settings of the service." } }, "managedIdentities": { - "$ref": "#/definitions/managedIdentitiesType", + "$ref": "#/definitions/managedIdentityAllType", + "nullable": true, "metadata": { "description": "Optional. The managed identity definition for this resource." } @@ -610,7 +646,8 @@ } }, "customerManagedKey": { - "$ref": "#/definitions/customerManagedKeyType", + "$ref": "#/definitions/customerManagedKeyWithAutoRotateType", + "nullable": true, "metadata": { "description": "Optional. The customer managed key definition." } @@ -678,7 +715,7 @@ "location": "[parameters('location')]", "identity": "[variables('identity')]", "tags": "[parameters('tags')]", - "properties": "[union(createObject('containers', parameters('containers'), 'encryptionProperties', if(not(empty(parameters('customerManagedKey'))), createObject('identity', if(not(empty(coalesce(tryGet(parameters('customerManagedKey'), 'userAssignedIdentityResourceId'), ''))), extensionResourceId(format('/subscriptions/{0}/resourceGroups/{1}', split(coalesce(tryGet(parameters('customerManagedKey'), 'userAssignedIdentityResourceId'), '//'), '/')[2], split(coalesce(tryGet(parameters('customerManagedKey'), 'userAssignedIdentityResourceId'), '////'), '/')[4]), 'Microsoft.ManagedIdentity/userAssignedIdentities', last(split(coalesce(tryGet(parameters('customerManagedKey'), 'userAssignedIdentityResourceId'), 'dummyMsi'), '/'))), null()), 'keyName', parameters('customerManagedKey').keyName, 'keyVersion', if(not(empty(coalesce(tryGet(parameters('customerManagedKey'), 'keyVersion'), ''))), parameters('customerManagedKey').keyVersion, last(split(reference('cMKKeyVault::cMKKey').keyUriWithVersion, '/'))), 'vaultBaseUrl', reference('cMKKeyVault').vaultUri), null()), 'imageRegistryCredentials', parameters('imageRegistryCredentials'), 'initContainers', parameters('initContainers'), 'restartPolicy', parameters('restartPolicy'), 'osType', parameters('osType'), 'ipAddress', createObject('type', parameters('ipAddressType'), 'autoGeneratedDomainNameLabelScope', if(not(empty(parameters('dnsNameServers'))), parameters('autoGeneratedDomainNameLabelScope'), null()), 'dnsNameLabel', parameters('dnsNameLabel'), 'ports', parameters('ipAddressPorts')), 'sku', parameters('sku'), 'subnetIds', if(not(empty(parameters('subnetId'))), createArray(createObject('id', parameters('subnetId'))), null()), 'volumes', parameters('volumes')), if(not(empty(parameters('dnsNameServers'))), createObject('dnsConfig', createObject('nameServers', parameters('dnsNameServers'), 'searchDomains', parameters('dnsSearchDomains'))), createObject()))]", + "properties": "[union(createObject('containers', parameters('containers'), 'encryptionProperties', if(not(empty(parameters('customerManagedKey'))), createObject('identity', if(not(empty(coalesce(tryGet(parameters('customerManagedKey'), 'userAssignedIdentityResourceId'), ''))), extensionResourceId(format('/subscriptions/{0}/resourceGroups/{1}', split(coalesce(tryGet(parameters('customerManagedKey'), 'userAssignedIdentityResourceId'), '//'), '/')[2], split(coalesce(tryGet(parameters('customerManagedKey'), 'userAssignedIdentityResourceId'), '////'), '/')[4]), 'Microsoft.ManagedIdentity/userAssignedIdentities', last(split(coalesce(tryGet(parameters('customerManagedKey'), 'userAssignedIdentityResourceId'), 'dummyMsi'), '/'))), null()), 'keyName', parameters('customerManagedKey').keyName, 'keyVersion', if(not(empty(coalesce(tryGet(parameters('customerManagedKey'), 'keyVersion'), ''))), parameters('customerManagedKey').keyVersion, if(coalesce(tryGet(parameters('customerManagedKey'), 'autoRotationEnabled'), true()), null(), last(split(reference('cMKKeyVault::cMKKey').keyUriWithVersion, '/')))), 'vaultBaseUrl', reference('cMKKeyVault').vaultUri), null()), 'imageRegistryCredentials', parameters('imageRegistryCredentials'), 'initContainers', parameters('initContainers'), 'restartPolicy', parameters('restartPolicy'), 'osType', parameters('osType'), 'ipAddress', createObject('type', parameters('ipAddressType'), 'autoGeneratedDomainNameLabelScope', if(not(empty(parameters('dnsNameServers'))), parameters('autoGeneratedDomainNameLabelScope'), null()), 'dnsNameLabel', parameters('dnsNameLabel'), 'ports', parameters('ipAddressPorts')), 'sku', parameters('sku'), 'subnetIds', if(not(empty(parameters('subnetResourceId'))), createArray(createObject('id', parameters('subnetResourceId'))), null()), 'volumes', parameters('volumes')), if(not(empty(parameters('dnsNameServers'))), createObject('dnsConfig', createObject('nameServers', parameters('dnsNameServers'), 'searchDomains', parameters('dnsSearchDomains'))), createObject()))]", "dependsOn": [ "cMKKeyVault", "cMKUserAssignedIdentity" @@ -730,10 +767,11 @@ }, "systemAssignedMIPrincipalId": { "type": "string", + "nullable": true, "metadata": { "description": "The principal ID of the system assigned identity." }, - "value": "[coalesce(tryGet(tryGet(reference('containergroup', '2023-05-01', 'full'), 'identity'), 'principalId'), '')]" + "value": "[tryGet(tryGet(reference('containergroup', '2023-05-01', 'full'), 'identity'), 'principalId')]" }, "location": { "type": "string", diff --git a/avm/res/container-instance/container-group/tests/e2e/private/main.test.bicep b/avm/res/container-instance/container-group/tests/e2e/private/main.test.bicep index 2c9dfcfaeb..632fbfb70f 100644 --- a/avm/res/container-instance/container-group/tests/e2e/private/main.test.bicep +++ b/avm/res/container-instance/container-group/tests/e2e/private/main.test.bicep @@ -118,7 +118,7 @@ module testDeployment '../../../main.bicep' = [ port: 8080 } ] - subnetId: nestedDependencies.outputs.subnetResourceId + subnetResourceId: nestedDependencies.outputs.subnetResourceId } } ] diff --git a/avm/res/container-instance/container-group/tests/e2e/waf-aligned/main.test.bicep b/avm/res/container-instance/container-group/tests/e2e/waf-aligned/main.test.bicep index 64d8252a1a..f8d4990a99 100644 --- a/avm/res/container-instance/container-group/tests/e2e/waf-aligned/main.test.bicep +++ b/avm/res/container-instance/container-group/tests/e2e/waf-aligned/main.test.bicep @@ -52,10 +52,6 @@ module testDeployment '../../../main.bicep' = [ params: { location: resourceLocation name: '${namePrefix}${serviceShort}001' - lock: { - kind: 'CanNotDelete' - name: 'myCustomLockName' - } containers: [ { name: '${namePrefix}-az-aci-x-001' diff --git a/avm/res/container-instance/container-group/version.json b/avm/res/container-instance/container-group/version.json index daf1a794d9..76049e1c4a 100644 --- a/avm/res/container-instance/container-group/version.json +++ b/avm/res/container-instance/container-group/version.json @@ -1,7 +1,7 @@ { "$schema": "https://aka.ms/bicep-registry-module-version-file-schema#", - "version": "0.2", + "version": "0.3", "pathFilters": [ "./main.json" ] -} +} \ No newline at end of file