Files
Orchestrator/bahn/db-planet-mcp-server/infra/main.bicep
ankn a5f8fb49ab Migrate all repos into monorepo context folders
Bahn: aisupport, Analyse-O2C-C2S, awesome-bahn-mcp-servers, beam-mcp,
      Confluence_Bot, db-planet-mcp-server, O2C-Harness, project-audit,
      Projekt-KIQ-HP, teamlandkarte-mcp
Dhive: Jury-Voting
Privat: CV, NoteGraph (NOTE: NoteGraph needs complete redo after consolidation)
Shared: AI-Orchestrator, OrgMyLife, power_skills_and_more
Shared/references: symphony (read-only)

Bahn repos remain available as independent remotes - this monorepo
pulls them in via subtree, the originals are untouched.
2026-06-30 20:39:52 +02:00

244 lines
11 KiB
Bicep

// DB Planet MCP Server Infrastructure
// Deploys: Resource Group, Managed Identity, Key Vault,
// Application Insights, Container App, Key Vault permissions
targetScope = 'subscription'
// ── Core parameters ──────────────────────────────────────────
@description('Environment name')
@allowed(['DEV', 'IAT', 'Prod'])
param environment string
@description('Azure region')
param location string = 'westeurope'
@description('Container image tag')
param imageTag string = 'latest'
@description('Set to true on second deployment after infra + permissions are in place')
param deployContainerApp bool = false
// ── Tags ─────────────────────────────────────────────────────
@description('Tags applied to all resources')
param tags object = {
CostReference: 'H-450007-52-01'
ReferenceID: 'A-113241'
ReferenceName: 'DB Planet MCP Server'
Environment: environment
}
// ── Existing infrastructure references ───────────────────────
@description('Central Key Vault name (shared secrets)')
param centralKeyVaultName string
@description('Central Key Vault resource group')
param centralKeyVaultResourceGroup string
@description('Container App Environment name')
param containerAppEnvironmentName string
@description('Container App Environment resource group')
param containerAppEnvironmentResourceGroup string
// ── Application configuration ────────────────────────────────
@description('Artifactory server URL')
param artifactoryServer string
@description('Registry username')
param registryUsername string
@description('DB Planet base URL (staging vs production)')
param dbplanetBaseUrl string
// ── Service Principal for Key Vault secrets management ───────
#disable-next-line secure-secrets-in-params // Object ID, not a secret
@description('Service Principal Object ID for Key Vault Secrets Officer role')
param secretsOfficerPrincipalId string = ''
// ── Custom domain (optional) ─────────────────────────────────
@description('Certificate name in Container App Environment')
param certificateName string = ''
@description('DNS zone name for custom domain')
param dnsZoneName string = ''
@description('DNS record name (subdomain)')
param dnsRecordName string = ''
@description('Resource group containing the DNS zone')
param dnsZoneResourceGroup string = 'Infrastructure'
// ── Derived values ───────────────────────────────────────────
var resourceGroupName = 'rg-dbplanet-mcp-${toLower(environment)}'
var resourceToken = toLower(uniqueString(subscription().id, resourceGroupName, location))
// ═══════════════════════════════════════════════════════════════
// 1. Resource Group
// ═══════════════════════════════════════════════════════════════
module rg 'modules/resource-group.bicep' = {
name: 'deploy-rg'
params: {
resourceGroupName: resourceGroupName
location: location
tags: tags
}
}
// ═══════════════════════════════════════════════════════════════
// 2. Managed Identity
// ═══════════════════════════════════════════════════════════════
module identity 'modules/managed-identity.bicep' = {
name: 'deploy-identity'
scope: resourceGroup(resourceGroupName)
dependsOn: [rg]
params: {
environment: environment
location: location
tags: tags
resourceToken: resourceToken
}
}
// ═══════════════════════════════════════════════════════════════
// 3. Key Vault (app-specific, public access)
// ═══════════════════════════════════════════════════════════════
module keyVault 'modules/keyvault.bicep' = {
name: 'deploy-keyvault'
scope: resourceGroup(resourceGroupName)
dependsOn: [rg]
params: {
environment: environment
location: location
tags: tags
resourceToken: resourceToken
}
}
// ═══════════════════════════════════════════════════════════════
// 4. Application Insights + Log Analytics
// ═══════════════════════════════════════════════════════════════
module appInsights 'modules/application-insights.bicep' = {
name: 'deploy-app-insights'
scope: resourceGroup(resourceGroupName)
params: {
environment: environment
location: location
tags: tags
resourceToken: resourceToken
keyVaultName: keyVault.outputs.keyVaultName
}
}
// ═══════════════════════════════════════════════════════════════
// 5. Container App Certificate (existing, optional)
// ═══════════════════════════════════════════════════════════════
module certificate 'modules/container-app-certificate.bicep' = if (!empty(certificateName)) {
name: 'deploy-certificate'
scope: resourceGroup(containerAppEnvironmentResourceGroup)
params: {
containerAppEnvironmentName: containerAppEnvironmentName
certificateName: certificateName
}
}
// ═══════════════════════════════════════════════════════════════
// 6. Container App
// ═══════════════════════════════════════════════════════════════
var customDomainName = !empty(dnsRecordName) && !empty(dnsZoneName) ? '${dnsRecordName}.${dnsZoneName}' : ''
module containerApp 'modules/container-app.bicep' = if (deployContainerApp) {
name: 'deploy-container-app'
scope: resourceGroup(resourceGroupName)
dependsOn: [rg]
params: {
environment: environment
location: location
tags: tags
resourceToken: resourceToken
centralKeyVaultName: centralKeyVaultName
centralKeyVaultResourceGroup: centralKeyVaultResourceGroup
appKeyVaultUri: keyVault.outputs.keyVaultUri
containerAppEnvironmentName: containerAppEnvironmentName
containerAppEnvironmentResourceGroup: containerAppEnvironmentResourceGroup
artifactoryServer: artifactoryServer
registryUsername: registryUsername
managedIdentityId: identity.outputs.managedIdentityId
imageTag: imageTag
dbplanetBaseUrl: dbplanetBaseUrl
customDomainName: !empty(certificateName) ? customDomainName : ''
containerAppCertificateId: !empty(certificateName) ? certificate.outputs.certificateId! : ''
}
}
// ═══════════════════════════════════════════════════════════════
// 7. DNS Record
// ═══════════════════════════════════════════════════════════════
module dnsRecord 'modules/dns-record.bicep' = if (deployContainerApp && !empty(dnsRecordName)) {
name: 'deploy-dns-record'
scope: resourceGroup(dnsZoneResourceGroup)
params: {
privateDnsZoneName: dnsZoneName
aRecordName: dnsRecordName
ipv4Address: containerApp.outputs.containerAppEnvironmentStaticIp!
}
}
// ═══════════════════════════════════════════════════════════════
// 8. Key Vault Permissions
// ═══════════════════════════════════════════════════════════════
// 6a. Managed Identity → central Key Vault (read registry secrets)
module centralKvPermissions 'modules/key-vault-permissions.bicep' = {
name: 'deploy-central-kv-permissions'
scope: resourceGroup(centralKeyVaultResourceGroup)
params: {
keyVaultName: centralKeyVaultName
principalId: identity.outputs.managedIdentityPrincipalId
roleName: 'Key Vault Secrets User'
}
}
// 6b. Managed Identity → app Key Vault (read app secrets)
module appKvIdentityPermissions 'modules/key-vault-permissions.bicep' = {
name: 'deploy-app-kv-identity-permissions'
scope: resourceGroup(resourceGroupName)
params: {
keyVaultName: keyVault.outputs.keyVaultName
principalId: identity.outputs.managedIdentityPrincipalId
roleName: 'Key Vault Secrets User'
}
}
// 6c. Container App system identity → app Key Vault (read app secrets)
module appKvContainerAppPermissions 'modules/key-vault-permissions.bicep' = if (deployContainerApp) {
name: 'deploy-app-kv-ca-permissions'
scope: resourceGroup(resourceGroupName)
params: {
keyVaultName: keyVault.outputs.keyVaultName
principalId: containerApp.outputs.systemIdentityPrincipalId!
roleName: 'Key Vault Secrets User'
}
}
// 6d. Service Principal → app Key Vault (read + write secrets for CI/CD)
module appKvOfficerPermissions 'modules/key-vault-permissions.bicep' = if (!empty(secretsOfficerPrincipalId)) {
name: 'deploy-app-kv-officer-permissions'
scope: resourceGroup(resourceGroupName)
params: {
keyVaultName: keyVault.outputs.keyVaultName
principalId: secretsOfficerPrincipalId
roleName: 'Key Vault Secrets Officer'
}
}
// ═══════════════════════════════════════════════════════════════
// Outputs
// ═══════════════════════════════════════════════════════════════
output resourceGroupName string = rg.outputs.resourceGroupName
output keyVaultName string = keyVault.outputs.keyVaultName
output keyVaultUri string = keyVault.outputs.keyVaultUri
output containerAppName string = deployContainerApp ? containerApp.outputs.containerAppName! : ''
output containerAppFqdn string = deployContainerApp ? containerApp.outputs.containerAppFqdn! : ''
output managedIdentityId string = identity.outputs.managedIdentityId
output appInsightsName string = appInsights.outputs.applicationInsightsName