Tools Early access builder

Build an Azure deployment package through guided choices.

Configure a modern .NET 8 isolated Function workload and generate original Bicep modules, environment files, documentation and a deployment pipeline without copying organization-specific templates.

Local-first Generic names only Bicep-first Feedback encouraged
Original, generic output

GateSift generates from original, neutral templates rather than republishing organization-specific source files. Generated files use generic names and public Azure patterns. Still review your employment and client agreements before publishing work created on company time.

Report a template problem
Azure Function workload

gatesift-sample / orders

.NET 8 isolated on Flex Consumption with identity-based runtime connections.

8Resource types
3Environments
12Generated files
Managed identity Shared-key storage disabled TLS 1.2 minimum RBAC-based access What-if before deployment
Review before deploymentReplace the Azure DevOps service connection placeholder before running the pipeline.
Review before deploymentEarly access generates public Azure endpoints with identity-based authentication. Private endpoints and DNS integration are intentionally not generated yet.
infra/main.bicepResource-group orchestration template
targetScope = 'resourceGroup'

@description('Short product or solution name used in resource names.')
@minLength(2)
@maxLength(32)
param projectName string

@description('Short workload name used in resource names.')
@minLength(2)
@maxLength(32)
param workloadName string

@allowed([
  'dev'
  'test'
  'prod'
])
param environment string

@description('Azure region for all resources.')
param location string = resourceGroup().location

@description('Deploy an Azure Service Bus namespace and queue.')
param includeServiceBus bool = true

@description('Queue name when Service Bus is enabled.')
param serviceBusQueueName string = 'messages'

@allowed([
  'send'
  'receive'
  'send-receive'
])
param serviceBusAccess string = 'send-receive'

@description('Deploy an Azure Key Vault using Azure RBAC.')
param includeKeyVault bool = true

@description('Tags applied to generated Azure resources.')
param tags object = {}

var compactProjectName = replace(toLower(projectName), '-', '')
var compactWorkloadName = replace(toLower(workloadName), '-', '')
var uniqueSuffix = take(uniqueString(subscription().id, resourceGroup().id, projectName, workloadName, environment), 6)
var readablePrefix = take(toLower('${projectName}-${workloadName}-${environment}'), 42)
var compactPrefix = take('${compactProjectName}${compactWorkloadName}${environment}', 17)

var generatedFunctionAppName = take('func-${readablePrefix}-${uniqueSuffix}', 60)
var functionPlanName = take('plan-${readablePrefix}-${uniqueSuffix}', 60)
var identityName = take('id-${readablePrefix}-${uniqueSuffix}', 64)
var generatedStorageAccountName = take('st${compactPrefix}${uniqueSuffix}', 24)
var deploymentContainerName = take('app-package-${compactPrefix}', 63)
var logAnalyticsName = take('log-${readablePrefix}-${uniqueSuffix}', 63)
var generatedApplicationInsightsName = take('appi-${readablePrefix}-${uniqueSuffix}', 255)
var generatedServiceBusNamespaceName = take('sbns-${readablePrefix}-${uniqueSuffix}', 50)
var generatedKeyVaultName = take('kv-${compactPrefix}-${uniqueSuffix}', 24)

var commonTags = union(tags, {
  environment: environment
  workload: workloadName
  managedBy: 'GateSift deployment builder'
})

var storageBlobDataOwnerRoleId = 'b7e6dc6d-f1e8-4753-8033-0f276bb0955b'
var storageQueueDataContributorRoleId = '974c5e8b-45b9-4653-ba55-5f855dd0fb88'
var storageTableDataContributorRoleId = '0a9a7e1f-b9d0-4cc4-a60d-0319b160aaa3'
var monitoringMetricsPublisherRoleId = '3913510d-42f4-4e42-8a64-420c390055eb'
var serviceBusDataSenderRoleId = '69a216fc-b8fb-44d8-bc22-1f3c2cd27a39'
var serviceBusDataReceiverRoleId = '4f6d3b9b-027b-4f4c-9142-0e5a2a2247e0'
var keyVaultSecretsUserRoleId = '4633458b-17de-408a-b874-0445c86b69e6'

