#!/usr/bin/env bash
# Azure Network Sensor - Bicep Project Generator
# Usage: ./azure-network-sensor.sh [TARGET_ROOT_DIR]
# 
# This script creates a ready-to-deploy Bicep project for the Azure network sensor
# in the specified target directory (or current directory if not specified).

set -euo pipefail

TARGET_ROOT="${1:-.}"
DEPLOY_DIR="$TARGET_ROOT/deploy/azure-network-sensor"
BLACKSHIELD_API_URL="${BLACKSHIELD_API_URL:-https://api.blackshield.chaplau.com}"
BLACKSHIELD_NETWORK_SENSOR_IMAGE="${BLACKSHIELD_NETWORK_SENSOR_IMAGE:-public.ecr.aws/blackshield-security/network-sensor:1.0.0}"

replace_literal() {
  local file_path="$1"
  local placeholder="$2"
  local replacement="$3"
  local tmp_file="${file_path}.tmp.$$"

  sed "s|${placeholder}|${replacement}|g" "$file_path" > "$tmp_file"
  mv "$tmp_file" "$file_path"
}

# Create directory structure
mkdir -p "$DEPLOY_DIR"

echo "Generating Azure Network Sensor Bicep project in $DEPLOY_DIR..."

# Write main.bicep
cat > "$DEPLOY_DIR/main.bicep" << 'EOF'
param location string = resourceGroup().location
param environment string = 'prod'
param vmName string = 'network-sensor-${environment}'
param vmSize string = 'Standard_B2s'
param vnetName string
param subnetName string
param imagePublisher string = 'Canonical'
param imageOffer = '0001-com-ubuntu-server-focal'
param imageSku string = '20_04-lts-gen2'
param imageVersion string = 'latest'
param adminUsername string
@secure()
param sshPublicKey string
@secure()
param apiKey string
param apiUrl string = 'https://api.blackshield.chaplau.com'
param sensorType string = 'suricata'
param minSeverity string = 'high'
param keyVaultName string
param keyVaultResourceGroup string = resourceGroup().name
var apiKeySecretName = 'blackshield-network-sensor-key'

// Reference existing resources
resource vnet 'Microsoft.Network/virtualNetworks@2021-02-01' existing = {
  name: vnetName
}

resource subnet 'Microsoft.Network/virtualNetworks/subnets@2021-02-01' existing = {
  parent: vnet
  name: subnetName
}

resource keyVault 'Microsoft.KeyVault/vaults@2021-06-01-preview' existing = {
  name: keyVaultName
  scope: resourceGroup(keyVaultResourceGroup)
}

// Network interface for sensor
resource sensorNic 'Microsoft.Network/networkInterfaces@2021-02-01' = {
  name: '${vmName}-nic'
  location: location
  properties: {
    networkSecurityGroup: {
      id: sensorNsg.id
    }
    ipConfigurations: [
      {
        name: 'ipconfig1'
        properties: {
          subnet: {
            id: subnet.id
          }
          privateIPAllocationMethod: 'Dynamic'
        }
      }
    ]
  }
}

// Network security group for sensor
resource sensorNsg 'Microsoft.Network/networkSecurityGroups@2021-02-01' = {
  name: '${vmName}-nsg'
  location: location
  properties: {
    securityRules: [
      {
        name: 'AllowVXLANInbound'
        properties: {
          protocol: 'Udp'
          sourcePortRange: '*'
          destinationPortRange: '4789'
          sourceAddressPrefix: '10.0.0.0/8'
          destinationAddressPrefix: '*'
          access: 'Allow'
          priority: 100
          direction: 'Inbound'
        }
      }
      {
        name: 'AllowHTTPSOutbound'
        properties: {
          protocol: 'Tcp'
          sourcePortRange: '*'
          destinationPortRange: '443'
          sourceAddressPrefix: '*'
          destinationAddressPrefix: '*'
          access: 'Allow'
          priority: 100
          direction: 'Outbound'
        }
      }
    ]
  }
}

// Managed identity for sensor VM
resource sensorIdentity 'Microsoft.ManagedIdentity/userAssignedIdentities@2018-11-30' = {
  name: '${vmName}-identity'
  location: location
}

