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.
This commit is contained in:
2026-06-30 20:39:52 +02:00
parent 2f2b295531
commit a5f8fb49ab
1717 changed files with 447332 additions and 0 deletions
+105
View File
@@ -0,0 +1,105 @@
#!/bin/bash
# Deployment script for DB Planet MCP Server
# Usage: ./infra/deploy.sh --environment DEV|IAT|Prod [--image-tag TAG]
set -e
ENVIRONMENT=""
IMAGE_TAG=""
LOCATION="westeurope"
while [[ $# -gt 0 ]]; do
case $1 in
-e|--environment) ENVIRONMENT="$2"; shift 2 ;;
-t|--image-tag) IMAGE_TAG="$2"; shift 2 ;;
-h|--help)
echo "Usage: $0 -e ENV [-t IMAGE_TAG]"
echo " -e, --environment DEV, IAT, or Prod"
echo " -t, --image-tag Container image tag (optional, uses param file default)"
exit 0 ;;
*) echo "Unknown option: $1"; exit 1 ;;
esac
done
if [[ ! "$ENVIRONMENT" =~ ^(DEV|IAT|Prod)$ ]]; then
echo "❌ Environment must be DEV, IAT, or Prod"
exit 1
fi
ENV_LOWER=$(echo "$ENVIRONMENT" | tr '[:upper:]' '[:lower:]')
PARAM_FILE="infra/parameters/${ENV_LOWER}.bicepparam"
if [[ ! -f "$PARAM_FILE" ]]; then
echo "❌ Parameter file not found: $PARAM_FILE"
exit 1
fi
echo "🚀 Deploying DB Planet MCP Server — $ENVIRONMENT"
echo " Parameter file: $PARAM_FILE"
[[ -n "$IMAGE_TAG" ]] && echo " Image tag: $IMAGE_TAG"
echo ""
# Step 1: Deploy infrastructure (RG, Identity, Key Vault, App Insights, RBAC)
DEPLOY_NAME="dbplanet-mcp-${ENV_LOWER}-$(date +%Y%m%d-%H%M%S)"
echo " Step 1: Deploying infrastructure..."
if ! az deployment sub create \
--location "$LOCATION" \
--parameters "$PARAM_FILE" \
--name "$DEPLOY_NAME"; then
echo "❌ Infrastructure deployment failed"
exit 1
fi
echo "✅ Infrastructure deployed"
echo ""
# Step 2: Deploy Container App
echo "📦 Step 2: Deploying Container App..."
DEPLOY_ARGS=("--location" "$LOCATION" "--parameters" "$PARAM_FILE"
"--parameters" "deployContainerApp=true"
"--name" "${DEPLOY_NAME}-app")
[[ -n "$IMAGE_TAG" ]] && DEPLOY_ARGS+=("--parameters" "imageTag=$IMAGE_TAG")
if ! az deployment sub create "${DEPLOY_ARGS[@]}"; then
echo "❌ Container App deployment failed"
exit 1
fi
echo "✅ Container App deployed"
echo ""
# Step 3: Verify
echo "🔍 Step 3: Verifying deployment..."
CA_NAME=$(az deployment sub show --name "${DEPLOY_NAME}-app" \
--query "properties.outputs.containerAppName.value" -o tsv)
CA_FQDN=$(az deployment sub show --name "${DEPLOY_NAME}-app" \
--query "properties.outputs.containerAppFqdn.value" -o tsv)
echo " Container App: $CA_NAME"
echo " FQDN: $CA_FQDN"
# Wait for healthy revision
RG_NAME="rg-dbplanet-mcp-${ENV_LOWER}"
for i in $(seq 1 10); do
STATE=$(az containerapp revision list --name "$CA_NAME" \
--resource-group "$RG_NAME" \
--query "[?properties.active].properties.runningState | [0]" -o tsv 2>/dev/null)
if [[ "$STATE" == "Running" || "$STATE" == "RunningAtMaxScale" ]]; then
echo " ✅ Revision is Running + Healthy"
break
fi
echo " ⏳ Waiting for revision ($STATE)... ($i/10)"
if [[ "$i" -eq 10 ]]; then
echo " ❌ Revision did not reach Running state after 10 attempts"
exit 1
fi
sleep 15
done
echo ""
echo "🎉 Deployment complete!"
echo " Health: https://${CA_FQDN}/health"
+243
View File
@@ -0,0 +1,243 @@
// 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
@@ -0,0 +1,71 @@
// Application Insights module
@description('The environment name (DEV, IAT, Prod)')
param environment string
@description('The location for Application Insights')
param location string
@description('Tags to apply to resources')
param tags object
@description('Unique token for resource naming')
param resourceToken string
@description('Key Vault name for storing connection string')
param keyVaultName string
var appInsightsName = 'appi-dbp-${toLower(environment)}-${resourceToken}'
var logAnalyticsWorkspaceName = 'log-dbp-${toLower(environment)}-${resourceToken}'
resource logAnalyticsWorkspace 'Microsoft.OperationalInsights/workspaces@2025-02-01' = {
name: logAnalyticsWorkspaceName
location: location
tags: tags
properties: {
sku: {
name: 'PerGB2018'
}
retentionInDays: environment == 'Prod' ? 90 : 30
features: {
enableLogAccessUsingOnlyResourcePermissions: true
}
}
}
resource applicationInsights 'Microsoft.Insights/components@2020-02-02' = {
name: appInsightsName
location: location
tags: tags
kind: 'web'
properties: {
Application_Type: 'web'
WorkspaceResourceId: logAnalyticsWorkspace.id
IngestionMode: 'LogAnalytics'
publicNetworkAccessForIngestion: 'Enabled'
publicNetworkAccessForQuery: 'Enabled'
}
}
resource keyVault 'Microsoft.KeyVault/vaults@2024-11-01' existing = {
name: keyVaultName
}
resource connectionStringSecret 'Microsoft.KeyVault/vaults/secrets@2024-11-01' = {
parent: keyVault
name: 'applicationinsights-connection-string'
properties: {
value: applicationInsights.properties.ConnectionString
attributes: {
enabled: true
}
}
}
output applicationInsightsName string = applicationInsights.name
output applicationInsightsId string = applicationInsights.id
output connectionString string = applicationInsights.properties.ConnectionString
output instrumentationKey string = applicationInsights.properties.InstrumentationKey
output logAnalyticsWorkspaceId string = logAnalyticsWorkspace.id
output logAnalyticsWorkspaceName string = logAnalyticsWorkspace.name
@@ -0,0 +1,18 @@
// Container App Environment Certificate module (existing)
@description('Container App Environment name')
param containerAppEnvironmentName string
@description('Certificate name in the Container App Environment')
param certificateName string
resource containerAppEnvironment 'Microsoft.App/managedEnvironments@2025-01-01' existing = {
name: containerAppEnvironmentName
}
resource containerAppCertificate 'Microsoft.App/managedEnvironments/certificates@2025-01-01' existing = {
name: certificateName
parent: containerAppEnvironment
}
output certificateId string = containerAppCertificate.id
@@ -0,0 +1,206 @@
// Container App module for DB Planet MCP Server
@description('The environment name (DEV, IAT, Prod)')
param environment string
@description('The location for the Container App')
param location string
@description('Tags to apply to resources')
param tags object
@description('Unique token for resource naming')
param resourceToken string
@description('Existing central Key Vault name (shared secrets)')
param centralKeyVaultName string
@description('Existing central Key Vault resource group')
param centralKeyVaultResourceGroup string
@description('App-specific Key Vault URI (created by keyvault.bicep)')
param appKeyVaultUri string
@description('Existing Container App Environment name')
param containerAppEnvironmentName string
@description('Existing Container App Environment resource group')
param containerAppEnvironmentResourceGroup string
@description('Artifactory server URL for container registry')
param artifactoryServer string
@description('Registry username for container registry authentication')
param registryUsername string
@description('Managed Identity ID for Key Vault access')
param managedIdentityId string
@description('Container image tag/version')
param imageTag string = 'latest'
@description('DB Planet base URL (staging vs production)')
param dbplanetBaseUrl string
@description('Custom domain name for the Container App')
param customDomainName string = ''
@description('Container App Certificate ID (if custom domain is configured)')
param containerAppCertificateId string = ''
var containerAppName = 'ca-dbp-${toLower(environment)}-${take(resourceToken, 8)}'
// Custom domain configuration
var customDomain = !empty(customDomainName) && !empty(containerAppCertificateId) ? [
{
name: customDomainName
certificateId: containerAppCertificateId
bindingType: 'SniEnabled'
}
] : []
// Reference existing central Key Vault
resource centralKeyVault 'Microsoft.KeyVault/vaults@2024-11-01' existing = {
name: centralKeyVaultName
scope: resourceGroup(centralKeyVaultResourceGroup)
}
// Reference existing Container App Environment
resource containerAppEnvironment 'Microsoft.App/managedEnvironments@2025-01-01' existing = {
name: containerAppEnvironmentName
scope: resourceGroup(containerAppEnvironmentResourceGroup)
}
// Container App
resource containerApp 'Microsoft.App/containerApps@2025-01-01' = {
name: containerAppName
location: location
tags: tags
identity: {
type: 'SystemAssigned, UserAssigned'
userAssignedIdentities: {
'${managedIdentityId}': {}
}
}
properties: {
managedEnvironmentId: containerAppEnvironment.id
workloadProfileName: 'Consumption'
configuration: {
ingress: {
external: true
targetPort: 4000
allowInsecure: false
customDomains: customDomain
traffic: [
{
weight: 100
latestRevision: true
}
]
}
secrets: [
{
name: 'artifactory-token'
keyVaultUrl: '${centralKeyVault.properties.vaultUri}secrets/artifactory-registry-token'
identity: managedIdentityId
}
{
name: 'appinsights-connection-string'
keyVaultUrl: '${appKeyVaultUri}secrets/applicationinsights-connection-string'
identity: 'system'
}
{
name: 'dbplanet-username'
keyVaultUrl: '${appKeyVaultUri}secrets/DBPLANET-USERNAME'
identity: 'system'
}
{
name: 'dbplanet-password'
keyVaultUrl: '${appKeyVaultUri}secrets/DBPLANET-PASSWORD'
identity: 'system'
}
{
name: 'dbplanet-client-id'
keyVaultUrl: '${appKeyVaultUri}secrets/DBPLANET-CLIENT-ID'
identity: 'system'
}
{
name: 'dbplanet-client-secret'
keyVaultUrl: '${appKeyVaultUri}secrets/DBPLANET-CLIENT-SECRET'
identity: 'system'
}
]
registries: [
{
server: artifactoryServer
username: registryUsername
passwordSecretRef: 'artifactory-token'
}
]
}
template: {
containers: [
{
name: 'dbplanet-mcp'
image: '${artifactoryServer}/db-planet-mcp-server:${imageTag}'
resources: {
cpu: json(environment == 'Prod' ? '1.0' : '0.5')
memory: environment == 'Prod' ? '2Gi' : '1Gi'
}
env: [
{ name: 'DBPLANET_BASE_URL', value: dbplanetBaseUrl }
{ name: 'DBPLANET_USERNAME', secretRef: 'dbplanet-username' }
{ name: 'DBPLANET_PASSWORD', secretRef: 'dbplanet-password' }
{ name: 'DBPLANET_CLIENT_ID', secretRef: 'dbplanet-client-id' }
{ name: 'DBPLANET_CLIENT_SECRET', secretRef: 'dbplanet-client-secret' }
{ name: 'NODE_ENV', value: environment == 'Prod' ? 'production' : 'development' }
{ name: 'HTTP_PROXY', value: 'http://webproxy.comp.db.de:8080' }
{ name: 'HTTPS_PROXY', value: 'http://webproxy.comp.db.de:8080' }
{ name: 'http_proxy', value: 'http://webproxy.comp.db.de:8080' }
{ name: 'https_proxy', value: 'http://webproxy.comp.db.de:8080' }
{ name: 'NO_PROXY', value: '169.254.169.254,169.254.170.2,cognitiveservices.azure.com,internal.deutschebahn.com,db.de' }
{ name: 'no_proxy', value: '169.254.169.254,169.254.170.2,cognitiveservices.azure.com,internal.deutschebahn.com,db.de' }
{ name: 'STREAMABLE_HTTP', value: 'true' }
{ name: 'REMOTE_AUTHORIZATION', value: 'true' }
{ name: 'HOST', value: '0.0.0.0' }
{
name: 'APPLICATIONINSIGHTS_CONNECTION_STRING'
secretRef: 'appinsights-connection-string'
}
]
probes: [
{
type: 'Readiness'
httpGet: {
path: '/health'
port: 4000
}
initialDelaySeconds: 5
periodSeconds: 30
}
{
type: 'Liveness'
httpGet: {
path: '/health'
port: 4000
}
initialDelaySeconds: 10
periodSeconds: 60
}
]
}
]
scale: {
minReplicas: 1
maxReplicas: 1
}
}
}
}
output containerAppName string = containerApp.name
output containerAppId string = containerApp.id
output containerAppFqdn string = containerApp.properties.configuration.ingress.fqdn
output systemIdentityPrincipalId string = containerApp.identity.principalId
output containerAppEnvironmentStaticIp string = containerAppEnvironment.properties.staticIp
@@ -0,0 +1,30 @@
// DNS A Record module for Container App access
@description('Private DNS Zone name')
param privateDnsZoneName string
@description('A Record name (subdomain)')
param aRecordName string
@description('IPv4 address to point to')
param ipv4Address string
resource privateDnsZone 'Microsoft.Network/privateDnsZones@2020-06-01' existing = {
name: privateDnsZoneName
}
resource aRecord 'Microsoft.Network/privateDnsZones/A@2020-06-01' = {
name: aRecordName
parent: privateDnsZone
properties: {
ttl: 3600
aRecords: [
{
ipv4Address: ipv4Address
}
]
}
}
output recordName string = aRecord.name
output fqdn string = '${aRecordName}.${privateDnsZoneName}'
@@ -0,0 +1,59 @@
// Key Vault permissions module - reusable for different roles and principals
@description('Key Vault name')
param keyVaultName string
@description('Principal ID for Key Vault access')
param principalId string
@description('Principal type (User, Group, ServicePrincipal)')
@allowed(['User', 'Group', 'ServicePrincipal'])
param principalType string = 'ServicePrincipal'
@description('Key Vault role to assign')
@allowed([
'Key Vault Administrator'
'Key Vault Certificates Officer'
'Key Vault Crypto Officer'
'Key Vault Crypto Service Encryption User'
'Key Vault Crypto User'
'Key Vault Reader'
'Key Vault Secrets Officer'
'Key Vault Secrets User'
])
param roleName string = 'Key Vault Secrets User'
var roleDefinitions = {
// gitleaks:allow
'Key Vault Administrator': '00482a5a-887f-4fb3-b363-3b7fe8e74483'
'Key Vault Certificates Officer': 'a4417e6f-fecd-4de8-b567-7b0420556985'
'Key Vault Crypto Officer': '14b46e9e-c2b7-41b4-b07b-48a6ebf60603'
'Key Vault Crypto Service Encryption User': 'e147488a-f6f5-4113-8e2d-b22465e65bf6'
// gitleaks:allow
'Key Vault Crypto User': '12338af0-0e69-4776-bea7-57ae8d297424'
// gitleaks:allow
'Key Vault Reader': '21090545-7ca7-4776-b22c-e363652d74d2'
// gitleaks:allow
'Key Vault Secrets Officer': 'b86a8fe4-44ce-4948-aee5-eccb2c155cd7'
// gitleaks:allow
'Key Vault Secrets User': '4633458b-17de-408a-b874-0445c86b69e6'
}
var roleDefinitionId = subscriptionResourceId('Microsoft.Authorization/roleDefinitions', roleDefinitions[roleName])
resource keyVault 'Microsoft.KeyVault/vaults@2024-11-01' existing = {
name: keyVaultName
}
resource keyVaultRoleAssignment 'Microsoft.Authorization/roleAssignments@2022-04-01' = {
name: guid(keyVault.id, principalId, roleName)
scope: keyVault
properties: {
roleDefinitionId: roleDefinitionId
principalId: principalId
principalType: principalType
}
}
output roleAssignmentId string = keyVaultRoleAssignment.id
output roleAssignmentName string = keyVaultRoleAssignment.name
@@ -0,0 +1,47 @@
// Azure Key Vault module (public access, no Private Endpoint)
@description('The environment name (DEV, IAT, Prod)')
param environment string
@description('The location for the Key Vault')
param location string
@description('Tags to apply to resources')
param tags object
@description('Unique token for resource naming')
param resourceToken string
@description('The tenant ID for Key Vault access')
param tenantId string = subscription().tenantId
var keyVaultName = 'kv-dbp-${toLower(environment)}-${take(resourceToken, 8)}'
resource keyVault 'Microsoft.KeyVault/vaults@2024-11-01' = {
name: keyVaultName
location: location
tags: tags
properties: {
sku: {
family: 'A'
name: 'standard'
}
tenantId: tenantId
enabledForDeployment: false
enabledForDiskEncryption: true
enabledForTemplateDeployment: true
enableSoftDelete: true
softDeleteRetentionInDays: 7
enablePurgeProtection: true
enableRbacAuthorization: true
publicNetworkAccess: 'Enabled'
networkAcls: {
defaultAction: 'Allow'
bypass: 'AzureServices'
}
}
}
output keyVaultName string = keyVault.name
output keyVaultId string = keyVault.id
output keyVaultUri string = keyVault.properties.vaultUri
@@ -0,0 +1,26 @@
// User Managed Identity module
@description('The environment name (DEV, IAT, Prod)')
param environment string
@description('The location for the managed identity')
param location string
@description('Tags to apply to resources')
param tags object
@description('Unique token for resource naming')
param resourceToken string
var managedIdentityName = 'id-dbplanet-${toLower(environment)}-${resourceToken}'
resource managedIdentity 'Microsoft.ManagedIdentity/userAssignedIdentities@2024-11-30' = {
name: managedIdentityName
location: location
tags: tags
}
output managedIdentityName string = managedIdentity.name
output managedIdentityId string = managedIdentity.id
output managedIdentityPrincipalId string = managedIdentity.properties.principalId
output managedIdentityClientId string = managedIdentity.properties.clientId
@@ -0,0 +1,21 @@
// Resource Group module
targetScope = 'subscription'
@description('The resource group name')
param resourceGroupName string
@description('The location for the resource group')
param location string
@description('Tags to apply to the resource group')
param tags object
resource resourceGroup 'Microsoft.Resources/resourceGroups@2025-04-01' = {
name: resourceGroupName
location: location
tags: tags
}
output resourceGroupName string = resourceGroup.name
output resourceGroupId string = resourceGroup.id
@@ -0,0 +1,29 @@
// Development environment parameters for DB Planet MCP Server
using '../main.bicep'
param environment = 'DEV'
param location = 'westeurope'
param imageTag = 'latest'
// ── Existing infrastructure ──────────────────────────────────
// gitleaks:allow
param centralKeyVaultName = 'bahngpt-kv-c76j3yuqbfnmq'
param centralKeyVaultResourceGroup = 'DevSecOps-DEV'
param containerAppEnvironmentName = 'cae-devsecops-dev-c76j3yuq'
param containerAppEnvironmentResourceGroup = 'DevSecOps-DEV'
// ── Registry ─────────────────────────────────────────────────
param artifactoryServer = 'generativeai-docker-stage-dev-local.bahnhub.tech.rz.db.de'
param registryUsername = 'techuser-generativeai'
// ── Application ──────────────────────────────────────────────
param dbplanetBaseUrl = 'https://dbahn-staging.haiilo.cloud'
// ── Permissions ──────────────────────────────────────────────
param secretsOfficerPrincipalId = ''
// ── Custom domain ────────────────────────────────────────────
param certificateName = 'wildcard-cert'
param dnsZoneName = 'genai-test.comp.db.de'
param dnsRecordName = 'dbplanet-dev'
param dnsZoneResourceGroup = 'Infrastructure'
@@ -0,0 +1,29 @@
// IAT environment parameters for DB Planet MCP Server
using '../main.bicep'
param environment = 'IAT'
param location = 'westeurope'
param imageTag = 'latest'
// ── Existing infrastructure ──────────────────────────────────
// gitleaks:allow
param centralKeyVaultName = 'bahngpt-kv-6i2jt7tebagcq'
param centralKeyVaultResourceGroup = 'DevSecOps-IAT'
param containerAppEnvironmentName = 'cae-devsecops-iat-6i2jt7te'
param containerAppEnvironmentResourceGroup = 'DevSecOps-IAT'
// ── Registry ─────────────────────────────────────────────────
param artifactoryServer = 'generativeai-docker-stage-iat-local.bahnhub.tech.rz.db.de'
param registryUsername = 'techuser-generativeai'
// ── Application ──────────────────────────────────────────────
param dbplanetBaseUrl = 'https://dbahn-staging.haiilo.cloud'
// ── Permissions ──────────────────────────────────────────────
param secretsOfficerPrincipalId = ''
// ── Custom domain ────────────────────────────────────────────
param certificateName = 'wildcard-cert'
param dnsZoneName = 'genai-test.comp.db.de'
param dnsRecordName = 'dbplanet-iat'
param dnsZoneResourceGroup = 'Infrastructure'