module monitoring './modules/monitoring.bicep' = {
  name: 'monitoring-${uniqueSuffix}'
  params: {
    location: location
    logAnalyticsName: logAnalyticsName
    applicationInsightsName: generatedApplicationInsightsName
    tags: commonTags
  }
}

module storage './modules/storage.bicep' = {
  name: 'storage-${uniqueSuffix}'
  params: {
    location: location
    storageAccountName: generatedStorageAccountName
    deploymentContainerName: deploymentContainerName
    tags: commonTags
  }
}

resource workloadIdentity 'Microsoft.ManagedIdentity/userAssignedIdentities@2023-01-31' = {
  name: identityName
  location: location
  tags: commonTags
}

module serviceBus './modules/service-bus.bicep' = if (includeServiceBus) {
  name: 'service-bus-${uniqueSuffix}'
  params: {
    location: location
    namespaceName: generatedServiceBusNamespaceName
    queueName: serviceBusQueueName
    tags: commonTags
  }
}

module keyVault './modules/key-vault.bicep' = if (includeKeyVault) {
  name: 'key-vault-${uniqueSuffix}'
  params: {
    location: location
    keyVaultName: generatedKeyVaultName
    enablePurgeProtection: environment == 'prod'
    tags: commonTags
  }
}

resource storageAccount 'Microsoft.Storage/storageAccounts@2023-05-01' existing = {
  name: storage.outputs.deployedStorageAccountName
}

resource applicationInsights 'Microsoft.Insights/components@2020-02-02' existing = {
  name: monitoring.outputs.deployedApplicationInsightsName
}

resource storageBlobOwner 'Microsoft.Authorization/roleAssignments@2022-04-01' = {
  name: guid(storageAccount.id, workloadIdentity.id, storageBlobDataOwnerRoleId)
  scope: storageAccount
  properties: {
    roleDefinitionId: subscriptionResourceId('Microsoft.Authorization/roleDefinitions', storageBlobDataOwnerRoleId)
    principalId: workloadIdentity.properties.principalId
    principalType: 'ServicePrincipal'
  }
}

resource storageQueueContributor 'Microsoft.Authorization/roleAssignments@2022-04-01' = {
  name: guid(storageAccount.id, workloadIdentity.id, storageQueueDataContributorRoleId)
  scope: storageAccount
  properties: {
    roleDefinitionId: subscriptionResourceId('Microsoft.Authorization/roleDefinitions', storageQueueDataContributorRoleId)
    principalId: workloadIdentity.properties.principalId
    principalType: 'ServicePrincipal'
  }
}

resource storageTableContributor 'Microsoft.Authorization/roleAssignments@2022-04-01' = {
  name: guid(storageAccount.id, workloadIdentity.id, storageTableDataContributorRoleId)
  scope: storageAccount
  properties: {
    roleDefinitionId: subscriptionResourceId('Microsoft.Authorization/roleDefinitions', storageTableDataContributorRoleId)
    principalId: workloadIdentity.properties.principalId
    principalType: 'ServicePrincipal'
  }
}

resource monitoringPublisher 'Microsoft.Authorization/roleAssignments@2022-04-01' = {
  name: guid(applicationInsights.id, workloadIdentity.id, monitoringMetricsPublisherRoleId)
  scope: applicationInsights
  properties: {
    roleDefinitionId: subscriptionResourceId('Microsoft.Authorization/roleDefinitions', monitoringMetricsPublisherRoleId)
    principalId: workloadIdentity.properties.principalId
    principalType: 'ServicePrincipal'
  }
}

resource serviceBusNamespace 'Microsoft.ServiceBus/namespaces@2024-01-01' existing = if (includeServiceBus) {
  name: serviceBus.outputs.deployedNamespaceName
}