// Key Vault access policy for managed identity
resource keyVaultAccessPolicy 'Microsoft.KeyVault/vaults/accessPolicies@2021-06-01-preview' = {
  parent: keyVault
  name: 'add'
  properties: {
    accessPolicies: [
      {
        tenantId: subscription().tenantId
        objectId: sensorIdentity.properties.principalId
        permissions: {
          secrets: [
            'get'
            'list'
          ]
        }
      }
    ]
  }
}

resource apiKeySecret 'Microsoft.KeyVault/vaults/secrets@2023-07-01' = {
  parent: keyVault
  name: apiKeySecretName
  properties: {
    value: apiKey
  }
}

// Virtual machine
resource sensorVm 'Microsoft.Compute/virtualMachines@2021-03-01' = {
  name: vmName
  location: location
  identity: {
    type: 'UserAssigned'
    userAssignedIdentities: {
      '${sensorIdentity.id}': {}
    }
  }
  properties: {
    hardwareProfile: {
      vmSize: vmSize
    }
    osProfile: {
      computerName: vmName
      adminUsername: adminUsername
      linuxConfiguration: {
        disablePasswordAuthentication: true
        ssh: {
          publicKeys: [
            {
              path: '/home/${adminUsername}/.ssh/authorized_keys'
              keyData: sshPublicKey
            }
          ]
        }
      }
    }
    storageProfile: {
      imageReference: {
        publisher: imagePublisher
        offer: imageOffer
        sku: imageSku
        version: imageVersion
      }
      osDisk: {
        createOption: 'FromImage'
        managedDisk: {
          storageAccountType: 'Premium_LRS'
        }
      }
    }
    networkProfile: {
      networkInterfaces: [
        {
          id: sensorNic.id
        }
      ]
    }
  }
}

// VM extension for startup script
resource sensorStartupExt 'Microsoft.Compute/virtualMachines/extensions@2021-03-01' = {
  parent: sensorVm
  name: 'CustomScript'
  location: location
  dependsOn: [
    keyVaultAccessPolicy
    apiKeySecret
  ]
  properties: {
    publisher: 'Microsoft.Azure.Extensions'
    type: 'CustomScript'
    typeHandlerVersion: '2.1'
    autoUpgradeMinorVersion: true
    settings: {
      script: loadFileAsBase64('startup.sh')
    }
    protectedSettings: {
      commandToExecute: 'export KEYVAULT_NAME=${keyVaultName} API_KEY_SECRET_NAME=${apiKeySecretName} BLACKSHIELD_API_URL=${apiUrl} SENSOR_TYPE=${sensorType} MIN_SEVERITY=${minSeverity}; bash startup.sh'
    }
  }
}

output vmId {
  value: sensorVm.id
  description: 'Resource ID of the sensor VM'
}

output vmName {
  value: sensorVm.name
  description: 'Name of the sensor VM'
}

output nicId {
  value: sensorNic.id
  description: 'Resource ID of the network interface'
}
EOF

replace_literal "$DEPLOY_DIR/main.bicep" "https://api.blackshield.chaplau.com" "$BLACKSHIELD_API_URL"

# Write startup.sh
cat > "$DEPLOY_DIR/startup.sh" << 'EOF'
#!/usr/bin/env bash
set -euo pipefail

# Update system
apt-get update
apt-get install -y docker.io curl jq

# Start Docker
systemctl enable --now docker

# Retrieve API key from Key Vault using managed identity
TOKEN=$(curl -s -H "Metadata: true" "http://169.254.169.254/metadata/identity/oauth2/token?api-version=2018-02-01&resource=https://vault.azure.net" | jq -r '.access_token')

API_KEY=$(curl -s -H "Authorization: Bearer $TOKEN" "https://${KEYVAULT_NAME}.vault.azure.net/secrets/${API_KEY_SECRET_NAME}?api-version=2016-10-01" | jq -r '.value')

# Pull and run sensor container
docker pull public.ecr.aws/blackshield-security/network-sensor:latest
docker rm -f network-sensor || true

docker run -d \
  --name network-sensor \
  --network host \
  --cap-add NET_ADMIN \
  --cap-add NET_RAW \
  --restart unless-stopped \
  -e BLACKSHIELD_API_URL="${BLACKSHIELD_API_URL}" \
  -e BLACKSHIELD_API_KEY="${API_KEY}" \
  -e SENSOR_TYPE="${SENSOR_TYPE}" \
  -e MIN_SEVERITY="${MIN_SEVERITY}" \
  public.ecr.aws/blackshield-security/network-sensor:latest

