Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
10 changes: 10 additions & 0 deletions infrastructure/bicep/core/core.bicep
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,8 @@ var applicationInsightsName = 'appi-${compName}-${rg}-${env}'
var sqlServerName = 'sql-${compName}-${rg}-${env}'
var sqlDbName = 'sqldb-${compName}-${rg}-${env}'

var storageAccountName = 'st${compName}${rg}${env}'

// --- MODULES --- //
module networkSecurityGroup './modules/networkSecurityGroups.bicep' = {
name: 'networkSecurityGroup'
Expand Down Expand Up @@ -61,6 +63,7 @@ module applicationInsights './modules/applicationInsights.bicep' = {
name: 'applicationInsights'
params: {
applicationInsightsName: applicationInsightsName
logAnalyticsWorkspaceId: logAnalytics.outputs.workspaceId
}
}

Expand All @@ -80,3 +83,10 @@ module sqlServer './modules/sqlServer.bicep' = {
virtualNetworks
]
}

module storageAccount './modules/storageAccount.bicep' = {
name: 'storageAccount'
params: {
storageAccountName: storageAccountName
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -5,14 +5,18 @@ param location string = resourceGroup().location
@description('Name of the application insights')
param applicationInsightsName string

@description('Resource ID of the Log Analytics Workspace')
param logAnalyticsWorkspaceId string

// --- RESOURCES --- //
resource applicationInsights 'Microsoft.Insights/components@2020-02-02' = {
name: applicationInsightsName
location: location
kind: 'web'
properties: {
Application_Type: 'web'
IngestionMode: 'ApplicationInsights'
IngestionMode: 'LogAnalytics'
WorkspaceResourceId: logAnalyticsWorkspaceId
publicNetworkAccessForIngestion: 'Enabled'
publicNetworkAccessForQuery: 'Enabled'
}
Expand Down
3 changes: 3 additions & 0 deletions infrastructure/bicep/core/modules/logAnalytics.bicep
Original file line number Diff line number Diff line change
Expand Up @@ -21,3 +21,6 @@ resource logAnalyticsWorkspace 'Microsoft.OperationalInsights/workspaces@2025-02
publicNetworkAccessForQuery: 'Enabled'
}
}

// --- OUTPUT --- //
output workspaceId string = logAnalyticsWorkspace.id
64 changes: 64 additions & 0 deletions infrastructure/bicep/core/modules/storageAccount.bicep
Original file line number Diff line number Diff line change
@@ -0,0 +1,64 @@
// --- PARAMETERS --- //
@description('Azure Location/Region')
param location string = resourceGroup().location

@description('Name of the storage account')
param storageAccountName string

@description('SKU for the storage account')
@allowed(['Standard_LRS', 'Standard_GRS', 'Standard_ZRS'])
param skuName string = 'Standard_LRS'

@description('Enable blob versioning (required for object replication)')
param enableVersioning bool = true

@description('Enable change feed (required for object replication)')
param enableChangeFeed bool = true

@description('Container names to create')
param containerNames array = [
'kyc'
'support'
]

// --- RESOURCES --- //
resource storageAccount 'Microsoft.Storage/storageAccounts@2023-01-01' = {
name: storageAccountName
location: location
sku: {
name: skuName
}
kind: 'StorageV2'
properties: {
accessTier: 'Hot'
minimumTlsVersion: 'TLS1_2'
supportsHttpsTrafficOnly: true
allowBlobPublicAccess: false
}
}

resource blobServices 'Microsoft.Storage/storageAccounts/blobServices@2023-01-01' = {
parent: storageAccount
name: 'default'
properties: {
isVersioningEnabled: enableVersioning
changeFeed: {
enabled: enableChangeFeed
}
}
}

resource containers 'Microsoft.Storage/storageAccounts/blobServices/containers@2023-01-01' = [
for containerName in containerNames: {
parent: blobServices
name: containerName
properties: {
publicAccess: 'None'
}
}
]

// --- OUTPUT --- //
output storageAccountId string = storageAccount.id
output storageAccountName string = storageAccount.name
output primaryBlobEndpoint string = storageAccount.properties.primaryEndpoints.blob
Original file line number Diff line number Diff line change
@@ -0,0 +1,69 @@
#!/bin/sh
set -e

# --- OPTIONS --- #
environmentOptions=("dev" "prd")

# --- FUNCTIONS --- #
selectOption() {
PS3="${1}: "
shift
options=("$@")

select opt in "${options[@]}" "quit"; do
case "$REPLY" in
*) selection="${opt}"; break ;;
esac
done

if [[ ! $selection || $selection == "quit" ]]; then exit -1; fi
echo "${selection}"
}

