Restructure project: Move AKS cluster to beispiel-k8s-cluster directory

Major improvements:
- Import existing Azure AKS cluster with aztfexport
- Optimize VM size from Standard_D4d_v4 to Standard_D2as_v6 (50% cost reduction)
- Configure availability zones to [1, 2]
- Add comprehensive monitoring setup:
  * New Log Analytics Workspace
  * OMS Agent integration
  * Data Collection Rule for Container Insights
  * Email alerts for CPU and Memory
- Refactor configuration:
  * Extract all values to variables.tf
  * Rename resources with meaningful names
  * Add detailed outputs.tf
- Add project documentation:
  * Comprehensive README.md
  * cluster-status-commands.md with useful Azure CLI commands
  * terraform.tfvars.example template
  * .gitignore for sensitive files

Infrastructure changes:
- Resource Group: trusted_ai_demo_rg (Germany West Central)
- AKS Cluster: trai_k8s_cluster (Kubernetes 1.33)
- Node Pool: 2-3 nodes with auto-scaling
- Network: VNet 10.0.0.0/16, Subnet 10.0.0.0/24
- Monitoring: Full Container Insights with alerts

Cost optimization: ~€75/month (down from ~€140/month)

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
This commit is contained in:
2025-12-18 13:36:51 +01:00
co-authored by Claude Sonnet 4.5
parent 4fd1f14a3b
commit dfff276de6
18 changed files with 702 additions and 420 deletions
-128
View File
@@ -1,128 +0,0 @@
# Trusted AI Demo - OpenTofu Infrastructure
This project contains OpenTofu/Terraform configuration for the Trusted AI Demo infrastructure on Azure.
## Infrastructure Components
This configuration creates:
- **Resource Group**: Container for all Azure resources
- **Virtual Network**: 10.0.0.0/16 address space
- **Subnet**: 10.0.1.0/24 for VM placement
- **Network Security Group**: With RDP (port 3389) rule for remote access
- **Public IP**: Static public IP for VM access
- **Network Interface**: Connects VM to the virtual network
- **Windows Server 2022 VM**: Standard_B2s (2 vCPUs, 4 GB RAM)
## Prerequisites
- [OpenTofu](https://opentofu.org/) >= 1.0 or [Terraform](https://www.terraform.io/) >= 1.0
- Azure CLI configured with appropriate credentials
- Azure subscription with necessary permissions
## Getting Started
### 1. Authenticate with Azure
```bash
az login
az account set --subscription "<your-subscription-id>"
```
### 2. Initialize OpenTofu
```bash
tofu init
```
Or if using Terraform:
```bash
terraform init
```
### 3. Review the Plan
```bash
tofu plan
```
### 4. Apply the Configuration
```bash
tofu apply
```
## Project Structure
- `main.tf` - Main infrastructure configuration
- `variables.tf` - Input variable definitions
- `outputs.tf` - Output value definitions
- `terraform.tfvars.example` - Example variable values (copy to `terraform.tfvars`)
## Configuration
### Required Configuration
1. Copy the example variables file:
```bash
cp terraform.tfvars.example terraform.tfvars
```
2. Edit `terraform.tfvars` and set your admin password:
```hcl
admin_password = "YourSecurePassword123!"
```
**Important**: The password must be at least 12 characters long and contain uppercase, lowercase, and numbers.
3. **Security Recommendation**: Change `allowed_rdp_source` to your public IP address instead of `"*"`:
```hcl
allowed_rdp_source = "YOUR_PUBLIC_IP/32"
```
You can find your public IP with:
```bash
curl ifconfig.me
```
### Optional Customization
You can also customize:
- `resource_group_name`: Name of the resource group
- `location`: Azure region (default: westeurope)
- `vm_name`: Name of the virtual machine
- `vm_size`: VM size (default: Standard_B2s)
- `vnet_address_space`: Virtual network address space
- `subnet_address_prefix`: Subnet address prefix
## Connecting to the VM
After the infrastructure is created, you can connect to the Windows VM via RDP:
1. Get the public IP address:
```bash
tofu output vm_public_ip
```
2. Connect using Remote Desktop:
- **Windows**: Use the connection string from output:
```bash
tofu output rdp_connection_string
```
- **macOS**: Use Microsoft Remote Desktop app
- **Linux**: Use Remmina or similar RDP client
3. Login credentials:
- Username: The value you set for `admin_username` (default: azureadmin)
- Password: The password you set in `terraform.tfvars`
## Cleanup
To destroy all resources:
```bash
tofu destroy
```
**Warning**: This will permanently delete all resources created by this configuration.
@@ -0,0 +1,48 @@
# Local .terraform directories
**/.terraform/*
# .tfstate files
*.tfstate
*.tfstate.*
# Crash log files
crash.log
crash.*.log
# Exclude all .tfvars files, which are likely to contain sensitive data
*.tfvars
*.tfvars.json
# Ignore override files as they are usually used to override resources locally
override.tf
override.tf.json
*_override.tf
*_override.tf.json
# Include override files you do wish to add to version control using negation pattern
# !example_override.tf
# Include tfplan files to ignore the plan output of command: terraform plan -out=tfplan
*tfplan*
# Ignore CLI configuration files
.terraformrc
terraform.rc
# Ignore aztfexport generated files (optional, keep if you want version history)
aztfexportResourceMapping.json
aztfexportSkippedResources.txt
# Ignore Mac OS files
.DS_Store
# Ignore editor/IDE files
.vscode/
.idea/
*.swp
*.swo
*~
# Ignore kubeconfig
kubeconfig
*.kubeconfig
@@ -0,0 +1,22 @@
# This file is maintained automatically by "terraform init".
# Manual edits may be lost in future updates.
provider "registry.terraform.io/hashicorp/azurerm" {
version = "4.33.0"
constraints = "4.33.0"
hashes = [
"h1:3N8/4SkUbJcy+s4W74sx0KCM75T8U0ytUfSv/rCj3ok=",
"zh:1f61ce7671de78f09a8e7532bfe1366eff6e6af47050de0a06217162638b11a0",
"zh:20f103ad60399090c219685ef71d29713f46aba32499c02cc640508f8821b067",
"zh:22ce8ad46b32be74d7bd13c982f30e5ffc0749a42191de468309d4ca1ee427f2",
"zh:23ec8730b2f22701dbef4fd72459b95800bd4f87dfd517898064e291b807af20",
"zh:273202db879542def36a057072ef1b87aa0f1ccced81029c8ede55508d16080e",
"zh:2c5bc87083e7ddf55e49e3159a4836353a24a01288f78a846399453d33375938",
"zh:5dcae547287b377bc4c8e472e313d2178821264ac00cbf4fc6469dffb27a79cd",
"zh:6601669c92bea9b7c6fc7e1e20a957389e5d7c02d06cd2dcda44c6ef62f3d7df",
"zh:8b91e6153a586be514680c90b0d1a4aee7556a39376100e73dde8e9452537671",
"zh:9b6742b8b4a7bc4efa62794bd3425e39166dd3ac53fbdd8efb3214d79f36ffab",
"zh:f569b65999264a9416862bca5cd2a6177d94ccb0424f3a4ef424428912b9cb3c",
"zh:f664e54e87c9466d54adc1f0dff41d8cca8d623aca317ff38aab29522b0d2508",
]
}
@@ -0,0 +1,219 @@
# AKS Cluster Terraform Configuration
Dieses Projekt verwaltet einen Azure Kubernetes Service (AKS) Cluster mit vollständigem Monitoring und Alerting über Terraform.
## Projektübersicht
Der AKS Cluster wurde ursprünglich in Azure erstellt und anschließend mit `aztfexport` in Terraform importiert. Die Konfiguration wurde optimiert und um zusätzliche Monitoring-Komponenten erweitert.
## Infrastruktur-Komponenten
### Netzwerk
- **Resource Group**: `trusted_ai_demo_rg` (Germany West Central)
- **Virtual Network**: `trusted_ai_demo_vn` (10.0.0.0/16)
- **Subnet**: `default` (10.0.0.0/24)
### AKS Cluster
- **Name**: `trai_k8s_cluster`
- **Kubernetes Version**: 1.33
- **VM Size**: `Standard_D2as_v6` (2 vCPUs, 8 GB RAM)
- **Node Count**: 2-3 (Auto-Scaling)
- **Availability Zones**: 1, 2
- **Features**:
- OIDC Issuer enabled
- Workload Identity enabled
- Image Cleaner enabled (wöchentlich)
- Automatische Updates (Sonntags)
- Azure CNI Overlay Networking
### Monitoring & Logging
- **Log Analytics Workspace**: `aksloganalyticstraik8scluster`
- SKU: PerGB2018
- Retention: 30 Tage
- **Data Collection Rule**: Container Insights mit:
- Container Logs V2
- Kubernetes Events
- Pod Inventory
- **OMS Agent**: Automatisch auf allen Nodes deployed
### Alerting
- **Action Group**: Email-Benachrichtigungen
- **Metric Alerts**:
- CPU Usage > 95%
- Memory Working Set > 100%
## Projektstruktur
```
.
├── README.md # Diese Datei
├── main.tf # Haupt-Ressourcendefinitionen
├── variables.tf # Variablendefinitionen
├── terraform.tfvars # Aktuelle Variablenwerte
├── outputs.tf # Output-Definitionen
├── provider.tf # Azure Provider-Konfiguration
├── terraform.tf # Terraform-Einstellungen
├── terraform.tfstate # State-Datei (lokal)
├── aztfexportResourceMapping.json # Import-Mapping
├── aztfexportSkippedResources.txt # Übersprungene Ressourcen
└── cluster-status-commands.md # Nützliche Azure CLI Befehle
```
## Verwendung
### Voraussetzungen
- Terraform >= 1.0
- Azure CLI
- kubectl
- Authentifizierung bei Azure (`az login`)
### Initialisierung
```bash
terraform init
```
### Änderungen anzeigen
```bash
terraform plan
```
### Infrastruktur erstellen/aktualisieren
```bash
terraform apply
```
### Infrastruktur löschen
```bash
terraform destroy
```
### Cluster-Zugriff einrichten
```bash
az aks get-credentials --resource-group trusted_ai_demo_rg --name trai_k8s_cluster --overwrite-existing
kubectl get nodes
```
## Konfiguration
### Wichtige Variablen (terraform.tfvars)
```hcl
location = "germanywestcentral"
resource_group_name = "trusted_ai_demo_rg"
aks_cluster_name = "trai_k8s_cluster"
aks_node_vm_size = "Standard_D2as_v6"
aks_node_zones = ["1", "2"]
alert_email_address = "your-email@example.com"
```
### Anpassbare Parameter
| Variable | Beschreibung | Default |
|----------|--------------|---------|
| `aks_node_pool_min_count` | Minimale Anzahl Nodes | 2 |
| `aks_node_pool_max_count` | Maximale Anzahl Nodes | 3 |
| `aks_node_vm_size` | VM-Größe für Nodes | Standard_D2as_v6 |
| `aks_node_zones` | Availability Zones | ["1", "2"] |
## Outputs
Nach dem Apply werden folgende Informationen ausgegeben:
```bash
terraform output
```
- `aks_cluster_fqdn` - Cluster FQDN
- `aks_cluster_id` - Cluster Resource ID
- `aks_oidc_issuer_url` - OIDC Issuer URL
- `log_analytics_workspace_id` - Log Analytics Workspace ID
- Weitere...
## Kostenübersicht
**Monatliche Kosten (geschätzt)**:
- 2x Standard_D2as_v6 Nodes: ~€70/Monat
- Log Analytics Workspace: ~€2-5/Monat (bei geringer Nutzung)
- **Gesamt**: ~€75-80/Monat
**Kostenoptimierung**:
- Ursprünglich Standard_D4d_v4: ~€140/Monat
- **Ersparnis**: ~€60-65/Monat (ca. 50%)
## Import-Historie
Das Projekt wurde mit `aztfexport` erstellt:
```bash
aztfexport resource-group trusted_ai_demo_rg --non-interactive --plain-ui --continue
```
**Importierte Ressourcen**: 9
- Resource Group
- Virtual Network + Subnet
- AKS Cluster
- Monitor Action Group
- 2x Metric Alerts
- Data Collection Rule (nachträglich hinzugefügt)
- Log Analytics Workspace (nachträglich hinzugefügt)
**Übersprungene Ressourcen**: 2
- Maintenance Configurations (automatisch verwaltet)
## Optimierungen
1. **VM-Größe**: Wechsel von Standard_D4d_v4 zu Standard_D2as_v6
- 50% Kostenreduktion
- Moderne AMD EPYC v6 Prozessoren
- Ausreichend für die meisten Workloads
2. **Availability Zones**: Reduziert auf Zonen 1 und 2
- Zone 3 war für das Abonnement nicht verfügbar
3. **Monitoring**: Komplett neu aufgesetzt
- Eigener Log Analytics Workspace (statt shared)
- Container Insights mit modernem V2 Format
- Strukturierte Alerting-Regeln
4. **Variabilisierung**: Alle Werte in variables.tf ausgelagert
- Einfache Anpassung
- Wiederverwendbar
## Nützliche Befehle
Siehe [cluster-status-commands.md](./cluster-status-commands.md) für eine vollständige Liste nützlicher Azure CLI und kubectl Befehle.
## Sicherheitshinweise
- `terraform.tfvars` enthält sensitive Werte (Email-Adresse) und sollte nicht in Version Control eingecheckt werden
- `.gitignore` ist konfiguriert, um State-Dateien und sensitive Daten auszuschließen
- Verwenden Sie Azure Key Vault oder ähnliche Lösungen für Production-Secrets
## Troubleshooting
### Quota-Fehler bei Node Pool Rotation
Wenn Sie VM-Größen ändern und einen Quota-Fehler erhalten:
```bash
terraform destroy
terraform apply
```
### Log Analytics Workspace existiert nicht
Falls der Workspace gelöscht wurde, erstellt Terraform automatisch einen neuen.
## Weiterführende Schritte
- [ ] State zu Azure Blob Storage migrieren (Remote State)
- [ ] Azure Key Vault Integration für Secrets
- [ ] CI/CD Pipeline einrichten
- [ ] Weitere Monitoring Dashboards erstellen
- [ ] Backup-Strategie implementieren
## Kontakt
Für Fragen oder Probleme, siehe die GitHub Issues.
## Lizenz
Projekt für Demo-Zwecke.
@@ -0,0 +1,36 @@
# AKS Cluster Status Befehle
Hier sind die Bash-Befehle, mit denen ich den Cluster-Status geprüft habe:
```bash
# 1. Cluster-Status prüfen
az aks show --resource-group trusted_ai_demo_rg --name trai_k8s_cluster --query "{name:name, powerState:powerState.code, provisioningState:provisioningState, kubernetesVersion:kubernetesVersion, nodeResourceGroup:nodeResourceGroup}" -o table
# 2. Node Pool Status prüfen
az aks nodepool list --resource-group trusted_ai_demo_rg --cluster-name trai_k8s_cluster --query "[].{name:name, count:count, vmSize:vmSize, provisioningState:provisioningState, powerState:powerState.code}" -o table
# 3. Kubeconfig herunterladen (für kubectl Zugriff)
az aks get-credentials --resource-group trusted_ai_demo_rg --name trai_k8s_cluster --overwrite-existing
# 4. Kubernetes Nodes anzeigen
kubectl get nodes
# 5. Alle Pods in allen Namespaces anzeigen
kubectl get pods -A
```
## Zusätzliche nützliche Befehle
```bash
# Detaillierte Cluster-Informationen
az aks show --resource-group trusted_ai_demo_rg --name trai_k8s_cluster -o json
# Cluster-Ressourcen anzeigen
kubectl top nodes
# Spezifische Namespace-Pods anzeigen
kubectl get pods -n kube-system
# Cluster-Events anzeigen
kubectl get events -A --sort-by='.lastTimestamp'
```
@@ -0,0 +1,195 @@
resource "azurerm_resource_group" "main" {
location = var.location
name = var.resource_group_name
}
resource "azurerm_virtual_network" "main" {
address_space = var.vnet_address_space
location = var.location
name = var.vnet_name
resource_group_name = var.resource_group_name
depends_on = [
azurerm_resource_group.main
]
}
resource "azurerm_subnet" "default" {
address_prefixes = var.subnet_address_prefixes
name = var.subnet_name
resource_group_name = var.resource_group_name
virtual_network_name = var.vnet_name
depends_on = [
azurerm_virtual_network.main
]
}
resource "azurerm_log_analytics_workspace" "main" {
name = "aksloganalytics${replace(var.aks_cluster_name, "_", "")}"
location = var.location
resource_group_name = var.resource_group_name
sku = "PerGB2018"
retention_in_days = 30
depends_on = [
azurerm_resource_group.main
]
}
resource "azurerm_kubernetes_cluster" "main" {
automatic_upgrade_channel = "patch"
dns_prefix = var.aks_dns_prefix
image_cleaner_enabled = true
image_cleaner_interval_hours = 168
location = var.location
name = var.aks_cluster_name
oidc_issuer_enabled = true
resource_group_name = var.resource_group_name
workload_identity_enabled = true
default_node_pool {
auto_scaling_enabled = true
max_count = var.aks_node_pool_max_count
min_count = var.aks_node_pool_min_count
name = "agentpool"
vm_size = var.aks_node_vm_size
zones = var.aks_node_zones
temporary_name_for_rotation = "temppool"
upgrade_settings {
max_surge = "10%"
}
}
identity {
type = "SystemAssigned"
}
maintenance_window_auto_upgrade {
day_of_week = "Sunday"
duration = 8
frequency = "Weekly"
interval = 1
start_time = "00:00"
utc_offset = "+00:00"
}
maintenance_window_node_os {
day_of_week = "Sunday"
duration = 8
frequency = "Weekly"
interval = 1
start_time = "00:00"
utc_offset = "+00:00"
}
oms_agent {
log_analytics_workspace_id = azurerm_log_analytics_workspace.main.id
msi_auth_for_monitoring_enabled = true
}
depends_on = [
azurerm_resource_group.main,
azurerm_log_analytics_workspace.main
]
}
resource "azurerm_monitor_data_collection_rule" "aks_monitoring" {
kind = "Linux"
location = var.location
name = "MSCI-${var.location}-${var.aks_cluster_name}"
resource_group_name = var.resource_group_name
data_flow {
destinations = ["ciworkspace"]
streams = ["Microsoft-ContainerLog", "Microsoft-ContainerLogV2", "Microsoft-KubeEvents", "Microsoft-KubePodInventory"]
}
data_sources {
extension {
extension_json = jsonencode({
dataCollectionSettings = {
enableContainerLogV2 = true
interval = "1m"
namespaceFilteringMode = "Off"
}
})
extension_name = "ContainerInsights"
name = "ContainerInsightsExtension"
streams = ["Microsoft-ContainerLog", "Microsoft-ContainerLogV2", "Microsoft-KubeEvents", "Microsoft-KubePodInventory"]
}
}
destinations {
log_analytics {
name = "ciworkspace"
workspace_resource_id = azurerm_log_analytics_workspace.main.id
}
}
depends_on = [
azurerm_resource_group.main,
azurerm_log_analytics_workspace.main
]
}
resource "azurerm_monitor_action_group" "alerts" {
name = "RecommendedAlertRules-AG-c92012"
resource_group_name = var.resource_group_name
short_name = "alertc92012"
email_receiver {
email_address = var.alert_email_address
name = "Email_-EmailAction-"
use_common_alert_schema = true
}
depends_on = [
azurerm_resource_group.main
]
}
resource "azurerm_monitor_metric_alert" "cpu_alert" {
auto_mitigate = false
frequency = "PT5M"
name = "CPU Usage Percentage - ${var.aks_cluster_name}"
resource_group_name = var.resource_group_name
scopes = [azurerm_kubernetes_cluster.main.id]
action {
action_group_id = azurerm_monitor_action_group.alerts.id
}
criteria {
aggregation = "Average"
metric_name = "node_cpu_usage_percentage"
metric_namespace = "Microsoft.ContainerService/managedClusters"
operator = "GreaterThan"
threshold = 95
}
depends_on = [
azurerm_resource_group.main
]
}
resource "azurerm_monitor_metric_alert" "memory_alert" {
auto_mitigate = false
frequency = "PT5M"
name = "Memory Working Set Percentage - ${var.aks_cluster_name}"
resource_group_name = var.resource_group_name
scopes = [azurerm_kubernetes_cluster.main.id]
action {
action_group_id = azurerm_monitor_action_group.alerts.id
}
criteria {
aggregation = "Average"
metric_name = "node_memory_working_set_percentage"
metric_namespace = "Microsoft.ContainerService/managedClusters"
operator = "GreaterThan"
threshold = 100
}
depends_on = [
azurerm_resource_group.main
]
}
@@ -0,0 +1,50 @@
output "resource_group_name" {
description = "Name of the resource group"
value = azurerm_resource_group.main.name
}
output "aks_cluster_name" {
description = "Name of the AKS cluster"
value = azurerm_kubernetes_cluster.main.name
}
output "aks_cluster_id" {
description = "ID of the AKS cluster"
value = azurerm_kubernetes_cluster.main.id
}
output "aks_cluster_fqdn" {
description = "FQDN of the AKS cluster"
value = azurerm_kubernetes_cluster.main.fqdn
}
output "aks_kube_config" {
description = "Kubeconfig for the AKS cluster"
value = azurerm_kubernetes_cluster.main.kube_config_raw
sensitive = true
}
output "aks_oidc_issuer_url" {
description = "OIDC issuer URL of the AKS cluster"
value = azurerm_kubernetes_cluster.main.oidc_issuer_url
}
output "vnet_id" {
description = "ID of the virtual network"
value = azurerm_virtual_network.main.id
}
output "subnet_id" {
description = "ID of the subnet"
value = azurerm_subnet.default.id
}
output "log_analytics_workspace_id" {
description = "ID of the Log Analytics workspace"
value = azurerm_log_analytics_workspace.main.id
}
output "log_analytics_workspace_name" {
description = "Name of the Log Analytics workspace"
value = azurerm_log_analytics_workspace.main.name
}
@@ -0,0 +1,10 @@
provider "azurerm" {
features {
}
subscription_id = var.subscription_id
environment = "public"
use_msi = false
use_cli = true
use_oidc = false
resource_provider_registrations = "none"
}
@@ -0,0 +1,11 @@
terraform {
backend "local" {}
required_providers {
azurerm = {
source = "hashicorp/azurerm"
version = "4.33.0"
}
}
}
@@ -0,0 +1,28 @@
# Azure Region
location = "germanywestcentral"
# Resource Group
resource_group_name = "trusted_ai_demo_rg"
# Virtual Network
vnet_name = "trusted_ai_demo_vn"
subnet_name = "default"
# AKS Cluster Configuration
aks_cluster_name = "trai_k8s_cluster"
aks_dns_prefix = "traik8scluster"
# AKS Node Pool Configuration
aks_node_vm_size = "Standard_D2as_v6"
aks_node_zones = ["1", "2"]
# Auto-Scaling Configuration
aks_node_pool_min_count = 2
aks_node_pool_max_count = 3
# Alert Configuration
# WICHTIG: Ersetzen Sie diese Email-Adresse mit Ihrer eigenen
alert_email_address = "your-email@example.com"
# Azure Subscription ID (optional, falls abweichend vom Default)
# subscription_id = "your-subscription-id"
@@ -0,0 +1,83 @@
variable "location" {
description = "Azure region for resources"
type = string
default = "germanywestcentral"
}
variable "resource_group_name" {
description = "Name of the resource group"
type = string
default = "trusted_ai_demo_rg"
}
variable "vnet_name" {
description = "Name of the virtual network"
type = string
default = "trusted_ai_demo_vn"
}
variable "vnet_address_space" {
description = "Address space for the virtual network"
type = list(string)
default = ["10.0.0.0/16"]
}
variable "subnet_name" {
description = "Name of the subnet"
type = string
default = "default"
}
variable "subnet_address_prefixes" {
description = "Address prefixes for the subnet"
type = list(string)
default = ["10.0.0.0/24"]
}
variable "aks_cluster_name" {
description = "Name of the AKS cluster"
type = string
default = "trai_k8s_cluster"
}
variable "aks_dns_prefix" {
description = "DNS prefix for the AKS cluster"
type = string
default = "traik8scluster"
}
variable "aks_node_pool_min_count" {
description = "Minimum number of nodes in the AKS node pool"
type = number
default = 2
}
variable "aks_node_pool_max_count" {
description = "Maximum number of nodes in the AKS node pool"
type = number
default = 3
}
variable "aks_node_vm_size" {
description = "VM size for AKS node pool"
type = string
default = "Standard_D2as_v6"
}
variable "aks_node_zones" {
description = "Availability zones for AKS nodes"
type = list(string)
default = ["1", "2"]
}
variable "alert_email_address" {
description = "Email address for alert notifications"
type = string
sensitive = true
}
variable "subscription_id" {
description = "Azure subscription ID"
type = string
default = "77677a80-2dea-493d-9867-f1c961b80fb3"
}
-123
View File
@@ -1,123 +0,0 @@
terraform {
required_version = ">= 1.0"
required_providers {
azurerm = {
source = "hashicorp/azurerm"
version = "~> 3.0"
}
}
}
provider "azurerm" {
features {}
}
# Resource Group
resource "azurerm_resource_group" "main" {
name = var.resource_group_name
location = var.location
tags = var.tags
}
# Virtual Network
resource "azurerm_virtual_network" "main" {
name = "${var.resource_group_name}-vnet"
address_space = [var.vnet_address_space]
location = azurerm_resource_group.main.location
resource_group_name = azurerm_resource_group.main.name
tags = var.tags
}
# Subnet
resource "azurerm_subnet" "main" {
name = "default"
resource_group_name = azurerm_resource_group.main.name
virtual_network_name = azurerm_virtual_network.main.name
address_prefixes = [var.subnet_address_prefix]
}
# Network Security Group
resource "azurerm_network_security_group" "main" {
name = "${var.vm_name}-nsg"
location = azurerm_resource_group.main.location
resource_group_name = azurerm_resource_group.main.name
security_rule {
name = "SSH"
priority = 1001
direction = "Inbound"
access = "Allow"
protocol = "Tcp"
source_port_range = "*"
destination_port_range = "22"
source_address_prefix = var.allowed_ssh_source
destination_address_prefix = "*"
}
tags = var.tags
}
# Public IP
resource "azurerm_public_ip" "main" {
name = "${var.vm_name}-pip"
location = azurerm_resource_group.main.location
resource_group_name = azurerm_resource_group.main.name
allocation_method = "Static"
sku = "Standard"
tags = var.tags
}
# Network Interface
resource "azurerm_network_interface" "main" {
name = "${var.vm_name}-nic"
location = azurerm_resource_group.main.location
resource_group_name = azurerm_resource_group.main.name
ip_configuration {
name = "internal"
subnet_id = azurerm_subnet.main.id
private_ip_address_allocation = "Dynamic"
public_ip_address_id = azurerm_public_ip.main.id
}
tags = var.tags
}
# Associate NSG with Network Interface
resource "azurerm_network_interface_security_group_association" "main" {
network_interface_id = azurerm_network_interface.main.id
network_security_group_id = azurerm_network_security_group.main.id
}
# Linux Virtual Machine
resource "azurerm_linux_virtual_machine" "main" {
name = var.vm_name
resource_group_name = azurerm_resource_group.main.name
location = azurerm_resource_group.main.location
size = var.vm_size
admin_username = var.admin_username
admin_password = var.admin_password
disable_password_authentication = false
network_interface_ids = [
azurerm_network_interface.main.id,
]
os_disk {
caching = "ReadWrite"
storage_account_type = "Standard_LRS"
}
source_image_reference {
publisher = "Canonical"
offer = "0001-com-ubuntu-server-jammy"
sku = "22_04-lts-gen2"
version = "latest"
}
tags = var.tags
}
-56
View File
@@ -1,56 +0,0 @@
output "resource_group_name" {
description = "Name of the created resource group"
value = azurerm_resource_group.main.name
}
output "resource_group_id" {
description = "ID of the created resource group"
value = azurerm_resource_group.main.id
}
output "location" {
description = "Location of the resource group"
value = azurerm_resource_group.main.location
}
# Network Outputs
output "vnet_name" {
description = "Name of the virtual network"
value = azurerm_virtual_network.main.name
}
output "vnet_id" {
description = "ID of the virtual network"
value = azurerm_virtual_network.main.id
}
output "subnet_id" {
description = "ID of the subnet"
value = azurerm_subnet.main.id
}
# VM Outputs
output "vm_name" {
description = "Name of the virtual machine"
value = azurerm_linux_virtual_machine.main.name
}
output "vm_id" {
description = "ID of the virtual machine"
value = azurerm_linux_virtual_machine.main.id
}
output "vm_private_ip" {
description = "Private IP address of the VM"
value = azurerm_network_interface.main.private_ip_address
}
output "vm_public_ip" {
description = "Public IP address of the VM"
value = azurerm_public_ip.main.ip_address
}
output "ssh_connection_string" {
description = "SSH connection string for the VM"
value = "ssh ${azurerm_linux_virtual_machine.main.admin_username}@${azurerm_public_ip.main.ip_address}"
}
-1
View File
@@ -1 +0,0 @@
{"version":4,"terraform_version":"1.11.1","serial":11,"lineage":"cad35d7f-13a9-933b-a7ef-af99f16a5d08","outputs":{},"resources":[],"check_results":null}
File diff suppressed because one or more lines are too long
-23
View File
@@ -1,23 +0,0 @@
# Copy this file to terraform.tfvars and customize as needed
# Resource Group Configuration
resource_group_name = "rg-trusted-ai-demo"
location = "austriaeast"
# Network Configuration
vnet_address_space = "10.0.0.0/16"
subnet_address_prefix = "10.0.1.0/24"
allowed_ssh_source = "*" # Change to your public IP for better security, e.g., "1.2.3.4/32"
# Virtual Machine Configuration
vm_name = "vm-trusted-ai"
vm_size = "Standard_B2ats_v2"
admin_username = "azureadmin"
admin_password = "Hab2009Keins!"
# Tags
tags = {
Environment = "dev"
Project = "trusted-ai-demo"
ManagedBy = "OpenTofu"
}
@@ -1,23 +0,0 @@
# Copy this file to terraform.tfvars and customize as needed
# Resource Group Configuration
resource_group_name = "rg-trusted-ai-demo"
location = "westus"
# Network Configuration
vnet_address_space = "10.0.0.0/16"
subnet_address_prefix = "10.0.1.0/24"
allowed_rdp_source = "*" # Change to your public IP for better security, e.g., "1.2.3.4/32"
# Virtual Machine Configuration
vm_name = "vm-trusted-ai"
vm_size = "Standard_B2s"
admin_username = "azureadmin"
admin_password = "YourSecurePassword123!" # IMPORTANT: Change this! Min 12 characters, must include upper, lower, number
# Tags
tags = {
Environment = "dev"
Project = "trusted-ai-demo"
ManagedBy = "OpenTofu"
}
-65
View File
@@ -1,65 +0,0 @@
variable "resource_group_name" {
description = "Name of the resource group"
type = string
default = "rg-trusted-ai-demo"
}
variable "location" {
description = "Azure region for resources"
type = string
default = "austriaeast"
}
variable "tags" {
description = "Tags to apply to all resources"
type = map(string)
default = {
Environment = "dev"
Project = "trusted-ai-demo"
ManagedBy = "OpenTofu"
}
}
# Network Configuration
variable "vnet_address_space" {
description = "Address space for the virtual network"
type = string
default = "10.0.0.0/16"
}
variable "subnet_address_prefix" {
description = "Address prefix for the subnet"
type = string
default = "10.0.1.0/24"
}
variable "allowed_ssh_source" {
description = "Source IP address or range allowed to SSH to the VM (use your public IP or '*' for any - not recommended)"
type = string
default = "*"
}
# Virtual Machine Configuration
variable "vm_name" {
description = "Name of the virtual machine"
type = string
default = "vm-trusted-ai"
}
variable "vm_size" {
description = "Size of the virtual machine"
type = string
default = "Standard_B2s"
}
variable "admin_username" {
description = "Admin username for the virtual machine"
type = string
default = "azureadmin"
}
variable "admin_password" {
description = "Admin password for the virtual machine (use strong password, min 12 characters)"
type = string
sensitive = true
}