echo "Network sensor container started"
docker logs -f network-sensor &

# Verify container is running
sleep 5
if docker ps | grep -q network-sensor; then
  echo "✓ Network sensor is running and healthy"
else
  echo "✗ Network sensor failed to start"
  exit 1
fi
EOF
chmod +x "$DEPLOY_DIR/startup.sh"

replace_literal \
  "$DEPLOY_DIR/startup.sh" \
  "public.ecr.aws/blackshield-security/network-sensor:latest" \
  "$BLACKSHIELD_NETWORK_SENSOR_IMAGE"

# Write parameters.json.example
cat > "$DEPLOY_DIR/parameters.json.example" << 'EOF'
{
  "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentParameters.json#",
  "contentVersion": "1.0.0.0",
  "parameters": {
    "location": {
      "value": "eastus"
    },
    "environment": {
      "value": "prod"
    },
    "vmName": {
      "value": "network-sensor-prod"
    },
    "vmSize": {
      "value": "Standard_B2s"
    },
    "vnetName": {
      "value": "my-vnet"
    },
    "subnetName": {
      "value": "sensor-subnet"
    },
    "adminUsername": {
      "value": "azureuser"
    },
    "sshPublicKey": {
      "value": "ssh-rsa AAAAB3NzaC1yc2E..."
    },
    "apiKey": {
      "value": "your-ingestion-api-key"
    },
    "apiUrl": {
      "value": "https://api.blackshield.chaplau.com"
    },
    "sensorType": {
      "value": "suricata"
    },
    "minSeverity": {
      "value": "high"
    },
    "keyVaultName": {
      "value": "my-key-vault"
    },
    "keyVaultResourceGroup": {
      "value": "my-resource-group"
    }
  }
}
EOF

replace_literal "$DEPLOY_DIR/parameters.json.example" "https://api.blackshield.chaplau.com" "$BLACKSHIELD_API_URL"

# Write README.md
cat > "$DEPLOY_DIR/README.md" << 'EOF'
# Azure Network Sensor Deployment

This Bicep template deploys the BlackShield network sensor on Azure using VNet TAP.

The generated template stores `apiKey` in your existing Key Vault as `blackshield-network-sensor-key`, grants the VM managed identity access, and starts the sensor container on first boot.

## Prerequisites

- Azure CLI configured with appropriate credentials
- Existing Azure VNet and subnet
- Existing Key Vault for storing API credentials
- BlackShield API key with ingestion scope
- SSH public key for VM access

## Quick Start

1. **Set up parameters:**
   ```bash
   cp parameters.json.example parameters.json
   ```

2. **Edit parameters.json:**
   - Set your VNet and subnet names
   - Provide your SSH public key
   - Add your BlackShield API key
   - Set Key Vault details
   - Override `apiUrl` only if you need a different BlackShield environment than the prefilled one

3. **Deploy:**
   ```bash
   az deployment group create \
     --resource-group my-resource-group \
     --template-file main.bicep \
     --parameters parameters.json
   ```

4. **Verify the deployment:**
   ```bash
   az vm list --resource-group my-resource-group --query "[?name=='network-sensor-prod']"
   az vm boot-diagnostics get-boot-log --resource-group my-resource-group --name network-sensor-prod
   ```

5. **Set up VNet TAP in Azure Portal:**
   - Go to Virtual Network TAPs
   - Create TAP targeting the sensor VM's network interface
   - Attach to source VM interfaces (workloads to monitor)

## Files

- `main.bicep` — VMs, managed identities, Key Vault integration, NSGs, network interfaces
- `startup.sh` — user data script to start the sensor container
- `parameters.json.example` — example parameter values

## Cleanup

```bash
az deployment group delete --resource-group my-resource-group --name network-sensor-deployment
```
EOF

echo ""
echo "✓ Azure Network Sensor project generated in $DEPLOY_DIR"
echo ""
echo "Next steps:"
echo "  1. cd $DEPLOY_DIR"
echo "  2. cp parameters.json.example parameters.json"
echo "  3. Edit parameters.json with your Azure resources and API key"
echo "  4. az deployment group create --resource-group my-rg --template-file main.bicep --parameters parameters.json"
echo ""