ENV=$(selectOption "Select Environment" "${environmentOptions[@]}")

# Account Keys abrufen
SOURCE_KEY=$(az storage account keys list \
--account-name stdfxapi${ENV} \
--query "[0].value" -o tsv)

DEST_KEY=$(az storage account keys list \
--account-name stdfxcore${ENV} \
--query "[0].value" -o tsv)

# SAS Tokens generieren (gültig für 1 Stunde)
SOURCE_SAS=$(az storage account generate-sas \
--account-name stdfxapi${ENV} \
--account-key "${SOURCE_KEY}" \
--permissions rl \
--resource-types co \
--services b \
--expiry $(date -u -v+1H '+%Y-%m-%dT%H:%MZ') \
-o tsv)

DEST_SAS=$(az storage account generate-sas \
--account-name stdfxcore${ENV} \
--account-key "${DEST_KEY}" \
--permissions rl \
--resource-types co \
--services b \
--expiry $(date -u -v+1H '+%Y-%m-%dT%H:%MZ') \
-o tsv)

# Container vergleichen
echo ""
echo "Vergleiche kyc Container:"
azcopy sync \
"https://stdfxapi${ENV}.blob.core.windows.net/kyc?${SOURCE_SAS}" \
"https://stdfxcore${ENV}.blob.core.windows.net/kyc?${DEST_SAS}" \
--dry-run

echo ""
echo "Vergleiche support Container:"
azcopy sync \
"https://stdfxapi${ENV}.blob.core.windows.net/support?${SOURCE_SAS}" \
"https://stdfxcore${ENV}.blob.core.windows.net/support?${DEST_SAS}" \
--dry-run

echo ""
echo "Ende."
51 changes: 51 additions & 0 deletions infrastructure/bicep/core/storage-replication/copy-initial.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
#!/bin/sh
set -e

# --- OPTIONS --- #
environmentOptions=("dev" "prd")

# --- FUNCTIONS --- #
selectOption() {
PS3="${1}: "
shift
options=("$@")

select opt in "${options[@]}" "quit"; do
case "$REPLY" in
*) selection="${opt}"; break ;;
esac
done

if [[ ! $selection || $selection == "quit" ]]; then exit -1; fi
echo "${selection}"
}

ENV=$(selectOption "Select Environment" "${environmentOptions[@]}")

# SAS Tokens generieren (gültig für 1 Stunde)
SOURCE_SAS=$(az storage account generate-sas \
--account-name stdfxapi${ENV} \
--permissions rl \
--resource-types co \
--services b \
--expiry $(date -u -v+1H '+%Y-%m-%dT%H:%MZ') \
-o tsv)

DEST_SAS=$(az storage account generate-sas \
--account-name stdfxcore${ENV} \
--permissions rwdlac \
--resource-types co \
--services b \
--expiry $(date -u -v+1H '+%Y-%m-%dT%H:%MZ') \
-o tsv)

# Kopieren
azcopy copy \
"https://stdfxapi${ENV}.blob.core.windows.net/kyc/*?${SOURCE_SAS}" \
"https://stdfxcore${ENV}.blob.core.windows.net/kyc/?${DEST_SAS}" \
--recursive

azcopy copy \
"https://stdfxapi${ENV}.blob.core.windows.net/support/*?${SOURCE_SAS}" \
"https://stdfxcore${ENV}.blob.core.windows.net/support/?${DEST_SAS}" \
--recursive
60 changes: 60 additions & 0 deletions infrastructure/bicep/core/storage-replication/deploy.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,60 @@
#!/bin/sh
set -e

# --- OPTIONS --- #
environmentOptions=("dev" "prd")

# --- FUNCTIONS --- #
selectOption() {
PS3="${1}: "
shift
options=("$@")

select opt in "${options[@]}" "quit"; do
case "$REPLY" in
*) selection="${opt}"; break ;;
esac
done

if [[ ! $selection || $selection == "quit" ]]; then exit -1; fi
echo "${selection}"
}

ENV=$(selectOption "Select Environment" "${environmentOptions[@]}")