resource serviceBusSender 'Microsoft.Authorization/roleAssignments@2022-04-01' = if (includeServiceBus && (serviceBusAccess == 'send' || serviceBusAccess == 'send-receive')) {
  name: guid(serviceBusNamespace.id, workloadIdentity.id, serviceBusDataSenderRoleId)
  scope: serviceBusNamespace
  properties: {
    roleDefinitionId: subscriptionResourceId('Microsoft.Authorization/roleDefinitions', serviceBusDataSenderRoleId)
    principalId: workloadIdentity.properties.principalId
    principalType: 'ServicePrincipal'
  }
}

resource serviceBusReceiver 'Microsoft.Authorization/roleAssignments@2022-04-01' = if (includeServiceBus && (serviceBusAccess == 'receive' || serviceBusAccess == 'send-receive')) {
  name: guid(serviceBusNamespace.id, workloadIdentity.id, serviceBusDataReceiverRoleId)
  scope: serviceBusNamespace
  properties: {
    roleDefinitionId: subscriptionResourceId('Microsoft.Authorization/roleDefinitions', serviceBusDataReceiverRoleId)
    principalId: workloadIdentity.properties.principalId
    principalType: 'ServicePrincipal'
  }
}

resource vault 'Microsoft.KeyVault/vaults@2023-07-01' existing = if (includeKeyVault) {
  name: keyVault.outputs.deployedKeyVaultName
}

resource keyVaultSecretsUser 'Microsoft.Authorization/roleAssignments@2022-04-01' = if (includeKeyVault) {
  name: guid(vault.id, workloadIdentity.id, keyVaultSecretsUserRoleId)
  scope: vault
  properties: {
    roleDefinitionId: subscriptionResourceId('Microsoft.Authorization/roleDefinitions', keyVaultSecretsUserRoleId)
    principalId: workloadIdentity.properties.principalId
    principalType: 'ServicePrincipal'
  }
}

var serviceBusSettings = includeServiceBus ? {
  'ServiceBus__fullyQualifiedNamespace': serviceBus.outputs.fullyQualifiedNamespace
  'ServiceBus__queueName': serviceBusQueueName
} : {}

var keyVaultSettings = includeKeyVault ? {
  'KeyVault__vaultUri': keyVault.outputs.vaultUri
} : {}

module functionApp './modules/function-app-flex.bicep' = {
  name: 'function-app-${uniqueSuffix}'
  params: {
    location: location
    functionAppName: generatedFunctionAppName
    planName: functionPlanName
    identityResourceId: workloadIdentity.id
    identityClientId: workloadIdentity.properties.clientId
    storageAccountName: storage.outputs.deployedStorageAccountName
    deploymentContainerUri: storage.outputs.deploymentContainerUri
    applicationInsightsConnectionString: monitoring.outputs.applicationInsightsConnectionString
    additionalAppSettings: union(serviceBusSettings, keyVaultSettings)
    tags: commonTags
  }
  dependsOn: [
    storageBlobOwner
    storageQueueContributor
    storageTableContributor
    monitoringPublisher
  ]
}

output functionAppName string = functionApp.outputs.deployedFunctionAppName
output functionAppHostName string = functionApp.outputs.defaultHostName
output managedIdentityName string = workloadIdentity.name
output storageAccountName string = storage.outputs.deployedStorageAccountName
output applicationInsightsName string = monitoring.outputs.deployedApplicationInsightsName
output serviceBusNamespaceName string = includeServiceBus ? serviceBus.outputs.deployedNamespaceName : ''
output keyVaultName string = includeKeyVault ? keyVault.outputs.deployedKeyVaultName : ''
Download the complete deployment packageBicep modules, environment parameters, documentation and the selected pipeline.

Early-access boundary: private endpoints, private DNS, existing landing zones and organization-specific naming rules are not guessed. The generated README explains what still needs deliberate design.