diff --git a/Environments/Todo-Mongo-AKS-LA/abbreviations.json b/Environments/Todo-Mongo-AKS-LA/abbreviations.json new file mode 100644 index 00000000..289a08aa --- /dev/null +++ b/Environments/Todo-Mongo-AKS-LA/abbreviations.json @@ -0,0 +1,136 @@ +{ + "analysisServicesServers": "as", + "apiManagementService": "apim-", + "appConfigurationConfigurationStores": "appcs-", + "appManagedEnvironments": "cae-", + "appContainerApps": "ca-", + "authorizationPolicyDefinitions": "policy-", + "automationAutomationAccounts": "aa-", + "blueprintBlueprints": "bp-", + "blueprintBlueprintsArtifacts": "bpa-", + "cacheRedis": "redis-", + "cdnProfiles": "cdnp-", + "cdnProfilesEndpoints": "cdne-", + "cognitiveServicesAccounts": "cog-", + "cognitiveServicesFormRecognizer": "cog-fr-", + "cognitiveServicesTextAnalytics": "cog-ta-", + "computeAvailabilitySets": "avail-", + "computeCloudServices": "cld-", + "computeDiskEncryptionSets": "des", + "computeDisks": "disk", + "computeDisksOs": "osdisk", + "computeGalleries": "gal", + "computeSnapshots": "snap-", + "computeVirtualMachines": "vm", + "computeVirtualMachineScaleSets": "vmss-", + "containerInstanceContainerGroups": "ci", + "containerRegistryRegistries": "cr", + "containerServiceManagedClusters": "aks-", + "databricksWorkspaces": "dbw-", + "dataFactoryFactories": "adf-", + "dataLakeAnalyticsAccounts": "dla", + "dataLakeStoreAccounts": "dls", + "dataMigrationServices": "dms-", + "dBforMySQLServers": "mysql-", + "dBforPostgreSQLServers": "psql-", + "devicesIotHubs": "iot-", + "devicesProvisioningServices": "provs-", + "devicesProvisioningServicesCertificates": "pcert-", + "documentDBDatabaseAccounts": "cosmos-", + "eventGridDomains": "evgd-", + "eventGridDomainsTopics": "evgt-", + "eventGridEventSubscriptions": "evgs-", + "eventHubNamespaces": "evhns-", + "eventHubNamespacesEventHubs": "evh-", + "hdInsightClustersHadoop": "hadoop-", + "hdInsightClustersHbase": "hbase-", + "hdInsightClustersKafka": "kafka-", + "hdInsightClustersMl": "mls-", + "hdInsightClustersSpark": "spark-", + "hdInsightClustersStorm": "storm-", + "hybridComputeMachines": "arcs-", + "insightsActionGroups": "ag-", + "insightsComponents": "appi-", + "keyVaultVaults": "kv-", + "kubernetesConnectedClusters": "arck", + "kustoClusters": "dec", + "kustoClustersDatabases": "dedb", + "loadTesting": "lt-", + "logicIntegrationAccounts": "ia-", + "logicWorkflows": "logic-", + "machineLearningServicesWorkspaces": "mlw-", + "managedIdentityUserAssignedIdentities": "id-", + "managementManagementGroups": "mg-", + "migrateAssessmentProjects": "migr-", + "networkApplicationGateways": "agw-", + "networkApplicationSecurityGroups": "asg-", + "networkAzureFirewalls": "afw-", + "networkBastionHosts": "bas-", + "networkConnections": "con-", + "networkDnsZones": "dnsz-", + "networkExpressRouteCircuits": "erc-", + "networkFirewallPolicies": "afwp-", + "networkFirewallPoliciesWebApplication": "waf", + "networkFirewallPoliciesRuleGroups": "wafrg", + "networkFrontDoors": "fd-", + "networkFrontdoorWebApplicationFirewallPolicies": "fdfp-", + "networkLoadBalancersExternal": "lbe-", + "networkLoadBalancersInternal": "lbi-", + "networkLoadBalancersInboundNatRules": "rule-", + "networkLocalNetworkGateways": "lgw-", + "networkNatGateways": "ng-", + "networkNetworkInterfaces": "nic-", + "networkNetworkSecurityGroups": "nsg-", + "networkNetworkSecurityGroupsSecurityRules": "nsgsr-", + "networkNetworkWatchers": "nw-", + "networkPrivateDnsZones": "pdnsz-", + "networkPrivateLinkServices": "pl-", + "networkPublicIPAddresses": "pip-", + "networkPublicIPPrefixes": "ippre-", + "networkRouteFilters": "rf-", + "networkRouteTables": "rt-", + "networkRouteTablesRoutes": "udr-", + "networkTrafficManagerProfiles": "traf-", + "networkVirtualNetworkGateways": "vgw-", + "networkVirtualNetworks": "vnet-", + "networkVirtualNetworksSubnets": "snet-", + "networkVirtualNetworksVirtualNetworkPeerings": "peer-", + "networkVirtualWans": "vwan-", + "networkVpnGateways": "vpng-", + "networkVpnGatewaysVpnConnections": "vcn-", + "networkVpnGatewaysVpnSites": "vst-", + "notificationHubsNamespaces": "ntfns-", + "notificationHubsNamespacesNotificationHubs": "ntf-", + "operationalInsightsWorkspaces": "log-", + "portalDashboards": "dash-", + "powerBIDedicatedCapacities": "pbi-", + "purviewAccounts": "pview-", + "recoveryServicesVaults": "rsv-", + "resourcesResourceGroups": "rg-", + "searchSearchServices": "srch-", + "serviceBusNamespaces": "sb-", + "serviceBusNamespacesQueues": "sbq-", + "serviceBusNamespacesTopics": "sbt-", + "serviceEndPointPolicies": "se-", + "serviceFabricClusters": "sf-", + "signalRServiceSignalR": "sigr", + "sqlManagedInstances": "sqlmi-", + "sqlServers": "sql-", + "sqlServersDataWarehouse": "sqldw-", + "sqlServersDatabases": "sqldb-", + "sqlServersDatabasesStretch": "sqlstrdb-", + "storageStorageAccounts": "st", + "storageStorageAccountsVm": "stvm", + "storSimpleManagers": "ssimp", + "streamAnalyticsCluster": "asa-", + "synapseWorkspaces": "syn", + "synapseWorkspacesAnalyticsWorkspaces": "synw", + "synapseWorkspacesSqlPoolsDedicated": "syndp", + "synapseWorkspacesSqlPoolsSpark": "synsp", + "timeSeriesInsightsEnvironments": "tsi-", + "webServerFarms": "plan-", + "webSitesAppService": "app-", + "webSitesAppServiceEnvironment": "ase-", + "webSitesFunctions": "func-", + "webStaticSites": "stapp-" +} \ No newline at end of file diff --git a/Environments/Todo-Mongo-AKS-LA/app/db.bicep b/Environments/Todo-Mongo-AKS-LA/app/db.bicep new file mode 100644 index 00000000..938949c6 --- /dev/null +++ b/Environments/Todo-Mongo-AKS-LA/app/db.bicep @@ -0,0 +1,40 @@ +param accountName string +param location string = resourceGroup().location +param tags object = {} + +param collections array = [ + { + name: 'TodoList' + id: 'TodoList' + shardKey: 'Hash' + indexKey: '_id' + } + { + name: 'TodoItem' + id: 'TodoItem' + shardKey: 'Hash' + indexKey: '_id' + } +] +param databaseName string = '' +param keyVaultName string + +// Because databaseName is optional in main.bicep, we make sure the database name is set here. +var defaultDatabaseName = 'Todo' +var actualDatabaseName = !empty(databaseName) ? databaseName : defaultDatabaseName + +module cosmos '../core/database/cosmos/mongo/cosmos-mongo-db.bicep' = { + name: 'cosmos-mongo' + params: { + accountName: accountName + databaseName: actualDatabaseName + location: location + collections: collections + keyVaultName: keyVaultName + tags: tags + } +} + +output connectionStringKey string = cosmos.outputs.connectionStringKey +output databaseName string = cosmos.outputs.databaseName +output endpoint string = cosmos.outputs.endpoint diff --git a/Environments/Todo-Mongo-AKS-LA/azuredeploy.json b/Environments/Todo-Mongo-AKS-LA/azuredeploy.json new file mode 100644 index 00000000..fb7cf37c --- /dev/null +++ b/Environments/Todo-Mongo-AKS-LA/azuredeploy.json @@ -0,0 +1,865 @@ +{ + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "contentVersion": "1.0.0.0", + "metadata": { + "_generator": { + "name": "bicep", + "version": "0.26.170.59819", + "templateHash": "8189193153050722730" + } + }, + "parameters": { + "environmentName": { + "type": "string", + "minLength": 1, + "maxLength": 64, + "metadata": { + "description": "Name of the the environment which is used to generate a short unique hash used in all resources." + } + }, + "location": { + "type": "string", + "defaultValue": "[resourceGroup().location]", + "minLength": 1, + "metadata": { + "description": "Primary location for all resources" + } + }, + "cosmosAccountName": { + "type": "string", + "defaultValue": "" + }, + "cosmosDatabaseName": { + "type": "string", + "defaultValue": "" + }, + "keyVaultName": { + "type": "string", + "defaultValue": "" + }, + "principalId": { + "type": "string", + "defaultValue": "" + }, + "aksClusterIdentityObjectId": { + "type": "string" + }, + "configStoreName": { + "type": "string", + "defaultValue": "" + }, + "contentType": { + "type": "string", + "defaultValue": "", + "metadata": { + "description": "Specifies the content type of the key-value resources. For feature flag, the value should be application/vnd.microsoft.appconfig.ff+json;charset=utf-8. For Key Value reference, the value should be application/vnd.microsoft.appconfig.keyvaultref+json;charset=utf-8. Otherwise, it's optional." + } + } + }, + "variables": { + "$fxv#0": { + "analysisServicesServers": "as", + "apiManagementService": "apim-", + "appConfigurationConfigurationStores": "appcs-", + "appManagedEnvironments": "cae-", + "appContainerApps": "ca-", + "authorizationPolicyDefinitions": "policy-", + "automationAutomationAccounts": "aa-", + "blueprintBlueprints": "bp-", + "blueprintBlueprintsArtifacts": "bpa-", + "cacheRedis": "redis-", + "cdnProfiles": "cdnp-", + "cdnProfilesEndpoints": "cdne-", + "cognitiveServicesAccounts": "cog-", + "cognitiveServicesFormRecognizer": "cog-fr-", + "cognitiveServicesTextAnalytics": "cog-ta-", + "computeAvailabilitySets": "avail-", + "computeCloudServices": "cld-", + "computeDiskEncryptionSets": "des", + "computeDisks": "disk", + "computeDisksOs": "osdisk", + "computeGalleries": "gal", + "computeSnapshots": "snap-", + "computeVirtualMachines": "vm", + "computeVirtualMachineScaleSets": "vmss-", + "containerInstanceContainerGroups": "ci", + "containerRegistryRegistries": "cr", + "containerServiceManagedClusters": "aks-", + "databricksWorkspaces": "dbw-", + "dataFactoryFactories": "adf-", + "dataLakeAnalyticsAccounts": "dla", + "dataLakeStoreAccounts": "dls", + "dataMigrationServices": "dms-", + "dBforMySQLServers": "mysql-", + "dBforPostgreSQLServers": "psql-", + "devicesIotHubs": "iot-", + "devicesProvisioningServices": "provs-", + "devicesProvisioningServicesCertificates": "pcert-", + "documentDBDatabaseAccounts": "cosmos-", + "eventGridDomains": "evgd-", + "eventGridDomainsTopics": "evgt-", + "eventGridEventSubscriptions": "evgs-", + "eventHubNamespaces": "evhns-", + "eventHubNamespacesEventHubs": "evh-", + "hdInsightClustersHadoop": "hadoop-", + "hdInsightClustersHbase": "hbase-", + "hdInsightClustersKafka": "kafka-", + "hdInsightClustersMl": "mls-", + "hdInsightClustersSpark": "spark-", + "hdInsightClustersStorm": "storm-", + "hybridComputeMachines": "arcs-", + "insightsActionGroups": "ag-", + "insightsComponents": "appi-", + "keyVaultVaults": "kv-", + "kubernetesConnectedClusters": "arck", + "kustoClusters": "dec", + "kustoClustersDatabases": "dedb", + "loadTesting": "lt-", + "logicIntegrationAccounts": "ia-", + "logicWorkflows": "logic-", + "machineLearningServicesWorkspaces": "mlw-", + "managedIdentityUserAssignedIdentities": "id-", + "managementManagementGroups": "mg-", + "migrateAssessmentProjects": "migr-", + "networkApplicationGateways": "agw-", + "networkApplicationSecurityGroups": "asg-", + "networkAzureFirewalls": "afw-", + "networkBastionHosts": "bas-", + "networkConnections": "con-", + "networkDnsZones": "dnsz-", + "networkExpressRouteCircuits": "erc-", + "networkFirewallPolicies": "afwp-", + "networkFirewallPoliciesWebApplication": "waf", + "networkFirewallPoliciesRuleGroups": "wafrg", + "networkFrontDoors": "fd-", + "networkFrontdoorWebApplicationFirewallPolicies": "fdfp-", + "networkLoadBalancersExternal": "lbe-", + "networkLoadBalancersInternal": "lbi-", + "networkLoadBalancersInboundNatRules": "rule-", + "networkLocalNetworkGateways": "lgw-", + "networkNatGateways": "ng-", + "networkNetworkInterfaces": "nic-", + "networkNetworkSecurityGroups": "nsg-", + "networkNetworkSecurityGroupsSecurityRules": "nsgsr-", + "networkNetworkWatchers": "nw-", + "networkPrivateDnsZones": "pdnsz-", + "networkPrivateLinkServices": "pl-", + "networkPublicIPAddresses": "pip-", + "networkPublicIPPrefixes": "ippre-", + "networkRouteFilters": "rf-", + "networkRouteTables": "rt-", + "networkRouteTablesRoutes": "udr-", + "networkTrafficManagerProfiles": "traf-", + "networkVirtualNetworkGateways": "vgw-", + "networkVirtualNetworks": "vnet-", + "networkVirtualNetworksSubnets": "snet-", + "networkVirtualNetworksVirtualNetworkPeerings": "peer-", + "networkVirtualWans": "vwan-", + "networkVpnGateways": "vpng-", + "networkVpnGatewaysVpnConnections": "vcn-", + "networkVpnGatewaysVpnSites": "vst-", + "notificationHubsNamespaces": "ntfns-", + "notificationHubsNamespacesNotificationHubs": "ntf-", + "operationalInsightsWorkspaces": "log-", + "portalDashboards": "dash-", + "powerBIDedicatedCapacities": "pbi-", + "purviewAccounts": "pview-", + "recoveryServicesVaults": "rsv-", + "resourcesResourceGroups": "rg-", + "searchSearchServices": "srch-", + "serviceBusNamespaces": "sb-", + "serviceBusNamespacesQueues": "sbq-", + "serviceBusNamespacesTopics": "sbt-", + "serviceEndPointPolicies": "se-", + "serviceFabricClusters": "sf-", + "signalRServiceSignalR": "sigr", + "sqlManagedInstances": "sqlmi-", + "sqlServers": "sql-", + "sqlServersDataWarehouse": "sqldw-", + "sqlServersDatabases": "sqldb-", + "sqlServersDatabasesStretch": "sqlstrdb-", + "storageStorageAccounts": "st", + "storageStorageAccountsVm": "stvm", + "storSimpleManagers": "ssimp", + "streamAnalyticsCluster": "asa-", + "synapseWorkspaces": "syn", + "synapseWorkspacesAnalyticsWorkspaces": "synw", + "synapseWorkspacesSqlPoolsDedicated": "syndp", + "synapseWorkspacesSqlPoolsSpark": "synsp", + "timeSeriesInsightsEnvironments": "tsi-", + "webServerFarms": "plan-", + "webSitesAppService": "app-", + "webSitesAppServiceEnvironment": "ase-", + "webSitesFunctions": "func-", + "webStaticSites": "stapp-" + }, + "abbrs": "[variables('$fxv#0')]", + "resourceToken": "[toLower(uniqueString(subscription().id, parameters('environmentName'), parameters('location')))]", + "tags": { + "azd-env-name": "[parameters('environmentName')]" + } + }, + "resources": [ + { + "type": "Microsoft.AppConfiguration/configurationStores", + "apiVersion": "2021-10-01-preview", + "name": "[if(not(empty(parameters('configStoreName'))), parameters('configStoreName'), format('{0}{1}', variables('abbrs').appConfigurationConfigurationStores, variables('resourceToken')))]", + "location": "[parameters('location')]", + "sku": { + "name": "standard" + } + }, + { + "type": "Microsoft.AppConfiguration/configurationStores/keyValues", + "apiVersion": "2021-10-01-preview", + "name": "[format('{0}/{1}', if(not(empty(parameters('configStoreName'))), parameters('configStoreName'), format('{0}{1}', variables('abbrs').appConfigurationConfigurationStores, variables('resourceToken'))), 'AZURE_COSMOS_CONNECTION_STRING_KEY')]", + "properties": { + "value": "[reference(resourceId('Microsoft.Resources/deployments', 'cosmos'), '2022-09-01').outputs.connectionStringKey.value]", + "contentType": "[parameters('contentType')]", + "tags": "[variables('tags')]" + }, + "dependsOn": [ + "[resourceId('Microsoft.AppConfiguration/configurationStores', if(not(empty(parameters('configStoreName'))), parameters('configStoreName'), format('{0}{1}', variables('abbrs').appConfigurationConfigurationStores, variables('resourceToken'))))]", + "[resourceId('Microsoft.Resources/deployments', 'cosmos')]" + ] + }, + { + "type": "Microsoft.AppConfiguration/configurationStores/keyValues", + "apiVersion": "2021-10-01-preview", + "name": "[format('{0}/{1}', if(not(empty(parameters('configStoreName'))), parameters('configStoreName'), format('{0}{1}', variables('abbrs').appConfigurationConfigurationStores, variables('resourceToken'))), 'AZURE_COSMOS_DATABASE_NAME')]", + "properties": { + "value": "[reference(resourceId('Microsoft.Resources/deployments', 'cosmos'), '2022-09-01').outputs.databaseName.value]", + "contentType": "[parameters('contentType')]", + "tags": "[variables('tags')]" + }, + "dependsOn": [ + "[resourceId('Microsoft.AppConfiguration/configurationStores', if(not(empty(parameters('configStoreName'))), parameters('configStoreName'), format('{0}{1}', variables('abbrs').appConfigurationConfigurationStores, variables('resourceToken'))))]", + "[resourceId('Microsoft.Resources/deployments', 'cosmos')]" + ] + }, + { + "type": "Microsoft.AppConfiguration/configurationStores/keyValues", + "apiVersion": "2021-10-01-preview", + "name": "[format('{0}/{1}', if(not(empty(parameters('configStoreName'))), parameters('configStoreName'), format('{0}{1}', variables('abbrs').appConfigurationConfigurationStores, variables('resourceToken'))), 'AZURE_KEY_VAULT_ENDPOINT')]", + "properties": { + "value": "[reference(resourceId('Microsoft.Resources/deployments', 'keyvault'), '2022-09-01').outputs.endpoint.value]", + "contentType": "[parameters('contentType')]", + "tags": "[variables('tags')]" + }, + "dependsOn": [ + "[resourceId('Microsoft.AppConfiguration/configurationStores', if(not(empty(parameters('configStoreName'))), parameters('configStoreName'), format('{0}{1}', variables('abbrs').appConfigurationConfigurationStores, variables('resourceToken'))))]", + "[resourceId('Microsoft.Resources/deployments', 'keyvault')]" + ] + }, + { + "type": "Microsoft.Resources/deployments", + "apiVersion": "2022-09-01", + "name": "cosmos", + "properties": { + "expressionEvaluationOptions": { + "scope": "inner" + }, + "mode": "Incremental", + "parameters": { + "accountName": "[if(not(empty(parameters('cosmosAccountName'))), createObject('value', parameters('cosmosAccountName')), createObject('value', format('{0}{1}', variables('abbrs').documentDBDatabaseAccounts, variables('resourceToken'))))]", + "databaseName": { + "value": "[parameters('cosmosDatabaseName')]" + }, + "location": { + "value": "[parameters('location')]" + }, + "tags": { + "value": "[variables('tags')]" + }, + "keyVaultName": { + "value": "[reference(resourceId('Microsoft.Resources/deployments', 'keyvault'), '2022-09-01').outputs.name.value]" + } + }, + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "contentVersion": "1.0.0.0", + "metadata": { + "_generator": { + "name": "bicep", + "version": "0.26.170.59819", + "templateHash": "11074299330608515845" + } + }, + "parameters": { + "accountName": { + "type": "string" + }, + "location": { + "type": "string", + "defaultValue": "[resourceGroup().location]" + }, + "tags": { + "type": "object", + "defaultValue": {} + }, + "collections": { + "type": "array", + "defaultValue": [ + { + "name": "TodoList", + "id": "TodoList", + "shardKey": "Hash", + "indexKey": "_id" + }, + { + "name": "TodoItem", + "id": "TodoItem", + "shardKey": "Hash", + "indexKey": "_id" + } + ] + }, + "databaseName": { + "type": "string", + "defaultValue": "" + }, + "keyVaultName": { + "type": "string" + } + }, + "variables": { + "defaultDatabaseName": "Todo", + "actualDatabaseName": "[if(not(empty(parameters('databaseName'))), parameters('databaseName'), variables('defaultDatabaseName'))]" + }, + "resources": [ + { + "type": "Microsoft.Resources/deployments", + "apiVersion": "2022-09-01", + "name": "cosmos-mongo", + "properties": { + "expressionEvaluationOptions": { + "scope": "inner" + }, + "mode": "Incremental", + "parameters": { + "accountName": { + "value": "[parameters('accountName')]" + }, + "databaseName": { + "value": "[variables('actualDatabaseName')]" + }, + "location": { + "value": "[parameters('location')]" + }, + "collections": { + "value": "[parameters('collections')]" + }, + "keyVaultName": { + "value": "[parameters('keyVaultName')]" + }, + "tags": { + "value": "[parameters('tags')]" + } + }, + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "contentVersion": "1.0.0.0", + "metadata": { + "_generator": { + "name": "bicep", + "version": "0.26.170.59819", + "templateHash": "3051764932488625981" + }, + "description": "Creates an Azure Cosmos DB for MongoDB account with a database." + }, + "parameters": { + "accountName": { + "type": "string" + }, + "databaseName": { + "type": "string" + }, + "location": { + "type": "string", + "defaultValue": "[resourceGroup().location]" + }, + "tags": { + "type": "object", + "defaultValue": {} + }, + "collections": { + "type": "array", + "defaultValue": [] + }, + "connectionStringKey": { + "type": "string", + "defaultValue": "AZURE-COSMOS-CONNECTION-STRING" + }, + "keyVaultName": { + "type": "string" + } + }, + "resources": [ + { + "copy": { + "name": "list", + "count": "[length(parameters('collections'))]" + }, + "type": "Microsoft.DocumentDB/databaseAccounts/mongodbDatabases/collections", + "apiVersion": "2022-08-15", + "name": "[format('{0}/{1}/{2}', split(format('{0}/{1}', parameters('accountName'), parameters('databaseName')), '/')[0], split(format('{0}/{1}', parameters('accountName'), parameters('databaseName')), '/')[1], parameters('collections')[copyIndex()].name)]", + "properties": { + "resource": { + "id": "[parameters('collections')[copyIndex()].id]", + "shardKey": { + "_id": "[parameters('collections')[copyIndex()].shardKey]" + }, + "indexes": [ + { + "key": { + "keys": [ + "[parameters('collections')[copyIndex()].indexKey]" + ] + } + } + ] + } + }, + "dependsOn": [ + "[resourceId('Microsoft.DocumentDB/databaseAccounts/mongodbDatabases', split(format('{0}/{1}', parameters('accountName'), parameters('databaseName')), '/')[0], split(format('{0}/{1}', parameters('accountName'), parameters('databaseName')), '/')[1])]" + ] + }, + { + "type": "Microsoft.DocumentDB/databaseAccounts/mongodbDatabases", + "apiVersion": "2022-08-15", + "name": "[format('{0}/{1}', parameters('accountName'), parameters('databaseName'))]", + "tags": "[parameters('tags')]", + "properties": { + "resource": { + "id": "[parameters('databaseName')]" + } + }, + "dependsOn": [ + "[resourceId('Microsoft.Resources/deployments', 'cosmos-mongo-account')]" + ] + }, + { + "type": "Microsoft.Resources/deployments", + "apiVersion": "2022-09-01", + "name": "cosmos-mongo-account", + "properties": { + "expressionEvaluationOptions": { + "scope": "inner" + }, + "mode": "Incremental", + "parameters": { + "name": { + "value": "[parameters('accountName')]" + }, + "location": { + "value": "[parameters('location')]" + }, + "keyVaultName": { + "value": "[parameters('keyVaultName')]" + }, + "tags": { + "value": "[parameters('tags')]" + }, + "connectionStringKey": { + "value": "[parameters('connectionStringKey')]" + } + }, + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "contentVersion": "1.0.0.0", + "metadata": { + "_generator": { + "name": "bicep", + "version": "0.26.170.59819", + "templateHash": "4693794629197446458" + }, + "description": "Creates an Azure Cosmos DB for MongoDB account." + }, + "parameters": { + "name": { + "type": "string" + }, + "location": { + "type": "string", + "defaultValue": "[resourceGroup().location]" + }, + "tags": { + "type": "object", + "defaultValue": {} + }, + "keyVaultName": { + "type": "string" + }, + "connectionStringKey": { + "type": "string", + "defaultValue": "AZURE-COSMOS-CONNECTION-STRING" + } + }, + "resources": [ + { + "type": "Microsoft.Resources/deployments", + "apiVersion": "2022-09-01", + "name": "cosmos-account", + "properties": { + "expressionEvaluationOptions": { + "scope": "inner" + }, + "mode": "Incremental", + "parameters": { + "name": { + "value": "[parameters('name')]" + }, + "location": { + "value": "[parameters('location')]" + }, + "connectionStringKey": { + "value": "[parameters('connectionStringKey')]" + }, + "keyVaultName": { + "value": "[parameters('keyVaultName')]" + }, + "kind": { + "value": "MongoDB" + }, + "tags": { + "value": "[parameters('tags')]" + } + }, + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "contentVersion": "1.0.0.0", + "metadata": { + "_generator": { + "name": "bicep", + "version": "0.26.170.59819", + "templateHash": "10034279666465122994" + }, + "description": "Creates an Azure Cosmos DB account." + }, + "parameters": { + "name": { + "type": "string" + }, + "location": { + "type": "string", + "defaultValue": "[resourceGroup().location]" + }, + "tags": { + "type": "object", + "defaultValue": {} + }, + "connectionStringKey": { + "type": "string", + "defaultValue": "AZURE-COSMOS-CONNECTION-STRING" + }, + "keyVaultName": { + "type": "string" + }, + "kind": { + "type": "string", + "allowedValues": [ + "GlobalDocumentDB", + "MongoDB", + "Parse" + ] + } + }, + "resources": [ + { + "type": "Microsoft.DocumentDB/databaseAccounts", + "apiVersion": "2022-08-15", + "name": "[parameters('name')]", + "kind": "[parameters('kind')]", + "location": "[parameters('location')]", + "tags": "[parameters('tags')]", + "properties": { + "consistencyPolicy": { + "defaultConsistencyLevel": "Session" + }, + "locations": [ + { + "locationName": "[parameters('location')]", + "failoverPriority": 0, + "isZoneRedundant": false + } + ], + "databaseAccountOfferType": "Standard", + "enableAutomaticFailover": false, + "enableMultipleWriteLocations": false, + "apiProperties": "[if(equals(parameters('kind'), 'MongoDB'), createObject('serverVersion', '4.2'), createObject())]", + "capabilities": [ + { + "name": "EnableServerless" + } + ], + "disableLocalAuth": true + } + }, + { + "type": "Microsoft.KeyVault/vaults/secrets", + "apiVersion": "2022-07-01", + "name": "[format('{0}/{1}', parameters('keyVaultName'), parameters('connectionStringKey'))]", + "properties": { + "value": "[listConnectionStrings(resourceId('Microsoft.DocumentDB/databaseAccounts', parameters('name')), '2022-08-15').connectionStrings[0].connectionString]" + }, + "dependsOn": [ + "[resourceId('Microsoft.DocumentDB/databaseAccounts', parameters('name'))]" + ] + } + ], + "outputs": { + "connectionStringKey": { + "type": "string", + "value": "[parameters('connectionStringKey')]" + }, + "endpoint": { + "type": "string", + "value": "[reference(resourceId('Microsoft.DocumentDB/databaseAccounts', parameters('name')), '2022-08-15').documentEndpoint]" + }, + "id": { + "type": "string", + "value": "[resourceId('Microsoft.DocumentDB/databaseAccounts', parameters('name'))]" + }, + "name": { + "type": "string", + "value": "[parameters('name')]" + } + } + } + } + } + ], + "outputs": { + "connectionStringKey": { + "type": "string", + "value": "[reference(resourceId('Microsoft.Resources/deployments', 'cosmos-account'), '2022-09-01').outputs.connectionStringKey.value]" + }, + "endpoint": { + "type": "string", + "value": "[reference(resourceId('Microsoft.Resources/deployments', 'cosmos-account'), '2022-09-01').outputs.endpoint.value]" + }, + "id": { + "type": "string", + "value": "[reference(resourceId('Microsoft.Resources/deployments', 'cosmos-account'), '2022-09-01').outputs.id.value]" + } + } + } + } + } + ], + "outputs": { + "connectionStringKey": { + "type": "string", + "value": "[parameters('connectionStringKey')]" + }, + "databaseName": { + "type": "string", + "value": "[parameters('databaseName')]" + }, + "endpoint": { + "type": "string", + "value": "[reference(resourceId('Microsoft.Resources/deployments', 'cosmos-mongo-account'), '2022-09-01').outputs.endpoint.value]" + } + } + } + } + } + ], + "outputs": { + "connectionStringKey": { + "type": "string", + "value": "[reference(resourceId('Microsoft.Resources/deployments', 'cosmos-mongo'), '2022-09-01').outputs.connectionStringKey.value]" + }, + "databaseName": { + "type": "string", + "value": "[reference(resourceId('Microsoft.Resources/deployments', 'cosmos-mongo'), '2022-09-01').outputs.databaseName.value]" + }, + "endpoint": { + "type": "string", + "value": "[reference(resourceId('Microsoft.Resources/deployments', 'cosmos-mongo'), '2022-09-01').outputs.endpoint.value]" + } + } + } + }, + "dependsOn": [ + "[resourceId('Microsoft.Resources/deployments', 'keyvault')]" + ] + }, + { + "type": "Microsoft.Resources/deployments", + "apiVersion": "2022-09-01", + "name": "keyvault", + "properties": { + "expressionEvaluationOptions": { + "scope": "inner" + }, + "mode": "Incremental", + "parameters": { + "name": "[if(not(empty(parameters('keyVaultName'))), createObject('value', parameters('keyVaultName')), createObject('value', format('{0}{1}', variables('abbrs').keyVaultVaults, variables('resourceToken'))))]", + "location": { + "value": "[parameters('location')]" + }, + "tags": { + "value": "[variables('tags')]" + }, + "principalId": { + "value": "[parameters('principalId')]" + } + }, + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "contentVersion": "1.0.0.0", + "metadata": { + "_generator": { + "name": "bicep", + "version": "0.26.170.59819", + "templateHash": "18407114162280426775" + }, + "description": "Creates an Azure Key Vault." + }, + "parameters": { + "name": { + "type": "string" + }, + "location": { + "type": "string", + "defaultValue": "[resourceGroup().location]" + }, + "tags": { + "type": "object", + "defaultValue": {} + }, + "principalId": { + "type": "string", + "defaultValue": "" + } + }, + "resources": [ + { + "type": "Microsoft.KeyVault/vaults", + "apiVersion": "2022-07-01", + "name": "[parameters('name')]", + "location": "[parameters('location')]", + "tags": "[parameters('tags')]", + "properties": { + "tenantId": "[subscription().tenantId]", + "sku": { + "family": "A", + "name": "standard" + }, + "accessPolicies": "[if(not(empty(parameters('principalId'))), createArray(createObject('objectId', parameters('principalId'), 'permissions', createObject('secrets', createArray('get', 'list')), 'tenantId', subscription().tenantId)), createArray())]" + } + } + ], + "outputs": { + "endpoint": { + "type": "string", + "value": "[reference(resourceId('Microsoft.KeyVault/vaults', parameters('name')), '2022-07-01').vaultUri]" + }, + "name": { + "type": "string", + "value": "[parameters('name')]" + } + } + } + } + }, + { + "type": "Microsoft.Resources/deployments", + "apiVersion": "2022-09-01", + "name": "cluster-keyvault-access", + "properties": { + "expressionEvaluationOptions": { + "scope": "inner" + }, + "mode": "Incremental", + "parameters": { + "keyVaultName": { + "value": "[reference(resourceId('Microsoft.Resources/deployments', 'keyvault'), '2022-09-01').outputs.name.value]" + }, + "principalId": { + "value": "[parameters('aksClusterIdentityObjectId')]" + } + }, + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "contentVersion": "1.0.0.0", + "metadata": { + "_generator": { + "name": "bicep", + "version": "0.26.170.59819", + "templateHash": "7922086847377910894" + }, + "description": "Assigns an Azure Key Vault access policy." + }, + "parameters": { + "name": { + "type": "string", + "defaultValue": "add" + }, + "keyVaultName": { + "type": "string" + }, + "permissions": { + "type": "object", + "defaultValue": { + "secrets": [ + "get", + "list" + ] + } + }, + "principalId": { + "type": "string" + } + }, + "resources": [ + { + "type": "Microsoft.KeyVault/vaults/accessPolicies", + "apiVersion": "2022-07-01", + "name": "[format('{0}/{1}', parameters('keyVaultName'), parameters('name'))]", + "properties": { + "accessPolicies": [ + { + "objectId": "[parameters('principalId')]", + "tenantId": "[subscription().tenantId]", + "permissions": "[parameters('permissions')]" + } + ] + } + } + ] + } + }, + "dependsOn": [ + "[resourceId('Microsoft.Resources/deployments', 'keyvault')]" + ] + } + ], + "outputs": { + "AZURE_COSMOS_CONNECTION_STRING_KEY": { + "type": "string", + "value": "[reference(resourceId('Microsoft.Resources/deployments', 'cosmos'), '2022-09-01').outputs.connectionStringKey.value]" + }, + "AZURE_COSMOS_DATABASE_NAME": { + "type": "string", + "value": "[reference(resourceId('Microsoft.Resources/deployments', 'cosmos'), '2022-09-01').outputs.databaseName.value]" + }, + "AZURE_LOCATION": { + "type": "string", + "value": "[parameters('location')]" + }, + "AZURE_TENANT_ID": { + "type": "string", + "value": "[tenant().tenantId]" + }, + "AZURE_KEY_VAULT_ENDPOINT": { + "type": "string", + "value": "[reference(resourceId('Microsoft.Resources/deployments', 'keyvault'), '2022-09-01').outputs.endpoint.value]" + }, + "AZURE_KEY_VAULT_NAME": { + "type": "string", + "value": "[reference(resourceId('Microsoft.Resources/deployments', 'keyvault'), '2022-09-01').outputs.name.value]" + } + } +} \ No newline at end of file diff --git a/Environments/Todo-Mongo-AKS-LA/core/database/cosmos/cosmos-account.bicep b/Environments/Todo-Mongo-AKS-LA/core/database/cosmos/cosmos-account.bicep new file mode 100644 index 00000000..6f8747f5 --- /dev/null +++ b/Environments/Todo-Mongo-AKS-LA/core/database/cosmos/cosmos-account.bicep @@ -0,0 +1,49 @@ +metadata description = 'Creates an Azure Cosmos DB account.' +param name string +param location string = resourceGroup().location +param tags object = {} + +param connectionStringKey string = 'AZURE-COSMOS-CONNECTION-STRING' +param keyVaultName string + +@allowed([ 'GlobalDocumentDB', 'MongoDB', 'Parse' ]) +param kind string + +resource cosmos 'Microsoft.DocumentDB/databaseAccounts@2022-08-15' = { + name: name + kind: kind + location: location + tags: tags + properties: { + consistencyPolicy: { defaultConsistencyLevel: 'Session' } + locations: [ + { + locationName: location + failoverPriority: 0 + isZoneRedundant: false + } + ] + databaseAccountOfferType: 'Standard' + enableAutomaticFailover: false + enableMultipleWriteLocations: false + apiProperties: (kind == 'MongoDB') ? { serverVersion: '4.2' } : {} + capabilities: [ { name: 'EnableServerless' } ] + } +} + +resource cosmosConnectionString 'Microsoft.KeyVault/vaults/secrets@2022-07-01' = { + parent: keyVault + name: connectionStringKey + properties: { + value: cosmos.listConnectionStrings().connectionStrings[0].connectionString + } +} + +resource keyVault 'Microsoft.KeyVault/vaults@2022-07-01' existing = { + name: keyVaultName +} + +output connectionStringKey string = connectionStringKey +output endpoint string = cosmos.properties.documentEndpoint +output id string = cosmos.id +output name string = cosmos.name diff --git a/Environments/Todo-Mongo-AKS-LA/core/database/cosmos/mongo/cosmos-mongo-account.bicep b/Environments/Todo-Mongo-AKS-LA/core/database/cosmos/mongo/cosmos-mongo-account.bicep new file mode 100644 index 00000000..4aafbf38 --- /dev/null +++ b/Environments/Todo-Mongo-AKS-LA/core/database/cosmos/mongo/cosmos-mongo-account.bicep @@ -0,0 +1,23 @@ +metadata description = 'Creates an Azure Cosmos DB for MongoDB account.' +param name string +param location string = resourceGroup().location +param tags object = {} + +param keyVaultName string +param connectionStringKey string = 'AZURE-COSMOS-CONNECTION-STRING' + +module cosmos '../../cosmos/cosmos-account.bicep' = { + name: 'cosmos-account' + params: { + name: name + location: location + connectionStringKey: connectionStringKey + keyVaultName: keyVaultName + kind: 'MongoDB' + tags: tags + } +} + +output connectionStringKey string = cosmos.outputs.connectionStringKey +output endpoint string = cosmos.outputs.endpoint +output id string = cosmos.outputs.id diff --git a/Environments/Todo-Mongo-AKS-LA/core/database/cosmos/mongo/cosmos-mongo-db.bicep b/Environments/Todo-Mongo-AKS-LA/core/database/cosmos/mongo/cosmos-mongo-db.bicep new file mode 100644 index 00000000..2a670578 --- /dev/null +++ b/Environments/Todo-Mongo-AKS-LA/core/database/cosmos/mongo/cosmos-mongo-db.bicep @@ -0,0 +1,47 @@ +metadata description = 'Creates an Azure Cosmos DB for MongoDB account with a database.' +param accountName string +param databaseName string +param location string = resourceGroup().location +param tags object = {} + +param collections array = [] +param connectionStringKey string = 'AZURE-COSMOS-CONNECTION-STRING' +param keyVaultName string + +module cosmos 'cosmos-mongo-account.bicep' = { + name: 'cosmos-mongo-account' + params: { + name: accountName + location: location + keyVaultName: keyVaultName + tags: tags + connectionStringKey: connectionStringKey + } +} + +resource database 'Microsoft.DocumentDB/databaseAccounts/mongodbDatabases@2022-08-15' = { + name: '${accountName}/${databaseName}' + tags: tags + properties: { + resource: { id: databaseName } + } + + resource list 'collections' = [for collection in collections: { + name: collection.name + properties: { + resource: { + id: collection.id + shardKey: { _id: collection.shardKey } + indexes: [ { key: { keys: [ collection.indexKey ] } } ] + } + } + }] + + dependsOn: [ + cosmos + ] +} + +output connectionStringKey string = connectionStringKey +output databaseName string = databaseName +output endpoint string = cosmos.outputs.endpoint diff --git a/Environments/Todo-Mongo-AKS-LA/core/database/cosmos/sql/cosmos-sql-account.bicep b/Environments/Todo-Mongo-AKS-LA/core/database/cosmos/sql/cosmos-sql-account.bicep new file mode 100644 index 00000000..8431135e --- /dev/null +++ b/Environments/Todo-Mongo-AKS-LA/core/database/cosmos/sql/cosmos-sql-account.bicep @@ -0,0 +1,22 @@ +metadata description = 'Creates an Azure Cosmos DB for NoSQL account.' +param name string +param location string = resourceGroup().location +param tags object = {} + +param keyVaultName string + +module cosmos '../../cosmos/cosmos-account.bicep' = { + name: 'cosmos-account' + params: { + name: name + location: location + tags: tags + keyVaultName: keyVaultName + kind: 'GlobalDocumentDB' + } +} + +output connectionStringKey string = cosmos.outputs.connectionStringKey +output endpoint string = cosmos.outputs.endpoint +output id string = cosmos.outputs.id +output name string = cosmos.outputs.name diff --git a/Environments/Todo-Mongo-AKS-LA/core/database/cosmos/sql/cosmos-sql-db.bicep b/Environments/Todo-Mongo-AKS-LA/core/database/cosmos/sql/cosmos-sql-db.bicep new file mode 100644 index 00000000..265880dc --- /dev/null +++ b/Environments/Todo-Mongo-AKS-LA/core/database/cosmos/sql/cosmos-sql-db.bicep @@ -0,0 +1,74 @@ +metadata description = 'Creates an Azure Cosmos DB for NoSQL account with a database.' +param accountName string +param databaseName string +param location string = resourceGroup().location +param tags object = {} + +param containers array = [] +param keyVaultName string +param principalIds array = [] + +module cosmos 'cosmos-sql-account.bicep' = { + name: 'cosmos-sql-account' + params: { + name: accountName + location: location + tags: tags + keyVaultName: keyVaultName + } +} + +resource database 'Microsoft.DocumentDB/databaseAccounts/sqlDatabases@2022-05-15' = { + name: '${accountName}/${databaseName}' + properties: { + resource: { id: databaseName } + } + + resource list 'containers' = [for container in containers: { + name: container.name + properties: { + resource: { + id: container.id + partitionKey: { paths: [ container.partitionKey ] } + } + options: {} + } + }] + + dependsOn: [ + cosmos + ] +} + +module roleDefinition 'cosmos-sql-role-def.bicep' = { + name: 'cosmos-sql-role-definition' + params: { + accountName: accountName + } + dependsOn: [ + cosmos + database + ] +} + +// We need batchSize(1) here because sql role assignments have to be done sequentially +@batchSize(1) +module userRole 'cosmos-sql-role-assign.bicep' = [for principalId in principalIds: if (!empty(principalId)) { + name: 'cosmos-sql-user-role-${uniqueString(principalId)}' + params: { + accountName: accountName + roleDefinitionId: roleDefinition.outputs.id + principalId: principalId + } + dependsOn: [ + cosmos + database + ] +}] + +output accountId string = cosmos.outputs.id +output accountName string = cosmos.outputs.name +output connectionStringKey string = cosmos.outputs.connectionStringKey +output databaseName string = databaseName +output endpoint string = cosmos.outputs.endpoint +output roleDefinitionId string = roleDefinition.outputs.id diff --git a/Environments/Todo-Mongo-AKS-LA/core/database/cosmos/sql/cosmos-sql-role-assign.bicep b/Environments/Todo-Mongo-AKS-LA/core/database/cosmos/sql/cosmos-sql-role-assign.bicep new file mode 100644 index 00000000..3949efef --- /dev/null +++ b/Environments/Todo-Mongo-AKS-LA/core/database/cosmos/sql/cosmos-sql-role-assign.bicep @@ -0,0 +1,19 @@ +metadata description = 'Creates a SQL role assignment under an Azure Cosmos DB account.' +param accountName string + +param roleDefinitionId string +param principalId string = '' + +resource role 'Microsoft.DocumentDB/databaseAccounts/sqlRoleAssignments@2022-05-15' = { + parent: cosmos + name: guid(roleDefinitionId, principalId, cosmos.id) + properties: { + principalId: principalId + roleDefinitionId: roleDefinitionId + scope: cosmos.id + } +} + +resource cosmos 'Microsoft.DocumentDB/databaseAccounts@2022-08-15' existing = { + name: accountName +} diff --git a/Environments/Todo-Mongo-AKS-LA/core/database/cosmos/sql/cosmos-sql-role-def.bicep b/Environments/Todo-Mongo-AKS-LA/core/database/cosmos/sql/cosmos-sql-role-def.bicep new file mode 100644 index 00000000..778d6dc4 --- /dev/null +++ b/Environments/Todo-Mongo-AKS-LA/core/database/cosmos/sql/cosmos-sql-role-def.bicep @@ -0,0 +1,30 @@ +metadata description = 'Creates a SQL role definition under an Azure Cosmos DB account.' +param accountName string + +resource roleDefinition 'Microsoft.DocumentDB/databaseAccounts/sqlRoleDefinitions@2022-08-15' = { + parent: cosmos + name: guid(cosmos.id, accountName, 'sql-role') + properties: { + assignableScopes: [ + cosmos.id + ] + permissions: [ + { + dataActions: [ + 'Microsoft.DocumentDB/databaseAccounts/readMetadata' + 'Microsoft.DocumentDB/databaseAccounts/sqlDatabases/containers/items/*' + 'Microsoft.DocumentDB/databaseAccounts/sqlDatabases/containers/*' + ] + notDataActions: [] + } + ] + roleName: 'Reader Writer' + type: 'CustomRole' + } +} + +resource cosmos 'Microsoft.DocumentDB/databaseAccounts@2022-08-15' existing = { + name: accountName +} + +output id string = roleDefinition.id diff --git a/Environments/Todo-Mongo-AKS-LA/core/security/aks-managed-cluster-access.bicep b/Environments/Todo-Mongo-AKS-LA/core/security/aks-managed-cluster-access.bicep new file mode 100644 index 00000000..dec984e8 --- /dev/null +++ b/Environments/Todo-Mongo-AKS-LA/core/security/aks-managed-cluster-access.bicep @@ -0,0 +1,19 @@ +metadata description = 'Assigns RBAC role to the specified AKS cluster and principal.' +param clusterName string +param principalId string + +var aksClusterAdminRole = subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'b1ff04bb-8a4e-4dc4-8eb5-8693973ce19b') + +resource aksRole 'Microsoft.Authorization/roleAssignments@2022-04-01' = { + scope: aksCluster // Use when specifying a scope that is different than the deployment scope + name: guid(subscription().id, resourceGroup().id, principalId, aksClusterAdminRole) + properties: { + roleDefinitionId: aksClusterAdminRole + principalType: 'User' + principalId: principalId + } +} + +resource aksCluster 'Microsoft.ContainerService/managedClusters@2023-10-02-preview' existing = { + name: clusterName +} diff --git a/Environments/Todo-Mongo-AKS-LA/core/security/keyvault-access.bicep b/Environments/Todo-Mongo-AKS-LA/core/security/keyvault-access.bicep new file mode 100644 index 00000000..316775f2 --- /dev/null +++ b/Environments/Todo-Mongo-AKS-LA/core/security/keyvault-access.bicep @@ -0,0 +1,22 @@ +metadata description = 'Assigns an Azure Key Vault access policy.' +param name string = 'add' + +param keyVaultName string +param permissions object = { secrets: [ 'get', 'list' ] } +param principalId string + +resource keyVaultAccessPolicies 'Microsoft.KeyVault/vaults/accessPolicies@2022-07-01' = { + parent: keyVault + name: name + properties: { + accessPolicies: [ { + objectId: principalId + tenantId: subscription().tenantId + permissions: permissions + } ] + } +} + +resource keyVault 'Microsoft.KeyVault/vaults@2022-07-01' existing = { + name: keyVaultName +} diff --git a/Environments/Todo-Mongo-AKS-LA/core/security/keyvault-secret.bicep b/Environments/Todo-Mongo-AKS-LA/core/security/keyvault-secret.bicep new file mode 100644 index 00000000..7441b296 --- /dev/null +++ b/Environments/Todo-Mongo-AKS-LA/core/security/keyvault-secret.bicep @@ -0,0 +1,31 @@ +metadata description = 'Creates or updates a secret in an Azure Key Vault.' +param name string +param tags object = {} +param keyVaultName string +param contentType string = 'string' +@description('The value of the secret. Provide only derived values like blob storage access, but do not hard code any secrets in your templates') +@secure() +param secretValue string + +param enabled bool = true +param exp int = 0 +param nbf int = 0 + +resource keyVaultSecret 'Microsoft.KeyVault/vaults/secrets@2022-07-01' = { + name: name + tags: tags + parent: keyVault + properties: { + attributes: { + enabled: enabled + exp: exp + nbf: nbf + } + contentType: contentType + value: secretValue + } +} + +resource keyVault 'Microsoft.KeyVault/vaults@2022-07-01' existing = { + name: keyVaultName +} diff --git a/Environments/Todo-Mongo-AKS-LA/core/security/keyvault.bicep b/Environments/Todo-Mongo-AKS-LA/core/security/keyvault.bicep new file mode 100644 index 00000000..314a1db6 --- /dev/null +++ b/Environments/Todo-Mongo-AKS-LA/core/security/keyvault.bicep @@ -0,0 +1,26 @@ +metadata description = 'Creates an Azure Key Vault.' +param name string +param location string = resourceGroup().location +param tags object = {} + +param principalId string = '' + +resource keyVault 'Microsoft.KeyVault/vaults@2022-07-01' = { + name: name + location: location + tags: tags + properties: { + tenantId: subscription().tenantId + sku: { family: 'A', name: 'standard' } + accessPolicies: !empty(principalId) ? [ + { + objectId: principalId + permissions: { secrets: [ 'get', 'list' ] } + tenantId: subscription().tenantId + } + ] : [] + } +} + +output endpoint string = keyVault.properties.vaultUri +output name string = keyVault.name diff --git a/Environments/Todo-Mongo-AKS-LA/core/security/registry-access.bicep b/Environments/Todo-Mongo-AKS-LA/core/security/registry-access.bicep new file mode 100644 index 00000000..5335efab --- /dev/null +++ b/Environments/Todo-Mongo-AKS-LA/core/security/registry-access.bicep @@ -0,0 +1,19 @@ +metadata description = 'Assigns ACR Pull permissions to access an Azure Container Registry.' +param containerRegistryName string +param principalId string + +var acrPullRole = subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '7f951dda-4ed3-4680-a7ca-43fe172d538d') + +resource aksAcrPull 'Microsoft.Authorization/roleAssignments@2022-04-01' = { + scope: containerRegistry // Use when specifying a scope that is different than the deployment scope + name: guid(subscription().id, resourceGroup().id, principalId, acrPullRole) + properties: { + roleDefinitionId: acrPullRole + principalType: 'ServicePrincipal' + principalId: principalId + } +} + +resource containerRegistry 'Microsoft.ContainerRegistry/registries@2022-02-01-preview' existing = { + name: containerRegistryName +} diff --git a/Environments/Todo-Mongo-AKS-LA/core/security/role.bicep b/Environments/Todo-Mongo-AKS-LA/core/security/role.bicep new file mode 100644 index 00000000..0b30cfd3 --- /dev/null +++ b/Environments/Todo-Mongo-AKS-LA/core/security/role.bicep @@ -0,0 +1,21 @@ +metadata description = 'Creates a role assignment for a service principal.' +param principalId string + +@allowed([ + 'Device' + 'ForeignGroup' + 'Group' + 'ServicePrincipal' + 'User' +]) +param principalType string = 'ServicePrincipal' +param roleDefinitionId string + +resource role 'Microsoft.Authorization/roleAssignments@2022-04-01' = { + name: guid(subscription().id, resourceGroup().id, principalId, roleDefinitionId) + properties: { + principalId: principalId + principalType: principalType + roleDefinitionId: resourceId('Microsoft.Authorization/roleDefinitions', roleDefinitionId) + } +} diff --git a/Environments/Todo-Mongo-AKS-LA/get-aks-info.bicep b/Environments/Todo-Mongo-AKS-LA/get-aks-info.bicep new file mode 100644 index 00000000..9cd133a4 --- /dev/null +++ b/Environments/Todo-Mongo-AKS-LA/get-aks-info.bicep @@ -0,0 +1,5 @@ +param aksName string +resource aks 'Microsoft.ContainerService/managedClusters@2023-10-02-preview' existing = { + name: aksName +} +output aksIdentityObjectId string = aks.properties.identityProfile.kubeletidentity.objectId diff --git a/Environments/Todo-Mongo-AKS-LA/get-shared-aks-name.bicep b/Environments/Todo-Mongo-AKS-LA/get-shared-aks-name.bicep new file mode 100644 index 00000000..9bbd7aa0 --- /dev/null +++ b/Environments/Todo-Mongo-AKS-LA/get-shared-aks-name.bicep @@ -0,0 +1,62 @@ +@description('app deployment name') +param appDeployName string + +@description('Shared AKS resource group') +param aksResourceGroupName string + +@description('Timestamp - utcNow can only be called as a default value of a parameter.') +param timestamp string = utcNow() + +@description('The location to run the deployment script in') +param location string = resourceGroup().location + +param identityName string + +var scriptToExecute = ''' +$output = Get-AzResource -ResourceGroupName $Env:RESOURCEGROUP -ResourceType Microsoft.ContainerService/ManagedClusters + +Write-Output $output +$DeploymentScriptOutputs = @{} +$DeploymentScriptOutputs['text'] = $output.Name +''' + +resource identity 'Microsoft.ManagedIdentity/userAssignedIdentities@2023-01-31' = { + name: identityName + location: location +} + +module roleAssignemnt './core/security/role.bicep' = { + name: 'read-role-assignment-to-aks' + scope: resourceGroup(aksResourceGroupName) + params: { + principalId: identity.properties.principalId + roleDefinitionId: 'acdd72a7-3385-48ef-bd42-f606fba81ae7' + } +} + +resource script 'Microsoft.Resources/deploymentScripts@2020-10-01' = { + kind: 'AzurePowerShell' + name: '${appDeployName}-get-aks-script' + location: location + identity: { + type: 'UserAssigned' + userAssignedIdentities: { + '${identity.id}' : {} + } + } + properties: { + forceUpdateTag: timestamp + azPowerShellVersion: '7.2.0' + retentionInterval: 'PT1H' + scriptContent: scriptToExecute + cleanupPreference: 'Always' + environmentVariables: [ + { + name: 'RESOURCEGROUP' + value: aksResourceGroupName + } + ] + } +} + +output clusterName string = empty(script.properties.outputs.text) ? '' : script.properties.outputs.text diff --git a/Environments/Todo-Mongo-AKS-LA/main.bicep b/Environments/Todo-Mongo-AKS-LA/main.bicep new file mode 100644 index 00000000..a2d1c00d --- /dev/null +++ b/Environments/Todo-Mongo-AKS-LA/main.bicep @@ -0,0 +1,122 @@ +@minLength(1) +@maxLength(64) +@description('Name of the the environment which is used to generate a short unique hash used in all resources.') +param environmentName string + +@minLength(1) +@description('Primary location for all resources') +param location string = resourceGroup().location + +param cosmosAccountName string = '' +param cosmosDatabaseName string = '' +param keyVaultName string = '' +param principalId string = '' +param configStoreName string = '' +param sharedAKSProjectName string +param sharedAKSEnvironmentName string +var sharedAKSResourceGroup = '${sharedAKSProjectName}-${sharedAKSEnvironmentName}' + +var abbrs = loadJsonContent('./abbreviations.json') +var resourceToken = toLower(uniqueString(subscription().id, environmentName, location)) +var tags = { 'azd-env-name': environmentName } + +// Store secrets in a keyvault +module keyVault './core/security/keyvault.bicep' = { + name: 'keyvault' + params: { + name: !empty(keyVaultName) ? keyVaultName : '${abbrs.keyVaultVaults}${resourceToken}' + location: location + tags: tags + principalId: principalId + } +} + +module aksName 'get-shared-aks-name.bicep' = { + name: 'get-aks-name' + params: { + appDeployName: 'todo-deploy' + aksResourceGroupName: sharedAKSResourceGroup + identityName : '${abbrs.managedIdentityUserAssignedIdentities}dp-${resourceToken}' + location: location + } +} + +module aks 'get-aks-info.bicep' = { + name: 'aks' + scope: resourceGroup(sharedAKSResourceGroup) + params: { + aksName: aksName.outputs.clusterName + } +} + +module clusterKeyVaultAccess './core/security/keyvault-access.bicep' = { + name: 'cluster-keyvault-access' + params: { + keyVaultName: keyVault.outputs.name + principalId: aks.outputs.aksIdentityObjectId + } +} + +// The application database +module cosmos './app/db.bicep' = { + name: 'cosmos' + params: { + accountName: !empty(cosmosAccountName) ? cosmosAccountName : '${abbrs.documentDBDatabaseAccounts}${resourceToken}' + databaseName: cosmosDatabaseName + location: location + tags: tags + keyVaultName: keyVault.outputs.name + } +} + +@description('Specifies the content type of the key-value resources. For feature flag, the value should be application/vnd.microsoft.appconfig.ff+json;charset=utf-8. For Key Value reference, the value should be application/vnd.microsoft.appconfig.keyvaultref+json;charset=utf-8. Otherwise, it\'s optional.') +param contentType string = '' + + +resource configStore 'Microsoft.AppConfiguration/configurationStores@2021-10-01-preview' = { + name: !empty(configStoreName) ? configStoreName : '${abbrs.appConfigurationConfigurationStores}${resourceToken}' + location: location + sku: { + name: 'standard' + } +} + +resource configStoreKeyValue 'Microsoft.AppConfiguration/configurationStores/keyValues@2021-10-01-preview' = { + parent: configStore + name: 'AZURE_COSMOS_CONNECTION_STRING_KEY' + properties: { + value: cosmos.outputs.connectionStringKey + contentType: contentType + tags: tags + } +} + +resource configStoreKeyValue2 'Microsoft.AppConfiguration/configurationStores/keyValues@2021-10-01-preview' = { + parent: configStore + name: 'AZURE_COSMOS_DATABASE_NAME' + properties: { + value: cosmos.outputs.databaseName + contentType: contentType + tags: tags + } +} + +resource configStoreKeyValue3 'Microsoft.AppConfiguration/configurationStores/keyValues@2021-10-01-preview' = { + parent: configStore + name: 'AZURE_KEY_VAULT_ENDPOINT' + properties: { + value: keyVault.outputs.endpoint + contentType: contentType + tags: tags + } +} + +// Data outputs +output AZURE_COSMOS_CONNECTION_STRING_KEY string = cosmos.outputs.connectionStringKey +output AZURE_COSMOS_DATABASE_NAME string = cosmos.outputs.databaseName + +// App outputs +output AZURE_LOCATION string = location +output AZURE_TENANT_ID string = tenant().tenantId +output AZURE_KEY_VAULT_ENDPOINT string = keyVault.outputs.endpoint +output AZURE_KEY_VAULT_NAME string = keyVault.outputs.name diff --git a/Environments/Todo-Mongo-AKS-LA/main.parameters.json b/Environments/Todo-Mongo-AKS-LA/main.parameters.json new file mode 100644 index 00000000..67ad8524 --- /dev/null +++ b/Environments/Todo-Mongo-AKS-LA/main.parameters.json @@ -0,0 +1,15 @@ +{ + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentParameters.json#", + "contentVersion": "1.0.0.0", + "parameters": { + "environmentName": { + "value": "${AZURE_ENV_NAME}" + }, + "location": { + "value": "${AZURE_LOCATION}" + }, + "principalId": { + "value": "${AZURE_PRINCIPAL_ID}" + } + } +} \ No newline at end of file diff --git a/Environments/Todo-Mongo-AKS-LA/manifest.yaml b/Environments/Todo-Mongo-AKS-LA/manifest.yaml new file mode 100644 index 00000000..5056d21b --- /dev/null +++ b/Environments/Todo-Mongo-AKS-LA/manifest.yaml @@ -0,0 +1,31 @@ +name: Todo-Mongo-AKS +version: 1.0.0 +summary: Todo Nodejs Mongo AKS +description: Deploys a todo app with Nodejs and Mongo +runner: ARM +templatePath: azuredeploy.json + +parameters: +- id: "environmentName" + name: "Environment Name (e.g. testenv)" + description: "Name of the Environment" + type: string + required: true + +- id: "location" + name: "Region (e.g. eastus)" + description: "Location of the resources" + type: string + required: true + +- id: "sharedAKSProjectName" + name: "Shared AKS Project Name" + description: "ADE Project name for the shared AKS cluster" + type: string + required: true + +- id: "sharedAKSEnvironmentName" + name: "Shared AKS Environment Name" + description: "ADE environment name for the shared AKS cluster" + type: string + required: true