diff --git a/api/src/app.controller.ts b/api/src/app.controller.ts index 942d1dd..e1d27cd 100644 --- a/api/src/app.controller.ts +++ b/api/src/app.controller.ts @@ -3,69 +3,20 @@ import { Get, Headers, Query, - Res, StreamableFile } from '@nestjs/common'; import { Client as MsGraphClient } from '@microsoft/microsoft-graph-client'; import { MsGraphService, Public } from '@noahspan/noahspan-modules'; -import { FeatureFlagValue } from '@azure/app-configuration'; import { Person } from '@microsoft/microsoft-graph-types'; import { AppService } from './app.service'; -import { createReadStream } from 'fs'; -import { join } from 'path'; -import { arrayBuffer } from 'stream/consumers'; -import type { Response } from 'express'; -import { DaprService } from '@noahspan/noahspan-modules'; @Controller() export class AppController { constructor( private readonly appService: AppService, - private readonly daprService: DaprService, private readonly msGraphService: MsGraphService ) {} - // @Public() - // @Get('featureFlags') - // async getFeatureFlags( - // @Query() query: any - // ): Promise<{ key: string; enabled: boolean }[]> { - // try { - // const featureFlagKeys: string[] = - // query.keys && query.keys.toString().includes(';') - // ? query.keys.split(';') - // : [query.keys]; - // const featureFlagLabel: string = query.label; - // const featureFlags: { key: string; enabled: boolean }[] = - // await this.appConfigService.getFeatureFlags( - // featureFlagKeys, - // featureFlagLabel - // ); - - // return featureFlags; - // } catch (error) { - // return error; - // } - // } - - @Public() - @Get('featureFlags') - async getFeatureFlags(@Query() query: any): Promise { - try { - // const config = await this.daprService.daprClient.configuration.get('app-config', ['flying-logbook'], { - // 'label': 'dev' - // }) - console.log('====== BLAH ======'); - const config = - await this.daprService.daprClient.configuration.get('app-config'); - - console.log('====== Config ======: ' + config); - } catch (error) { - console.log(`======= ERROR ======: ${error}`); - return error; - } - } - @Get('userPhoto') async getProfilePhoto(@Headers() headers: any): Promise { try { diff --git a/api/src/app.module.ts b/api/src/app.module.ts index ff5f6f4..7eaa87b 100644 --- a/api/src/app.module.ts +++ b/api/src/app.module.ts @@ -4,81 +4,42 @@ import { AppService } from './app.service'; import { AuthGuard, AuthModule } from '@noahspan/noahspan-modules'; import { MsGraphModule } from '@noahspan/noahspan-modules'; import { APP_GUARD } from '@nestjs/core'; +import { FeatureFlagModule } from './featureFlag/feature-flag.module' import { LogModule } from './log/log.module'; import { PilotModule } from './pilot/pilot.module'; import { APP_FILTER } from '@nestjs/core'; import { HttpExceptionFilter } from './filters/http-exception.filter'; -import { DaprModule, DaprService } from '@noahspan/noahspan-modules'; -import { AzureTableStorageModule } from '@noahspan/azure-database'; - -const secretStoreName = 'key-vault'; +import { ConfigModule, ConfigService } from '@nestjs/config'; +import configuration from './config/configuration'; @Module({ imports: [ AuthModule.registerAsync({ - imports: [DaprModule], - useFactory: async (daprService: DaprService) => { - const clientIdSecret = await daprService.daprClient.secret.get( - secretStoreName, - 'client-id' - ); - const clientSecret = await daprService.daprClient.secret.get( - secretStoreName, - 'client-secret' - ); - const tenantIdSecret = await daprService.daprClient.secret.get( - secretStoreName, - 'tenant-id' - ); - + imports: [ConfigModule], + useFactory: async (configService: ConfigService) => { return { - clientId: clientIdSecret['client-id'].toString(), - clientSecret: clientSecret['client-secret'].toString(), - tenantId: tenantIdSecret['tenant-id'].toString() + clientId: configService.get('clientId'), + clientSecret: configService.get('clientSecret'), + tenantId: configService.get('tenantId') }; }, - inject: [DaprService] + inject: [ConfigService] }), - AzureTableStorageModule.forRootAsync({ - imports: [DaprModule], - useFactory: async (daprService: DaprService) => { - const connectionString = await daprService.daprClient.secret.get( - secretStoreName, - 'azure-storage-connection-string' - ); - - return { - connectionString: - connectionString['azure-storage-connection-string'].toString() - }; - }, - inject: [DaprService] + ConfigModule.forRoot({ + load: [configuration] }), - DaprModule, + FeatureFlagModule, LogModule, MsGraphModule.registerAsync({ - imports: [DaprModule], - useFactory: async (daprService: DaprService) => { - const clientIdSecret = await daprService.daprClient.secret.get( - secretStoreName, - 'client-id' - ); - const clientSecret = await daprService.daprClient.secret.get( - secretStoreName, - 'client-secret' - ); - const tenantIdSecret = await daprService.daprClient.secret.get( - secretStoreName, - 'tenant-id' - ); - + imports: [ConfigModule], + useFactory: async (configService: ConfigService) => { return { - clientId: clientIdSecret['client-id'].toString(), - clientSecret: clientSecret['client-secret'].toString(), - tenantId: tenantIdSecret['tenant-id'].toString() + clientId: configService.get('clientId'), + clientSecret: configService.get('clientSecret'), + tenantId: configService.get('tenantId') }; }, - inject: [DaprService] + inject: [ConfigService] }), PilotModule ], diff --git a/api/src/config/configuration.ts b/api/src/config/configuration.ts new file mode 100644 index 0000000..2354131 --- /dev/null +++ b/api/src/config/configuration.ts @@ -0,0 +1,6 @@ +export default () => ({ + azureStorageConnectionString: process.env.AZURE_STORAGE_CONNECTION_STRING, + clientId: process.env.CLIENT_ID, + clientSecret: process.env.CLIENT_SECRET, + tenantId: process.env.TENANT_ID +}) \ No newline at end of file diff --git a/api/src/featureFlag/feature-flag.controller.ts b/api/src/featureFlag/feature-flag.controller.ts new file mode 100644 index 0000000..77f627c --- /dev/null +++ b/api/src/featureFlag/feature-flag.controller.ts @@ -0,0 +1,40 @@ +import { + Controller, + Get, + HttpException, + Param, +} from '@nestjs/common'; +import { FeatureFlagService } from './feature-flag.service'; +import { CustomError, Public } from '@noahspan/noahspan-modules'; + +@Controller('featureFlags') +export class FeatureFlagController { + constructor(private readonly featureFlagService: FeatureFlagService) {} + + @Get(':partitionKey/:rowKey') + @Public() + async find( + @Param('partitionKey') partitionKey: string, + @Param('rowKey') rowKey: string + ) { + try { + return await this.featureFlagService.find(partitionKey, rowKey); + } catch (error) { + const customError = error as CustomError; + + throw new HttpException(customError.message, customError.statusCode); + } + } + + @Get() + @Public() + async findAll() { + try { + return await this.featureFlagService.findAll(); + } catch (error) { + const customError = error as CustomError; + + throw new HttpException(customError.message, customError.statusCode); + } + } +} diff --git a/api/src/featureFlag/feature-flag.dto.ts b/api/src/featureFlag/feature-flag.dto.ts new file mode 100644 index 0000000..0b31d35 --- /dev/null +++ b/api/src/featureFlag/feature-flag.dto.ts @@ -0,0 +1,5 @@ +export class FeatureFlagDto { + partitionKey: string; + rowKey: string; + active: string; +} diff --git a/api/src/featureFlag/feature-flag.entity.ts b/api/src/featureFlag/feature-flag.entity.ts new file mode 100644 index 0000000..d5a4e4c --- /dev/null +++ b/api/src/featureFlag/feature-flag.entity.ts @@ -0,0 +1,7 @@ +import { EntityString } from '@noahspan/azure-database'; + +export class FeatureFlag { + @EntityString() partitionKey: string; + @EntityString() rowKey: string; + @EntityString() active: string; +} diff --git a/api/src/featureFlag/feature-flag.module.ts b/api/src/featureFlag/feature-flag.module.ts new file mode 100644 index 0000000..bc39292 --- /dev/null +++ b/api/src/featureFlag/feature-flag.module.ts @@ -0,0 +1,27 @@ +import { Module } from '@nestjs/common'; +import { FeatureFlagController } from './feature-flag.controller'; +import { FeatureFlagService } from './feature-flag.service'; +import { AzureTableStorageModule } from '@noahspan/azure-database'; +import { ConfigModule, ConfigService } from '@nestjs/config'; +import { FeatureFlag } from './feature-flag.entity'; + +@Module({ + imports: [ + AzureTableStorageModule.forRootAsync({ + imports: [ConfigModule], + useFactory: async (configService: ConfigService) => { + return { + connectionString: configService.get('azureStorageConnectionString') + }; + }, + inject: [ConfigService] + }), + AzureTableStorageModule.forFeature(FeatureFlag, { + createTableIfNotExists: false, + table: 'featureFlags' + }), + ], + controllers: [FeatureFlagController], + providers: [FeatureFlagService] +}) +export class FeatureFlagModule {} diff --git a/api/src/featureFlag/feature-flag.service.ts b/api/src/featureFlag/feature-flag.service.ts new file mode 100644 index 0000000..b05dbb0 --- /dev/null +++ b/api/src/featureFlag/feature-flag.service.ts @@ -0,0 +1,18 @@ +import { Injectable } from '@nestjs/common'; +import { InjectRepository, Repository } from '@noahspan/azure-database'; +import { FeatureFlag } from './feature-flag.entity'; + +@Injectable() +export class FeatureFlagService { + constructor( + @InjectRepository(FeatureFlag) private readonly featureFlagRepository: Repository + ) {} + + async find(partitionKey: string, rowKey: string): Promise { + return await this.featureFlagRepository.find(partitionKey, rowKey); + } + + async findAll(): Promise { + return await this.featureFlagRepository.findAll(); + } +} diff --git a/api/src/filters/http-exception.filter.ts b/api/src/filters/http-exception.filter.ts index 56a25a3..a1942a0 100644 --- a/api/src/filters/http-exception.filter.ts +++ b/api/src/filters/http-exception.filter.ts @@ -13,7 +13,6 @@ export class HttpExceptionFilter implements ExceptionFilter { const response = ctx.getResponse(); const request = ctx.getRequest(); const status = excpetion.getStatus(); - console.log(excpetion.cause); response.status(status).json({ name: excpetion.cause, diff --git a/api/src/log/log.controller.ts b/api/src/log/log.controller.ts index 1cfde94..44d5d51 100644 --- a/api/src/log/log.controller.ts +++ b/api/src/log/log.controller.ts @@ -48,7 +48,7 @@ export class LogController { const log = new Log(); Object.assign(log, logDto); - console.log(log); + return await this.logService.create(log); } catch (error) { const customError = error as CustomError; diff --git a/api/src/log/log.module.ts b/api/src/log/log.module.ts index 6bf0b7b..a1343d4 100644 --- a/api/src/log/log.module.ts +++ b/api/src/log/log.module.ts @@ -1,32 +1,25 @@ import { Module } from '@nestjs/common'; -import { DaprModule, DaprService } from '@noahspan/noahspan-modules'; import { LogController } from './log.controller'; import { LogService } from './log.service'; import { AzureTableStorageModule } from '@noahspan/azure-database'; import { Log } from './log.entity'; +import { ConfigModule, ConfigService } from '@nestjs/config'; @Module({ imports: [ AzureTableStorageModule.forRootAsync({ - imports: [DaprModule], - useFactory: async (daprService: DaprService) => { - const connectionString = await daprService.daprClient.secret.get( - 'key-vault', - 'azure-storage-connection-string' - ); - + imports: [ConfigModule], + useFactory: async (configService: ConfigService) => { return { - connectionString: - connectionString['azure-storage-connection-string'].toString() + connectionString: configService.get('azureStorageConnectionString') }; }, - inject: [DaprService] + inject: [ConfigService] }), AzureTableStorageModule.forFeature(Log, { createTableIfNotExists: false, table: 'logs' }), - DaprModule ], controllers: [LogController], providers: [LogService] diff --git a/api/src/log/log.service.ts b/api/src/log/log.service.ts index c7ad5d9..c7de866 100644 --- a/api/src/log/log.service.ts +++ b/api/src/log/log.service.ts @@ -5,8 +5,6 @@ import { v4 as uuidv4 } from 'uuid'; @Injectable() export class LogService { - private readonly tableName = 'Logbook'; - constructor( @InjectRepository(Log) private readonly logRepository: Repository ) {} diff --git a/api/src/pilot/pilot.module.ts b/api/src/pilot/pilot.module.ts index 8c262c4..432f53c 100644 --- a/api/src/pilot/pilot.module.ts +++ b/api/src/pilot/pilot.module.ts @@ -1,32 +1,25 @@ import { Module } from '@nestjs/common'; -import { DaprModule, DaprService } from '@noahspan/noahspan-modules'; import { PilotController } from './pilot.controller'; import { PilotService } from './pilot.service'; import { AzureTableStorageModule } from '@noahspan/azure-database'; import { Pilot } from './pilot.entity'; +import { ConfigModule, ConfigService } from '@nestjs/config'; @Module({ imports: [ AzureTableStorageModule.forRootAsync({ - imports: [DaprModule], - useFactory: async (daprService: DaprService) => { - const connectionString = await daprService.daprClient.secret.get( - 'key-vault', - 'azure-storage-connection-string' - ); - + imports: [ConfigModule], + useFactory: async (configService: ConfigService) => { return { - connectionString: - connectionString['azure-storage-connection-string'].toString() + connectionString: configService.get('azureStorageConnectionString') }; }, - inject: [DaprService] + inject: [ConfigService] }), AzureTableStorageModule.forFeature(Pilot, { createTableIfNotExists: false, table: 'pilots' }), - DaprModule ], controllers: [PilotController], providers: [PilotService] diff --git a/app/src/App.tsx b/app/src/App.tsx index 80a9595..36c21e9 100644 --- a/app/src/App.tsx +++ b/app/src/App.tsx @@ -15,12 +15,17 @@ const App: React.FC = () => { useEffect(() => { const getFeatureFlags = async () => { try { - const featureFlagKeys: string = 'flying-pilots'; + const featureFlags: { key: string; enabled: boolean }[] = [] const response: AxiosResponse = await httpClient.get( - `api/featureFlags?keys=${featureFlagKeys}&label=${import.meta.env.MODE}` + 'api/featureFlags' ); - console.log(response); - const featureFlags: { key: string; enabled: boolean }[] = response.data; + + for (const featureFlag of response.data) { + featureFlags.push({ + key: featureFlag.rowKey, + enabled: featureFlag.active === 'true' ? true : false + }) + } if (featureFlags.length > 0) { appContext.dispatch({ @@ -40,7 +45,7 @@ const App: React.FC = () => {
- {useFeatureFlag('flying-pilots')?.enabled && ( + {useFeatureFlag('pilots')?.enabled && ( } /> )} } /> diff --git a/app/src/hooks/featureFlag/UseFeatureFlag.tsx b/app/src/hooks/featureFlag/UseFeatureFlag.tsx index 7b961c1..002f929 100644 --- a/app/src/hooks/featureFlag/UseFeatureFlag.tsx +++ b/app/src/hooks/featureFlag/UseFeatureFlag.tsx @@ -5,6 +5,6 @@ export const useFeatureFlag = (featureFlagKey: string) => { const featureFlag = appContext.state.featureFlags.find( (featureFlag) => featureFlag.key === featureFlagKey ); - + console.log(featureFlag) return featureFlag; }; diff --git a/infrastructure/config/main.tf b/infrastructure/config/main.tf index edaae33..103dd1c 100644 --- a/infrastructure/config/main.tf +++ b/infrastructure/config/main.tf @@ -3,7 +3,6 @@ locals { dev = "flying-app-dev" } - container_app_app_container_image = { dev = "noahspan/flying-app:v0.0.1" } @@ -32,6 +31,10 @@ locals { dev = "flying-dev" } + logbook_feature_flag_active = { + dev = "true" + } + key_vault_name = { dev = "noahspanflyingkeyvault" } @@ -40,11 +43,11 @@ locals { dev = "flying-log-analytics-workspace-dev" } + pilots_feature_flag_active = { + dev = "true" + } + storage_account_name = { dev = "noahspanflyingdev" } - - user_assigned_identity_name = { - dev = "noahspanflyingdevuser" - } } \ No newline at end of file diff --git a/infrastructure/config/outputs.tf b/infrastructure/config/outputs.tf index ed09076..fea3171 100644 --- a/infrastructure/config/outputs.tf +++ b/infrastructure/config/outputs.tf @@ -34,14 +34,18 @@ output "key_vault_name" { value = local.key_vault_name[var.environment] } +output "logbook_feature_flag_active" { + value = local.logbook_feature_flag_active[var.environment] +} + output "log_analytics_workspace_name" { value = local.log_analytics_workspace_name[var.environment] } -output "storage_account_name" { - value = local.storage_account_name[var.environment] +output "pilots_feature_flag_active" { + value = local.pilots_feature_flag_active[var.environment] } -output "user_assigned_identity_name" { - value = local.user_assigned_identity_name[var.environment] +output "storage_account_name" { + value = local.storage_account_name[var.environment] } \ No newline at end of file diff --git a/infrastructure/dapr.tf b/infrastructure/dapr.tf deleted file mode 100644 index 59edf9e..0000000 --- a/infrastructure/dapr.tf +++ /dev/null @@ -1,66 +0,0 @@ -resource "azurerm_container_app_environment_dapr_component" "table_storage_pilots_dapr_component" { - name = "table-storage-pilots" - container_app_environment_id = azurerm_container_app_environment.container_app_environment.id - component_type = "state.azure.tablestorage" - version = "v1" - - metadata { - name = "accountName" - value = azurerm_storage_account.storage_account.name - } - - metadata { - name = "azureClientId" - value = azurerm_user_assigned_identity.user_assigned_identity.id - } - - metadata { - name = "tableName" - value = "Pilots" - } - - scopes = [ azurerm_container_app.container_app_api.dapr[0].app_id ] -} - -resource "azurerm_container_app_environment_dapr_component" "table_storage_logbook_dapr_component" { - name = "table-storage-logbook" - container_app_environment_id = azurerm_container_app_environment.container_app_environment.id - component_type = "state.azure.tablestorage" - version = "v1" - - metadata { - name = "accountName" - value = azurerm_storage_account.storage_account.name - } - - metadata { - name = "azureClientId" - value = azurerm_user_assigned_identity.user_assigned_identity.client_id - } - - metadata { - name = "tableName" - value = "Logbook" - } - - scopes = [ azurerm_container_app.container_app_api.dapr[0].app_id ] -} - -resource "azurerm_container_app_environment_dapr_component" "key_vault_dapr_component" { - name = "key-vault" - container_app_environment_id = azurerm_container_app_environment.container_app_environment.id - component_type = "secretstores.azure.keyvault" - version = "v1" - - metadata { - name = "vaultName" - value = azurerm_key_vault.key_vault.name - } - - metadata { - name = "azureClientId" - value = azurerm_user_assigned_identity.user_assigned_identity.client_id - } - - scopes = [ azurerm_container_app.container_app_api.dapr[0].app_id ] -} \ No newline at end of file diff --git a/infrastructure/identity.tf b/infrastructure/identity.tf deleted file mode 100644 index 866f96d..0000000 --- a/infrastructure/identity.tf +++ /dev/null @@ -1,5 +0,0 @@ -resource "azurerm_user_assigned_identity" "user_assigned_identity" { - name = module.environment.user_assigned_identity_name - resource_group_name = data.azurerm_resource_group.resource_group.name - location = data.azurerm_resource_group.resource_group.location -} \ No newline at end of file diff --git a/infrastructure/key_vault.tf b/infrastructure/key_vault.tf deleted file mode 100644 index e493fb3..0000000 --- a/infrastructure/key_vault.tf +++ /dev/null @@ -1,70 +0,0 @@ -resource "azurerm_key_vault" "key_vault" { - name = module.environment.key_vault_name - resource_group_name = data.azurerm_resource_group.resource_group.name - location = data.azurerm_resource_group.resource_group.location - tenant_id = data.azurerm_client_config.current.tenant_id - soft_delete_retention_days = 7 - sku_name = "standard" -} - -resource "azurerm_key_vault_access_policy" "key_vault_access_policy_cli" { - key_vault_id = azurerm_key_vault.key_vault.id - tenant_id = data.azurerm_client_config.current.tenant_id - object_id = data.azurerm_client_config.current.object_id - - key_permissions = [ - "Create", - "Get", - ] - - secret_permissions = [ - "Set", - "Get", - "Delete", - "Purge", - "Recover" - ] -} - -resource "azurerm_key_vault_access_policy" "key_vault_access_policy_user_assigned_identity" { - key_vault_id = azurerm_key_vault.key_vault.id - tenant_id = data.azurerm_client_config.current.tenant_id - object_id = azurerm_user_assigned_identity.user_assigned_identity.principal_id - - key_permissions = [ - "Create", - "Get", - ] - - secret_permissions = [ - "Set", - "Get", - "Delete", - "Purge", - "Recover" - ] -} - -resource "azurerm_key_vault_secret" "client_id_key_vault_secret" { - name = "client-id" - value = var.CLIENT_ID - key_vault_id = azurerm_key_vault.key_vault.id - - depends_on = [ azurerm_key_vault_access_policy.key_vault_access_policy_cli ] -} - -resource "azurerm_key_vault_secret" "client_secret_key_vault_secret" { - name = "client-secret" - value = var.CLIENT_SECRET - key_vault_id = azurerm_key_vault.key_vault.id - - depends_on = [ azurerm_key_vault_access_policy.key_vault_access_policy_cli ] -} - -resource "azurerm_key_vault_secret" "tenant_id_key_vault_secret" { - name = "tenant-id" - value = var.TENANT_ID - key_vault_id = azurerm_key_vault.key_vault.id - - depends_on = [ azurerm_key_vault_access_policy.key_vault_access_policy_cli ] -} \ No newline at end of file diff --git a/infrastructure/main.tf b/infrastructure/main.tf index 6ad11f5..7a88ee9 100644 --- a/infrastructure/main.tf +++ b/infrastructure/main.tf @@ -42,6 +42,26 @@ resource "azurerm_container_app" "container_app_api" { image = module.environment.container_app_api_container_image cpu = 0.25 memory = "0.5Gi" + + env { + name = "AZURE_STORAGE_CONNECTION_STRING" + secret_name = "azure-storage-connection-string" + } + + env { + name = "CLIENT_ID" + secret_name = "client-id" + } + + env { + name = "CLIENT_SECRET" + secret_name = "client-secret" + } + + env { + name = "TENANT_ID" + secret_name = "tenant-id" + } } } @@ -62,6 +82,26 @@ resource "azurerm_container_app" "container_app_api" { value = var.DOCKER_IO_PASSWORD } + secret { + name = "azure-storage-connection-string" + value = var.AZURE_STORAGE_CONNECTION_STRING + } + + secret { + name = "client-id" + value = var.CLIENT_ID + } + + secret { + name = "client-secret" + value = var.CLIENT_SECRET + } + + secret { + name = "tenant-id" + value = var.TENANT_ID + } + lifecycle { ignore_changes = [ template[0].container[0].image ] } diff --git a/infrastructure/storage_account.tf b/infrastructure/storage_account.tf index 8d79199..e55c1aa 100644 --- a/infrastructure/storage_account.tf +++ b/infrastructure/storage_account.tf @@ -4,11 +4,6 @@ resource "azurerm_storage_account" "storage_account" { location = data.azurerm_resource_group.resource_group.location account_tier = "Standard" account_replication_type = "LRS" - - identity { - type = "UserAssigned" - identity_ids = [azurerm_user_assigned_identity.user_assigned_identity.id] - } } resource "azurerm_storage_table" "logs_table" { @@ -19,4 +14,31 @@ resource "azurerm_storage_table" "logs_table" { resource "azurerm_storage_table" "pilot_table" { name = "pilots" storage_account_name = azurerm_storage_account.storage_account.name +} + +resource "azurerm_storage_table" "feature_flags_table" { + name = "featureFlags" + storage_account_name = azurerm_storage_account.storage_account.name +} + +resource "azurerm_storage_table_entity" "logbook_feature_flag_entity" { + storage_table_id = azurerm_storage_table.feature_flags_table.id + + partition_key = "featureFlag" + row_key = "logbook" + + entity = { + active = module.environment.logbook_feature_flag_active + } +} + +resource "azurerm_storage_table_entity" "pilots_feature_flag_entity" { + storage_table_id = azurerm_storage_table.feature_flags_table.id + + partition_key = "featureFlag" + row_key = "pilots" + + entity = { + active = module.environment.pilots_feature_flag_active + } } \ No newline at end of file diff --git a/infrastructure/variables.tf b/infrastructure/variables.tf index 43a102d..6b3bdbc 100644 --- a/infrastructure/variables.tf +++ b/infrastructure/variables.tf @@ -6,6 +6,10 @@ variable "APP_SUBDOMAIN_NAME" { type = string } +variable "AZURE_STORAGE_CONNECTION_STRING" { + type = string +} + variable "CLIENT_ID" { type = string }