echo "Schritt 1: Subscription-ID holen"
SUB_ID=$(az account show --query id -o tsv)

echo "Sub-ID: $SUB_ID"

echo "Schritt 2: Destination Policy (rg-dfx-core-${ENV})"
az deployment group create \
--resource-group rg-dfx-core-${ENV} \
--template-file ./storageObjectReplicationDestination.bicep \
--parameters \
destinationStorageAccountName=stdfxcore${ENV} \
sourceStorageAccountId="/subscriptions/${SUB_ID}/resourceGroups/rg-dfx-api-${ENV}/providers/Microsoft.Storage/storageAccounts/stdfxapi${ENV}"

echo "Schritt 3: Policy-ID und Rules von Azure holen"
POLICY_ID=$(az storage account or-policy list \
--account-name stdfxcore${ENV} \
--resource-group rg-dfx-core-${ENV} \
--query "[0].policyId" -o tsv)

RULES=$(az storage account or-policy list \
--account-name stdfxcore${ENV} \
--resource-group rg-dfx-core-${ENV} \
--query "[0].rules" -o json)

echo "Policy-ID: $POLICY_ID"
echo "Rules: $RULES"

echo "Schritt 4: Source Policy (rg-dfx-api-${ENV})"
az deployment group create \
--resource-group rg-dfx-api-${ENV} \
--template-file ./storageObjectReplicationSource.bicep \
--parameters \
sourceStorageAccountName=stdfxapi${ENV} \
destinationStorageAccountId="/subscriptions/${SUB_ID}/resourceGroups/rg-dfx-core-${ENV}/providers/Microsoft.Storage/storageAccounts/stdfxcore${ENV}" \
replicationPolicyId="${POLICY_ID}" \
containerRules="${RULES}"
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
// --- PARAMETERS --- //
@description('Name of the destination storage account')
param destinationStorageAccountName string

@description('Resource ID of the source storage account')
param sourceStorageAccountId string

@description('Container rules for replication')
param containerRules array = [
{ sourceContainer: 'kyc', destinationContainer: 'kyc' }
{ sourceContainer: 'support', destinationContainer: 'support' }
]

// --- EXISTING RESOURCES --- //
resource destinationStorageAccount 'Microsoft.Storage/storageAccounts@2023-01-01' existing = {
name: destinationStorageAccountName
}

// --- RESOURCES --- //
resource destinationReplicationPolicy 'Microsoft.Storage/storageAccounts/objectReplicationPolicies@2023-01-01' = {
parent: destinationStorageAccount
name: 'default'
properties: {
sourceAccount: sourceStorageAccountId
destinationAccount: destinationStorageAccount.id
rules: [
for rule in containerRules: {
sourceContainer: rule.sourceContainer
destinationContainer: rule.destinationContainer
filters: contains(rule, 'prefixMatch')
? {
prefixMatch: rule.prefixMatch
}
: null
}
]
}
}

// --- OUTPUT --- //
// Die Policy-ID wird aus der Resource-ID extrahiert (letztes Segment = generierte GUID)
output policyId string = last(split(destinationReplicationPolicy.id, '/'))
output destinationStorageAccountId string = destinationStorageAccount.id
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
// --- PARAMETERS --- //
@description('Name of the source storage account')
param sourceStorageAccountName string

@description('Resource ID of the destination storage account')
param destinationStorageAccountId string

@description('Policy ID from the destination deployment')
param replicationPolicyId string

@description('Container rules from destination policy (including ruleId)')
param containerRules array

// --- EXISTING RESOURCES --- //
resource sourceStorageAccount 'Microsoft.Storage/storageAccounts@2023-01-01' existing = {
name: sourceStorageAccountName
}

// --- RESOURCES --- //
resource sourceReplicationPolicy 'Microsoft.Storage/storageAccounts/objectReplicationPolicies@2023-01-01' = {
parent: sourceStorageAccount
name: replicationPolicyId
properties: {
sourceAccount: sourceStorageAccount.id
destinationAccount: destinationStorageAccountId
rules: [for rule in containerRules: {
ruleId: rule.ruleId
sourceContainer: rule.sourceContainer
destinationContainer: rule.destinationContainer
}]
}
}

// --- OUTPUT --- //
output replicationPolicyId string = sourceReplicationPolicy.name
Loading
Loading