diff --git a/infra/aspire.bicep b/infra/aspire.bicep index add37d05..e0f2712d 100644 --- a/infra/aspire.bicep +++ b/infra/aspire.bicep @@ -17,6 +17,15 @@ param enabledForDeployment bool = true param enabledForTemplateDeployment bool = true param enableRbacAuthorization bool = true +//TODO: 배포 시점에 사용자 princpalId, apiapp principalId를 받는 방법 조사 +//param creatorAdminPrincipalId string = '' +//param apiAppUserPrincipalId string = '' + +// parameters for storage account +param storageAccountName string = '' +// tableNames passed as a comma separated string from command line +param tableNames string = 'events' + var abbrs = loadJsonContent('./abbreviations.json') // Tags that should be applied to all resources. @@ -39,6 +48,9 @@ var resourceToken = uniqueString(resourceGroup().id) #disable-next-line no-unused-vars // var apiServiceName = 'python-api' +// tables for storage account seperated by comma +var tables = split(tableNames, ',') + // Add resources to be provisioned below. // Provision Key Vault @@ -54,6 +66,35 @@ module keyVault './core/security/keyvault.bicep' = { } } +// Provision Storage Account +module storageAccount './core/storage/storage-account.bicep' = { + name: 'storageAccount' + params: { + name: !empty(storageAccountName) ? storageAccountName : '${abbrs.storageStorageAccounts}${resourceToken}' + location: location + tags: tags + tables: tables + keyVaultName: keyVault.outputs.name + } +} + +// TODO: Key vault Secret 권한부여, 생성한 사람에게 관리자 권한을, 그 외에는 secret user 권한을 부여 +//resource keyVaultSecretRoleAssignment 'Microsoft.Authorization/roleAssignments@2020-04-01-preview' = { +// name: guid(resourceGroup().id, resolvedKeyVaultName, 'secret-role-assignment') +// properties: { +// principalId: creatorAdminPrincipalId +// roleDefinitionId: '00482A5A-887F-4FB3-B363-3B7FE8E74483' // administrator role +// } +//} +// +//resource keyVaultSecretApiAppRoleAssignment 'Microsoft.Authorization/roleAssignments@2020-04-01-preview' = { +// name: guid(resourceGroup().id, resolvedKeyVaultName, 'secret-apiapp-role-assignment') +// properties: { +// principalId: apiAppUserPrincipalId +// roleDefinitionId: '4633458B-17DE-408A-B874-0445C86B69E6' // secret user role +// } +//} + // Add outputs from the deployment here, if needed. // // This allows the outputs to be referenced by other bicep deployments in the deployment pipeline, diff --git a/infra/core/storage/storage-account.bicep b/infra/core/storage/storage-account.bicep new file mode 100644 index 00000000..9a2fab4a --- /dev/null +++ b/infra/core/storage/storage-account.bicep @@ -0,0 +1,118 @@ +metadata description = 'Creates an Azure storage account.' +param name string +param location string = resourceGroup().location +param tags object = {} + +@allowed([ + 'Cool' + 'Hot' + 'Premium' ]) +param accessTier string = 'Hot' +param allowBlobPublicAccess bool = true +param allowCrossTenantReplication bool = true +param allowSharedKeyAccess bool = true +param containers array = [] +param corsRules array = [] +param defaultToOAuthAuthentication bool = false +param deleteRetentionPolicy object = {} +@allowed([ 'AzureDnsZone', 'Standard' ]) +param dnsEndpointType string = 'Standard' +param files array = [] +param kind string = 'StorageV2' +param minimumTlsVersion string = 'TLS1_2' +param queues array = [] +param shareDeleteRetentionPolicy object = {} +param supportsHttpsTrafficOnly bool = true +param tables array = [] +param networkAcls object = { + bypass: 'AzureServices' + defaultAction: 'Allow' +} +@allowed([ 'Enabled', 'Disabled' ]) +param publicNetworkAccess string = 'Enabled' +param sku object = { name: 'Standard_LRS' } +param keyVaultName string = '' + +resource storage 'Microsoft.Storage/storageAccounts@2023-01-01' = { + name: name + location: location + tags: tags + kind: kind + sku: sku + properties: { + accessTier: accessTier + allowBlobPublicAccess: allowBlobPublicAccess + allowCrossTenantReplication: allowCrossTenantReplication + allowSharedKeyAccess: allowSharedKeyAccess + defaultToOAuthAuthentication: defaultToOAuthAuthentication + dnsEndpointType: dnsEndpointType + minimumTlsVersion: minimumTlsVersion + networkAcls: networkAcls + publicNetworkAccess: publicNetworkAccess + supportsHttpsTrafficOnly: supportsHttpsTrafficOnly + } + + resource blobServices 'blobServices' = if (!empty(containers)) { + name: 'default' + properties: { + cors: { + corsRules: corsRules + } + deleteRetentionPolicy: deleteRetentionPolicy + } + resource container 'containers' = [for container in containers: { + name: container.name + properties: { + // todo: Warning use-safe-access: Use the safe access (.?) operator instead of checking object contents with the 'contains' function. [https://aka.ms/bicep/linter/use-safe-access] + publicAccess: contains(container, 'publicAccess') ? container.publicAccess : 'None' + } + }] + } + + resource fileServices 'fileServices' = if (!empty(files)) { + name: 'default' + properties: { + cors: { + corsRules: corsRules + } + shareDeleteRetentionPolicy: shareDeleteRetentionPolicy + } + } + + resource queueServices 'queueServices' = if (!empty(queues)) { + name: 'default' + properties: { + + } + resource queue 'queues' = [for queue in queues: { + name: queue.name + properties: { + metadata: {} + } + }] + } + + resource tableServices 'tableServices' = if (!empty(tables)) { + name: 'default' + properties: {} + // create tables pre-defined in aspire.bicep + resource table 'tables' = [for table in tables: { + name: table + properties: {} + }] + } +} + +// Save Storage Account Connection String in Key Vault Secret +module keyVaultSecrets '../../core/security/keyvault-secret.bicep' = { + name: 'keyVaultSecrets' + params: { + name: 'storage-connection-string' + secretValue:'DefaultEndpointsProtocol=https;EndpointSuffix=${environment().suffixes.storage};AccountName=${storage.name};AccountKey=${storage.listKeys().keys[0].value};BlobEndpoint=${storage.properties.primaryEndpoints.blob};FileEndpoint=${storage.properties.primaryEndpoints.file};QueueEndpoint=${storage.properties.primaryEndpoints.queue};TableEndpoint=${storage.properties.primaryEndpoints.table}' + keyVaultName:keyVaultName + } +} + +output id string = storage.id +output name string = storage.name +output primaryEndpoints object = storage.properties.primaryEndpoints