commit b970b4fc51255c7bea17e89aab247fe36a1e0421 Author: defiQUG Date: Mon Feb 9 21:51:46 2026 -0800 Initial commit: add .gitignore and README diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..4c64e16 --- /dev/null +++ b/.gitignore @@ -0,0 +1,49 @@ +# Dependencies +node_modules/ +.pnpm-store/ +vendor/ + +# Package manager lock files (optional: uncomment to ignore) +# package-lock.json +# yarn.lock + +# Environment and secrets +.env +.env.local +.env.*.local +*.env.backup +.env.backup.* + +# Logs and temp +*.log +logs/ +*.tmp +*.temp +*.tmp.* + +# OS +.DS_Store +Thumbs.db + +# IDE +.vscode/ +.idea/ +*.swp +*.swo +*~ + +# Build / output +dist/ +build/ +.next/ +out/ +*.pyc +__pycache__/ +.eggs/ +*.egg-info/ +.coverage +htmlcov/ + +# Optional +.reports/ +reports/ diff --git a/README.md b/README.md new file mode 100644 index 0000000..aba8e91 --- /dev/null +++ b/README.md @@ -0,0 +1,86 @@ +# Infrastructure Monorepo + +**Purpose**: Consolidated infrastructure as code for all projects +**Status**: 🚧 Structure Complete - Ready for Consolidation + +--- + +## Overview + +This directory contains all infrastructure as code, organized for easy management and deployment. + +--- + +## Structure + +``` +infrastructure/ +β”œβ”€β”€ terraform/ # Terraform modules and configurations +β”‚ β”œβ”€β”€ modules/ # Shared Terraform modules +β”‚ └── examples/ # Example configurations +β”œβ”€β”€ kubernetes/ # Kubernetes configurations +β”‚ β”œβ”€β”€ shared-cluster/ # Shared cluster setup +β”‚ └── dev-staging/ # Dev/staging cluster configs +β”œβ”€β”€ monitoring/ # Monitoring stack +β”‚ β”œβ”€β”€ prometheus/ # Prometheus/Grafana +β”‚ β”œβ”€β”€ loki/ # Loki logging +β”‚ └── alerts/ # Alerting rules +β”œβ”€β”€ api-gateway/ # API Gateway (Kong) +β”œβ”€β”€ event-bus/ # Event bus (NATS) +β”œβ”€β”€ identity/ # Identity provider (Keycloak) +└── data-storage/ # Data storage (MinIO) +``` + +--- + +## Terraform Modules + +### Azure Modules +- `azure/networking` - Virtual networks and subnets +- `azure/keyvault` - Key Vault +- `azure/storage` - Storage accounts + +### Kubernetes Modules +- `kubernetes/namespace` - Namespace with quotas + +--- + +## Deployment + +### Monitoring +```bash +cd monitoring/prometheus && ./install.sh +cd monitoring/loki && ./install.sh +``` + +### API Gateway +```bash +cd api-gateway/kong && ./install.sh +``` + +### Event Bus +```bash +cd event-bus/nats && ./install.sh +``` + +### Identity +```bash +kubectl apply -f identity/keycloak/k8s-deployment.yaml +``` + +### Data Storage +```bash +kubectl apply -f data-storage/minio/k8s-deployment.yaml +``` + +--- + +## Documentation + +- [Infrastructure Deployment Guide](../docs/INFRASTRUCTURE_DEPLOYMENT_GUIDE.md) +- [Terraform Migration Guide](../docs/TERRAFORM_MIGRATION_GUIDE.md) + +--- + +**Status**: 🚧 Structure Complete - Ready for Project Consolidation + diff --git a/api-gateway/kong/install.sh b/api-gateway/kong/install.sh new file mode 100755 index 0000000..2b51755 --- /dev/null +++ b/api-gateway/kong/install.sh @@ -0,0 +1,39 @@ +#!/bin/bash +# Install Kong API Gateway + +set -e + +NAMESPACE="api-gateway" + +echo "πŸšͺ Installing Kong API Gateway..." + +# Check prerequisites +command -v kubectl >/dev/null 2>&1 || { echo "❌ kubectl not found"; exit 1; } + +# Create namespace +echo "πŸ“¦ Creating namespace: $NAMESPACE" +kubectl create namespace "$NAMESPACE" --dry-run=client -o yaml | kubectl apply -f - + +# Create ConfigMap from kong.yaml +echo "πŸ“ Creating Kong configuration..." +kubectl create configmap kong-config \ + --from-file=kong.yaml=kong.yaml \ + --namespace="$NAMESPACE" \ + --dry-run=client -o yaml | kubectl apply -f - + +# Apply deployment +echo "πŸš€ Deploying Kong..." +kubectl apply -f k8s-deployment.yaml + +# Wait for deployment +echo "⏳ Waiting for Kong to be ready..." +kubectl wait --for=condition=available --timeout=300s deployment/kong -n "$NAMESPACE" + +echo "βœ… Kong API Gateway installed successfully!" +echo "" +echo "πŸ“ Access Kong Admin API:" +echo " kubectl port-forward -n $NAMESPACE svc/kong-proxy 8001:8001" +echo "" +echo "πŸ“ Access Kong Proxy:" +echo " kubectl port-forward -n $NAMESPACE svc/kong-proxy 8000:80" + diff --git a/api-gateway/kong/k8s-deployment.yaml b/api-gateway/kong/k8s-deployment.yaml new file mode 100644 index 0000000..e2221f9 --- /dev/null +++ b/api-gateway/kong/k8s-deployment.yaml @@ -0,0 +1,89 @@ +# Kong API Gateway Kubernetes Deployment + +apiVersion: v1 +kind: Namespace +metadata: + name: api-gateway +--- +apiVersion: apps/v1 +kind: Deployment +metadata: + name: kong + namespace: api-gateway +spec: + replicas: 2 + selector: + matchLabels: + app: kong + template: + metadata: + labels: + app: kong + spec: + containers: + - name: kong + image: kong:3.4 + env: + - name: KONG_DATABASE + value: "off" + - name: KONG_DECLARATIVE_CONFIG + value: "/kong/kong.yaml" + - name: KONG_PROXY_ACCESS_LOG + value: /dev/stdout + - name: KONG_ADMIN_ACCESS_LOG + value: /dev/stdout + - name: KONG_PROXY_ERROR_LOG + value: /dev/stderr + - name: KONG_ADMIN_ERROR_LOG + value: /dev/stderr + - name: KONG_ADMIN_LISTEN + value: "0.0.0.0:8001" + ports: + - name: proxy + containerPort: 8000 + - name: admin + containerPort: 8001 + resources: + requests: + memory: "256Mi" + cpu: "100m" + limits: + memory: "512Mi" + cpu: "500m" + volumeMounts: + - name: kong-config + mountPath: /kong/kong.yaml + subPath: kong.yaml + volumes: + - name: kong-config + configMap: + name: kong-config +--- +apiVersion: v1 +kind: Service +metadata: + name: kong-proxy + namespace: api-gateway +spec: + type: LoadBalancer + ports: + - port: 80 + targetPort: 8000 + protocol: TCP + name: http + - port: 443 + targetPort: 8443 + protocol: TCP + name: https + selector: + app: kong +--- +apiVersion: v1 +kind: ConfigMap +metadata: + name: kong-config + namespace: api-gateway +data: + kong.yaml: | + # Kong configuration will be loaded from kong.yaml file + diff --git a/api-gateway/kong/kong.yaml b/api-gateway/kong/kong.yaml new file mode 100644 index 0000000..1033bcf --- /dev/null +++ b/api-gateway/kong/kong.yaml @@ -0,0 +1,75 @@ +# Kong API Gateway Configuration + +_format_version: "3.0" + +services: + - name: example-service + url: http://example-service:8080 + routes: + - name: example-route + paths: + - /api/example + methods: + - GET + - POST + - PUT + - DELETE + strip_path: false + preserve_host: true + +plugins: + - name: rate-limiting + service: example-service + config: + minute: 100 + hour: 1000 + policy: local + fault_tolerant: true + hide_client_headers: false + + - name: cors + service: example-service + config: + origins: + - "*" + methods: + - GET + - POST + - PUT + - DELETE + - OPTIONS + headers: + - Accept + - Accept-Version + - Content-Length + - Content-MD5 + - Content-Type + - Date + - Authorization + exposed_headers: + - X-Auth-Token + credentials: true + max_age: 3600 + + - name: jwt + service: example-service + config: + uri_param_names: + - token + cookie_names: + - jwt + claims_to_verify: + - exp + - iat + secret_is_base64: false + run_on_preflight: true + +consumers: + - username: api-consumer + custom_id: api-consumer-001 + +jwt_secrets: + - consumer: api-consumer + key: api-key-001 + secret: your-secret-key-here + diff --git a/data-storage/data-catalog/README.md b/data-storage/data-catalog/README.md new file mode 100644 index 0000000..308029b --- /dev/null +++ b/data-storage/data-catalog/README.md @@ -0,0 +1,112 @@ +# Data Catalog + +**Purpose**: Unified data catalog for tracking and discovering datasets +**Status**: 🚧 Planned + +--- + +## Overview + +The data catalog provides a centralized registry for all datasets across the workspace, enabling discovery, access control, and metadata management. + +--- + +## Features + +- Dataset registration +- Metadata management +- Search and discovery +- Access control +- Schema tracking +- Lineage tracking + +--- + +## Schema + +See `metadata-schema.json` for the complete metadata schema. + +### Key Fields + +- **id**: Unique dataset identifier +- **name**: Human-readable name +- **source**: Source system/project +- **storage**: Storage location details +- **schema**: Data schema definition +- **tags**: Categorization tags +- **access**: Access control settings + +--- + +## Implementation Options + +### Option 1: Custom API +- Build custom API using shared packages +- Use PostgreSQL for metadata storage +- Implement search using PostgreSQL full-text search + +### Option 2: DataHub +- Deploy DataHub (open-source) +- Use existing metadata models +- Leverage built-in features + +### Option 3: Amundsen +- Deploy Amundsen (open-source) +- Use existing metadata models +- Leverage built-in features + +--- + +## Usage + +### Register Dataset + +```json +{ + "id": "user-events-2025", + "name": "User Events 2025", + "description": "User interaction events for 2025", + "source": "analytics-service", + "storage": { + "type": "minio", + "bucket": "analytics", + "path": "events/2025/" + }, + "format": "parquet", + "tags": ["events", "analytics", "2025"], + "owner": "analytics-team", + "access": { + "level": "internal", + "permissions": ["read"] + } +} +``` + +### Search Datasets + +```bash +# Search by tag +GET /api/catalog/datasets?tag=analytics + +# Search by source +GET /api/catalog/datasets?source=analytics-service + +# Full-text search +GET /api/catalog/datasets?q=user+events +``` + +--- + +## Next Steps + +1. Choose implementation option +2. Set up metadata storage +3. Implement registration API +4. Implement search functionality +5. Set up access control +6. Integrate with projects + +--- + +**Status**: 🚧 Planned - Schema and design complete, implementation pending + diff --git a/data-storage/data-catalog/metadata-schema.json b/data-storage/data-catalog/metadata-schema.json new file mode 100644 index 0000000..c2bf22e --- /dev/null +++ b/data-storage/data-catalog/metadata-schema.json @@ -0,0 +1,92 @@ +{ + "$schema": "http://json-schema.org/draft-07/schema#", + "type": "object", + "title": "Data Catalog Metadata Schema", + "description": "Schema for data catalog metadata", + "properties": { + "id": { + "type": "string", + "description": "Unique identifier for the dataset" + }, + "name": { + "type": "string", + "description": "Human-readable name of the dataset" + }, + "description": { + "type": "string", + "description": "Description of the dataset" + }, + "source": { + "type": "string", + "description": "Source system or project" + }, + "storage": { + "type": "object", + "properties": { + "type": { + "type": "string", + "enum": ["s3", "minio", "azure-blob", "gcs"], + "description": "Storage type" + }, + "bucket": { + "type": "string", + "description": "Bucket or container name" + }, + "path": { + "type": "string", + "description": "Path within bucket" + } + }, + "required": ["type", "bucket"] + }, + "schema": { + "type": "object", + "description": "Data schema definition" + }, + "format": { + "type": "string", + "enum": ["parquet", "json", "csv", "avro"], + "description": "Data format" + }, + "tags": { + "type": "array", + "items": { + "type": "string" + }, + "description": "Tags for categorization" + }, + "owner": { + "type": "string", + "description": "Owner or team responsible" + }, + "created": { + "type": "string", + "format": "date-time", + "description": "Creation timestamp" + }, + "updated": { + "type": "string", + "format": "date-time", + "description": "Last update timestamp" + }, + "access": { + "type": "object", + "properties": { + "level": { + "type": "string", + "enum": ["public", "internal", "restricted"], + "description": "Access level" + }, + "permissions": { + "type": "array", + "items": { + "type": "string", + "enum": ["read", "write", "delete"] + } + } + } + } + }, + "required": ["id", "name", "source", "storage"] +} + diff --git a/data-storage/minio/k8s-deployment.yaml b/data-storage/minio/k8s-deployment.yaml new file mode 100644 index 0000000..6942979 --- /dev/null +++ b/data-storage/minio/k8s-deployment.yaml @@ -0,0 +1,100 @@ +# MinIO Object Storage Kubernetes Deployment + +apiVersion: v1 +kind: Namespace +metadata: + name: data-storage +--- +apiVersion: v1 +kind: Secret +metadata: + name: minio-secret + namespace: data-storage +type: Opaque +stringData: + MINIO_ROOT_USER: minioadmin + MINIO_ROOT_PASSWORD: change-me-in-production +--- +apiVersion: apps/v1 +kind: StatefulSet +metadata: + name: minio + namespace: data-storage +spec: + serviceName: minio + replicas: 4 + selector: + matchLabels: + app: minio + template: + metadata: + labels: + app: minio + spec: + containers: + - name: minio + image: minio/minio:latest + args: + - server + - /data + - --console-address + - ":9001" + envFrom: + - secretRef: + name: minio-secret + ports: + - containerPort: 9000 + name: api + - containerPort: 9001 + name: console + volumeMounts: + - name: data + mountPath: /data + resources: + requests: + memory: "512Mi" + cpu: "250m" + limits: + memory: "1Gi" + cpu: "500m" + volumeClaimTemplates: + - metadata: + name: data + spec: + accessModes: ["ReadWriteOnce"] + storageClassName: standard + resources: + requests: + storage: 100Gi +--- +apiVersion: v1 +kind: Service +metadata: + name: minio + namespace: data-storage +spec: + clusterIP: None + ports: + - port: 9000 + targetPort: 9000 + name: api + - port: 9001 + targetPort: 9001 + name: console + selector: + app: minio +--- +apiVersion: v1 +kind: Service +metadata: + name: minio-console + namespace: data-storage +spec: + type: LoadBalancer + ports: + - port: 9001 + targetPort: 9001 + name: console + selector: + app: minio + diff --git a/event-bus/nats/install.sh b/event-bus/nats/install.sh new file mode 100755 index 0000000..fbe197b --- /dev/null +++ b/event-bus/nats/install.sh @@ -0,0 +1,30 @@ +#!/bin/bash +# Install NATS Event Bus + +set -e + +NAMESPACE="event-bus" + +echo "πŸ“‘ Installing NATS Event Bus..." + +# Check prerequisites +command -v kubectl >/dev/null 2>&1 || { echo "❌ kubectl not found"; exit 1; } + +# Create namespace +echo "πŸ“¦ Creating namespace: $NAMESPACE" +kubectl create namespace "$NAMESPACE" --dry-run=client -o yaml | kubectl apply -f - + +# Apply deployment +echo "πŸš€ Deploying NATS..." +kubectl apply -f k8s-deployment.yaml + +# Wait for StatefulSet +echo "⏳ Waiting for NATS to be ready..." +kubectl wait --for=condition=ready --timeout=300s pod -l app=nats -n "$NAMESPACE" + +echo "βœ… NATS Event Bus installed successfully!" +echo "" +echo "πŸ“ Access NATS monitoring:" +echo " kubectl port-forward -n $NAMESPACE svc/nats 8222:8222" +echo " Then visit: http://localhost:8222" + diff --git a/event-bus/nats/k8s-deployment.yaml b/event-bus/nats/k8s-deployment.yaml new file mode 100644 index 0000000..87ba2f8 --- /dev/null +++ b/event-bus/nats/k8s-deployment.yaml @@ -0,0 +1,96 @@ +# NATS Server Kubernetes Deployment + +apiVersion: v1 +kind: Namespace +metadata: + name: event-bus +--- +apiVersion: v1 +kind: ConfigMap +metadata: + name: nats-config + namespace: event-bus +data: + nats.conf: | + port: 4222 + http_port: 8222 + jetstream: + store_dir: /data/jetstream + max_mem: 2GB + max_file: 10GB +--- +apiVersion: apps/v1 +kind: StatefulSet +metadata: + name: nats + namespace: event-bus +spec: + serviceName: nats + replicas: 3 + selector: + matchLabels: + app: nats + template: + metadata: + labels: + app: nats + spec: + containers: + - name: nats + image: nats:2.10-alpine + args: + - -c + - /etc/nats/nats.conf + ports: + - name: client + containerPort: 4222 + - name: cluster + containerPort: 6222 + - name: monitor + containerPort: 8222 + volumeMounts: + - name: config + mountPath: /etc/nats + - name: data + mountPath: /data/jetstream + resources: + requests: + memory: "512Mi" + cpu: "200m" + limits: + memory: "1Gi" + cpu: "500m" + volumes: + - name: config + configMap: + name: nats-config + volumeClaimTemplates: + - metadata: + name: data + spec: + accessModes: ["ReadWriteOnce"] + storageClassName: standard + resources: + requests: + storage: 10Gi +--- +apiVersion: v1 +kind: Service +metadata: + name: nats + namespace: event-bus +spec: + clusterIP: None + ports: + - port: 4222 + targetPort: 4222 + name: client + - port: 6222 + targetPort: 6222 + name: cluster + - port: 8222 + targetPort: 8222 + name: monitor + selector: + app: nats + diff --git a/event-bus/nats/nats.yaml b/event-bus/nats/nats.yaml new file mode 100644 index 0000000..a2f5898 --- /dev/null +++ b/event-bus/nats/nats.yaml @@ -0,0 +1,41 @@ +# NATS Server Configuration + +port: 4222 +http_port: 8222 +cluster: + port: 6222 + routes: + - nats://nats-1:6222 + - nats://nats-2:6222 + - nats://nats-3:6222 + +jetstream: + store_dir: /data/jetstream + max_mem: 2GB + max_file: 10GB + +logging: + time: true + debug: false + trace: false + logtime: true + log_file: "/var/log/nats/nats.log" + log_size_limit: 100MB + +authorization: + users: + - user: api-user + password: ${NATS_API_PASSWORD} + permissions: + publish: + - ">" + subscribe: + - ">" + - user: service-user + password: ${NATS_SERVICE_PASSWORD} + permissions: + publish: + - "events.>" + subscribe: + - "events.>" + diff --git a/identity/keycloak/k8s-deployment.yaml b/identity/keycloak/k8s-deployment.yaml new file mode 100644 index 0000000..f6f33e9 --- /dev/null +++ b/identity/keycloak/k8s-deployment.yaml @@ -0,0 +1,109 @@ +# Keycloak Identity Provider Kubernetes Deployment + +apiVersion: v1 +kind: Namespace +metadata: + name: identity +--- +apiVersion: v1 +kind: Secret +metadata: + name: keycloak-db-secret + namespace: identity +type: Opaque +stringData: + username: keycloak + password: change-me-in-production +--- +apiVersion: apps/v1 +kind: Deployment +metadata: + name: keycloak + namespace: identity +spec: + replicas: 2 + selector: + matchLabels: + app: keycloak + template: + metadata: + labels: + app: keycloak + spec: + containers: + - name: keycloak + image: quay.io/keycloak/keycloak:23.0 + args: + - start + - --hostname-strict=false + - --proxy-headers=xforwarded + - --http-relative-path=/ + env: + - name: KEYCLOAK_ADMIN + value: admin + - name: KEYCLOAK_ADMIN_PASSWORD + valueFrom: + secretKeyRef: + name: keycloak-admin-secret + key: password + - name: KC_DB + value: postgres + - name: KC_DB_URL + value: jdbc:postgresql://postgres:5432/keycloak + - name: KC_DB_USERNAME + valueFrom: + secretKeyRef: + name: keycloak-db-secret + key: username + - name: KC_DB_PASSWORD + valueFrom: + secretKeyRef: + name: keycloak-db-secret + key: password + ports: + - containerPort: 8080 + name: http + resources: + requests: + memory: "1Gi" + cpu: "500m" + limits: + memory: "2Gi" + cpu: "1000m" + readinessProbe: + httpGet: + path: /health/ready + port: 8080 + initialDelaySeconds: 60 + periodSeconds: 10 + livenessProbe: + httpGet: + path: /health/live + port: 8080 + initialDelaySeconds: 60 + periodSeconds: 10 +--- +apiVersion: v1 +kind: Service +metadata: + name: keycloak + namespace: identity +spec: + type: LoadBalancer + ports: + - port: 80 + targetPort: 8080 + protocol: TCP + name: http + selector: + app: keycloak +--- +apiVersion: v1 +kind: Secret +metadata: + name: keycloak-admin-secret + namespace: identity +type: Opaque +stringData: + password: change-me-in-production + diff --git a/identity/user-management/keycloak-realm.json b/identity/user-management/keycloak-realm.json new file mode 100644 index 0000000..fa738e9 --- /dev/null +++ b/identity/user-management/keycloak-realm.json @@ -0,0 +1,69 @@ +{ + "realm": "workspace", + "enabled": true, + "displayName": "Workspace Realm", + "displayNameHtml": "
Workspace
", + "users": [ + { + "username": "admin", + "enabled": true, + "emailVerified": true, + "firstName": "Admin", + "lastName": "User", + "email": "admin@example.com", + "credentials": [ + { + "type": "password", + "value": "change-me-in-production", + "temporary": false + } + ], + "realmRoles": ["admin", "user"] + } + ], + "roles": { + "realm": [ + { + "name": "admin", + "description": "Administrator role" + }, + { + "name": "user", + "description": "Standard user role" + }, + { + "name": "developer", + "description": "Developer role" + }, + { + "name": "viewer", + "description": "View-only role" + } + ] + }, + "clients": [ + { + "clientId": "workspace-api", + "enabled": true, + "clientAuthenticatorType": "client-secret", + "secret": "change-me-in-production", + "redirectUris": ["*"], + "webOrigins": ["*"], + "protocol": "openid-connect", + "publicClient": false, + "standardFlowEnabled": true, + "directAccessGrantsEnabled": true + } + ], + "identityProviders": [], + "smtpServer": { + "host": "smtp.example.com", + "port": "587", + "from": "noreply@example.com", + "auth": true, + "starttls": true, + "user": "smtp-user", + "password": "smtp-password" + } +} + diff --git a/identity/user-management/setup.sh b/identity/user-management/setup.sh new file mode 100755 index 0000000..5bf7e99 --- /dev/null +++ b/identity/user-management/setup.sh @@ -0,0 +1,48 @@ +#!/bin/bash +# Setup centralized user management in Keycloak + +set -e + +NAMESPACE="identity" +KEYCLOAK_URL="${KEYCLOAK_URL:-http://keycloak.${NAMESPACE}.svc.cluster.local:8080}" +ADMIN_USER="${KEYCLOAK_ADMIN:-admin}" +ADMIN_PASSWORD="${KEYCLOAK_ADMIN_PASSWORD:-change-me-in-production}" + +echo "πŸ‘₯ Setting up centralized user management..." + +# Check if Keycloak is accessible +if ! curl -s "${KEYCLOAK_URL}/health" > /dev/null; then + echo "⚠️ Keycloak not accessible at $KEYCLOAK_URL" + echo " β†’ Ensure Keycloak is deployed and running" + exit 1 +fi + +# Get admin token +echo "πŸ”‘ Getting admin token..." +TOKEN=$(curl -s -X POST "${KEYCLOAK_URL}/realms/master/protocol/openid-connect/token" \ + -d "client_id=admin-cli" \ + -d "username=${ADMIN_USER}" \ + -d "password=${ADMIN_PASSWORD}" \ + -d "grant_type=password" | jq -r '.access_token') + +if [ -z "$TOKEN" ] || [ "$TOKEN" == "null" ]; then + echo "❌ Failed to get admin token" + exit 1 +fi + +# Create realm +echo "🌍 Creating workspace realm..." +curl -s -X POST "${KEYCLOAK_URL}/admin/realms" \ + -H "Authorization: Bearer $TOKEN" \ + -H "Content-Type: application/json" \ + -d @keycloak-realm.json + +echo "βœ… User management setup complete!" +echo "" +echo "πŸ“ Next steps:" +echo " 1. Access Keycloak admin console" +echo " 2. Review realm configuration" +echo " 3. Create additional users and roles" +echo " 4. Configure identity providers (if needed)" +echo " 5. Set up user federation (if needed)" + diff --git a/kubernetes/dev-staging/cluster-config.yaml b/kubernetes/dev-staging/cluster-config.yaml new file mode 100644 index 0000000..a8fdc5e --- /dev/null +++ b/kubernetes/dev-staging/cluster-config.yaml @@ -0,0 +1,31 @@ +# Development and Staging Kubernetes Cluster Configuration + +apiVersion: v1 +kind: ConfigMap +metadata: + name: cluster-config + namespace: kube-system +data: + environment: "dev-staging" + cluster-type: "shared" + node-pool: + dev: "dev-pool" + staging: "staging-pool" + resource-quotas: + dev: | + requests.cpu: "4" + requests.memory: "8Gi" + limits.cpu: "8" + limits.memory: "16Gi" + staging: | + requests.cpu: "8" + requests.memory: "16Gi" + limits.cpu: "16" + limits.memory: "32Gi" + storage-classes: + dev: "standard" + staging: "premium" + network-policies: "enabled" + monitoring: "enabled" + logging: "enabled" + diff --git a/kubernetes/dev-staging/setup.sh b/kubernetes/dev-staging/setup.sh new file mode 100755 index 0000000..8b449d7 --- /dev/null +++ b/kubernetes/dev-staging/setup.sh @@ -0,0 +1,70 @@ +#!/bin/bash +# Setup shared dev/staging Kubernetes clusters + +set -e + +echo "☸️ Setting up shared dev/staging Kubernetes clusters..." + +# Check prerequisites +command -v kubectl >/dev/null 2>&1 || { echo "❌ kubectl not found"; exit 1; } +command -v helm >/dev/null 2>&1 || { echo "❌ helm not found"; exit 1; } + +# Create namespaces +echo "πŸ“¦ Creating namespaces..." +kubectl create namespace dev --dry-run=client -o yaml | kubectl apply -f - +kubectl create namespace staging --dry-run=client -o yaml | kubectl apply -f - + +# Label namespaces +kubectl label namespace dev environment=dev --overwrite +kubectl label namespace staging environment=staging --overwrite + +# Apply cluster configuration +echo "βš™οΈ Applying cluster configuration..." +kubectl apply -f cluster-config.yaml + +# Set up resource quotas +echo "πŸ“Š Setting up resource quotas..." + +# Dev namespace quota +cat </dev/null 2>&1 || { echo "❌ kubectl not found"; exit 1; } + +# Apply namespace isolation +echo "πŸ”’ Applying namespace isolation..." +kubectl apply -f namespace-isolation.yaml + +# Apply ingress controller +echo "πŸšͺ Setting up ingress controller..." +kubectl apply -f ingress-controller.yaml + +# Wait for ingress controller +echo "⏳ Waiting for ingress controller to be ready..." +kubectl wait --for=condition=available --timeout=300s deployment/ingress-nginx-controller -n ingress-nginx + +echo "βœ… Shared Kubernetes cluster configuration complete!" +echo "" +echo "πŸ“ Ingress controller is ready" +echo " Get external IP: kubectl get svc -n ingress-nginx ingress-nginx" + diff --git a/monitoring/alerts/prometheus-rules.yaml b/monitoring/alerts/prometheus-rules.yaml new file mode 100644 index 0000000..addefc7 --- /dev/null +++ b/monitoring/alerts/prometheus-rules.yaml @@ -0,0 +1,101 @@ +# Prometheus Alerting Rules + +apiVersion: monitoring.coreos.com/v1 +kind: PrometheusRule +metadata: + name: shared-services-alerts + namespace: monitoring + labels: + app: prometheus +spec: + groups: + - name: kubernetes.rules + interval: 30s + rules: + - alert: PodCrashLooping + expr: rate(kube_pod_container_status_restarts_total[15m]) > 0 + for: 5m + labels: + severity: warning + annotations: + summary: "Pod {{ $labels.namespace }}/{{ $labels.pod }} is crash looping" + description: "Pod {{ $labels.namespace }}/{{ $labels.pod }} has restarted {{ $value }} times in the last 15 minutes" + + - alert: PodNotReady + expr: sum by (namespace, pod) (kube_pod_status_phase{phase!~"Running|Succeeded"}) > 0 + for: 10m + labels: + severity: warning + annotations: + summary: "Pod {{ $labels.namespace }}/{{ $labels.pod }} is not ready" + description: "Pod {{ $labels.namespace }}/{{ $labels.pod }} has been in a non-ready state for more than 10 minutes" + + - alert: HighMemoryUsage + expr: (sum by (namespace, pod) (container_memory_usage_bytes) / sum by (namespace, pod) (kube_pod_container_resource_limits_memory_bytes)) > 0.9 + for: 5m + labels: + severity: warning + annotations: + summary: "Pod {{ $labels.namespace }}/{{ $labels.pod }} memory usage is high" + description: "Pod {{ $labels.namespace }}/{{ $labels.pod }} is using {{ $value | humanizePercentage }} of its memory limit" + + - alert: HighCPUUsage + expr: (sum by (namespace, pod) (rate(container_cpu_usage_seconds_total[5m])) / sum by (namespace, pod) (kube_pod_container_resource_limits_cpu)) > 0.9 + for: 5m + labels: + severity: warning + annotations: + summary: "Pod {{ $labels.namespace }}/{{ $labels.pod }} CPU usage is high" + description: "Pod {{ $labels.namespace }}/{{ $labels.pod }} is using {{ $value | humanizePercentage }} of its CPU limit" + + - name: application.rules + interval: 30s + rules: + - alert: HighErrorRate + expr: rate(http_requests_total{status=~"5.."}[5m]) > 0.1 + for: 5m + labels: + severity: critical + annotations: + summary: "High error rate detected" + description: "Error rate is {{ $value }} errors per second" + + - alert: HighLatency + expr: histogram_quantile(0.95, rate(http_request_duration_seconds_bucket[5m])) > 1 + for: 10m + labels: + severity: warning + annotations: + summary: "High latency detected" + description: "95th percentile latency is {{ $value }} seconds" + + - alert: ServiceDown + expr: up{job=~".+"} == 0 + for: 1m + labels: + severity: critical + annotations: + summary: "Service {{ $labels.job }} is down" + description: "Service {{ $labels.job }} has been down for more than 1 minute" + + - name: infrastructure.rules + interval: 30s + rules: + - alert: NodeNotReady + expr: kube_node_status_condition{condition="Ready",status="true"} == 0 + for: 5m + labels: + severity: critical + annotations: + summary: "Node {{ $labels.node }} is not ready" + description: "Node {{ $labels.node }} has been in a not-ready state for more than 5 minutes" + + - alert: DiskSpaceLow + expr: (node_filesystem_avail_bytes / node_filesystem_size_bytes) < 0.1 + for: 5m + labels: + severity: warning + annotations: + summary: "Disk space low on {{ $labels.instance }}" + description: "Disk {{ $labels.device }} on {{ $labels.instance }} has only {{ $value | humanizePercentage }} space available" + diff --git a/monitoring/event-monitoring/prometheus-rules.yaml b/monitoring/event-monitoring/prometheus-rules.yaml new file mode 100644 index 0000000..a3010fb --- /dev/null +++ b/monitoring/event-monitoring/prometheus-rules.yaml @@ -0,0 +1,50 @@ +# Event Bus Monitoring Rules + +apiVersion: monitoring.coreos.com/v1 +kind: PrometheusRule +metadata: + name: event-bus-alerts + namespace: event-bus + labels: + app: nats +spec: + groups: + - name: nats.rules + interval: 30s + rules: + - alert: NATSConnectionFailure + expr: nats_connz_connections{state!="OPEN"} > 0 + for: 5m + labels: + severity: warning + annotations: + summary: "NATS connection failure detected" + description: "NATS has {{ $value }} non-open connections" + + - alert: NATSHighMessageRate + expr: rate(nats_varz_in_msgs[5m]) > 10000 + for: 10m + labels: + severity: warning + annotations: + summary: "High NATS message rate" + description: "NATS is processing {{ $value }} messages per second" + + - alert: NATSJetStreamStorageFull + expr: (nats_jetstream_varz_store_bytes / nats_jetstream_varz_store_max_bytes) > 0.9 + for: 5m + labels: + severity: critical + annotations: + summary: "NATS JetStream storage nearly full" + description: "JetStream storage is {{ $value | humanizePercentage }} full" + + - alert: NATSPodDown + expr: up{job="nats"} == 0 + for: 1m + labels: + severity: critical + annotations: + summary: "NATS pod is down" + description: "NATS pod has been down for more than 1 minute" + diff --git a/monitoring/event-monitoring/setup.sh b/monitoring/event-monitoring/setup.sh new file mode 100755 index 0000000..5e99b25 --- /dev/null +++ b/monitoring/event-monitoring/setup.sh @@ -0,0 +1,19 @@ +#!/bin/bash +# Setup event monitoring + +set -e + +echo "πŸ“‘ Setting up event monitoring..." + +# Apply Prometheus rules +echo "πŸ“Š Applying Prometheus rules for event bus..." +kubectl apply -f prometheus-rules.yaml + +echo "βœ… Event monitoring configured!" +echo "" +echo "πŸ“ Monitoring:" +echo " - NATS connection metrics" +echo " - Message rate metrics" +echo " - JetStream storage metrics" +echo " - Pod health metrics" + diff --git a/monitoring/loki/install.sh b/monitoring/loki/install.sh new file mode 100755 index 0000000..1c5e644 --- /dev/null +++ b/monitoring/loki/install.sh @@ -0,0 +1,36 @@ +#!/bin/bash +# Install Loki Stack for Logging + +set -e + +NAMESPACE="monitoring" +RELEASE_NAME="loki" + +echo "πŸ“Š Installing Loki Stack..." + +# Check prerequisites +command -v helm >/dev/null 2>&1 || { echo "❌ helm not found"; exit 1; } +command -v kubectl >/dev/null 2>&1 || { echo "❌ kubectl not found"; exit 1; } + +# Create namespace +echo "πŸ“¦ Creating namespace: $NAMESPACE" +kubectl create namespace "$NAMESPACE" --dry-run=client -o yaml | kubectl apply -f - + +# Add Grafana Helm repo +echo "πŸ“₯ Adding Grafana Helm repository..." +helm repo add grafana https://grafana.github.io/helm-charts +helm repo update + +# Install Loki Stack +echo "πŸš€ Installing Loki Stack..." +helm upgrade --install "$RELEASE_NAME" grafana/loki-stack \ + --namespace "$NAMESPACE" \ + --create-namespace \ + --values values.yaml \ + --wait + +echo "βœ… Loki Stack installed successfully!" +echo "" +echo "πŸ“ Access Grafana:" +echo " kubectl port-forward -n $NAMESPACE svc/$RELEASE_NAME-grafana 3000:80" + diff --git a/monitoring/loki/values.yaml b/monitoring/loki/values.yaml new file mode 100644 index 0000000..57320ee --- /dev/null +++ b/monitoring/loki/values.yaml @@ -0,0 +1,87 @@ +# Loki Stack Helm Values + +loki: + enabled: true + persistence: + enabled: true + storageClassName: standard + size: 50Gi + resources: + requests: + memory: 1Gi + cpu: 500m + limits: + memory: 2Gi + cpu: 1000m + config: + schema_config: + configs: + - from: 2020-10-24 + store: boltdb-shipper + object_store: filesystem + schema: v11 + index: + prefix: index_ + period: 24h + storage_config: + boltdb_shipper: + active_index_directory: /loki/boltdb-shipper-active + cache_location: /loki/boltdb-shipper-cache + shared_store: filesystem + filesystem: + directory: /loki/chunks + limits_config: + ingestion_rate_mb: 10 + ingestion_burst_size_mb: 20 + max_query_length: 0h + max_query_parallelism: 32 + max_streams_per_user: 10000 + +promtail: + enabled: true + config: + clients: + - url: http://loki:3100/loki/api/v1/push + scrape_configs: + - job_name: kubernetes-pods + kubernetes_sd_configs: + - role: pod + relabel_configs: + - source_labels: + - __meta_kubernetes_pod_controller_name + regex: ([0-9a-z-.]+?)(-[0-9a-f]{8,10})? + action: replace + target_label: __tmp_controller_name + - source_labels: + - __meta_kubernetes_pod_label_app_kubernetes_io_name + - __meta_kubernetes_pod_label_app + - __tmp_controller_name + - __meta_kubernetes_pod_name + regex: ^;*([^;]+)(;.*)?$ + action: replace + target_label: app + - source_labels: + - __meta_kubernetes_pod_label_app_kubernetes_io_instance + - __meta_kubernetes_pod_label_release + regex: ^;*([^;]+)(;.*)?$ + action: replace + target_label: instance + - source_labels: + - __meta_kubernetes_pod_label_app_kubernetes_io_component + - __meta_kubernetes_pod_label_component + regex: ^;*([^;]+)(;.*)?$ + action: replace + target_label: component + +grafana: + enabled: true + datasources: + datasources.yaml: + apiVersion: 1 + datasources: + - name: Loki + type: loki + access: proxy + url: http://loki:3100 + isDefault: false + diff --git a/monitoring/metrics-dashboard/grafana-dashboard.json b/monitoring/metrics-dashboard/grafana-dashboard.json new file mode 100644 index 0000000..c660454 --- /dev/null +++ b/monitoring/metrics-dashboard/grafana-dashboard.json @@ -0,0 +1,151 @@ +{ + "dashboard": { + "title": "Integration & Streamlining Success Metrics", + "tags": ["metrics", "success", "integration"], + "timezone": "browser", + "panels": [ + { + "id": 1, + "title": "Infrastructure Cost Reduction", + "type": "stat", + "targets": [ + { + "expr": "infrastructure_cost_reduction_percent", + "legendFormat": "Cost Reduction" + } + ], + "fieldConfig": { + "defaults": { + "unit": "percent", + "thresholds": { + "steps": [ + { "value": 0, "color": "red" }, + { "value": 30, "color": "yellow" }, + { "value": 40, "color": "green" } + ] + } + } + } + }, + { + "id": 2, + "title": "Shared Infrastructure Adoption", + "type": "stat", + "targets": [ + { + "expr": "shared_infrastructure_adoption_percent", + "legendFormat": "Adoption" + } + ], + "fieldConfig": { + "defaults": { + "unit": "percent", + "thresholds": { + "steps": [ + { "value": 0, "color": "red" }, + { "value": 60, "color": "yellow" }, + { "value": 80, "color": "green" } + ] + } + } + } + }, + { + "id": 3, + "title": "Shared Packages Usage", + "type": "stat", + "targets": [ + { + "expr": "shared_packages_count", + "legendFormat": "Packages" + } + ], + "fieldConfig": { + "defaults": { + "unit": "short", + "thresholds": { + "steps": [ + { "value": 0, "color": "red" }, + { "value": 7, "color": "yellow" }, + { "value": 10, "color": "green" } + ] + } + } + } + }, + { + "id": 4, + "title": "Deployment Time Reduction", + "type": "stat", + "targets": [ + { + "expr": "deployment_time_reduction_percent", + "legendFormat": "Time Reduction" + } + ], + "fieldConfig": { + "defaults": { + "unit": "percent", + "thresholds": { + "steps": [ + { "value": 0, "color": "red" }, + { "value": 30, "color": "yellow" }, + { "value": 50, "color": "green" } + ] + } + } + } + }, + { + "id": 5, + "title": "CI/CD Adoption", + "type": "stat", + "targets": [ + { + "expr": "cicd_adoption_percent", + "legendFormat": "Adoption" + } + ], + "fieldConfig": { + "defaults": { + "unit": "percent", + "thresholds": { + "steps": [ + { "value": 0, "color": "red" }, + { "value": 70, "color": "yellow" }, + { "value": 90, "color": "green" } + ] + } + } + } + }, + { + "id": 6, + "title": "Service Uptime", + "type": "stat", + "targets": [ + { + "expr": "service_uptime_percent", + "legendFormat": "Uptime" + } + ], + "fieldConfig": { + "defaults": { + "unit": "percent", + "thresholds": { + "steps": [ + { "value": 0, "color": "red" }, + { "value": 99, "color": "yellow" }, + { "value": 99.9, "color": "green" } + ] + } + } + } + } + ], + "refresh": "30s", + "schemaVersion": 27, + "version": 1 + } +} + diff --git a/monitoring/metrics-dashboard/setup.sh b/monitoring/metrics-dashboard/setup.sh new file mode 100755 index 0000000..41b1e30 --- /dev/null +++ b/monitoring/metrics-dashboard/setup.sh @@ -0,0 +1,32 @@ +#!/bin/bash +# Setup metrics dashboard in Grafana + +set -e + +NAMESPACE="monitoring" +DASHBOARD_FILE="grafana-dashboard.json" + +echo "πŸ“Š Setting up Metrics Dashboard in Grafana..." + +# Check if Grafana is accessible +if ! kubectl get svc -n "$NAMESPACE" | grep -q grafana; then + echo "⚠️ Grafana not found in namespace $NAMESPACE" + echo " β†’ Deploy Grafana first: cd ../prometheus && ./install.sh" + exit 1 +fi + +# Create ConfigMap with dashboard +echo "πŸ“ Creating dashboard ConfigMap..." +kubectl create configmap metrics-dashboard \ + --from-file=dashboard.json="$DASHBOARD_FILE" \ + -n "$NAMESPACE" \ + --dry-run=client -o yaml | kubectl apply -f - + +echo "βœ… Metrics dashboard configured!" +echo "" +echo "πŸ“ Next steps:" +echo " 1. Access Grafana: kubectl port-forward -n $NAMESPACE svc/prometheus-grafana 3000:80" +echo " 2. Import dashboard from ConfigMap" +echo " 3. Configure data sources" +echo " 4. Set up metrics collection" + diff --git a/monitoring/prometheus/install.sh b/monitoring/prometheus/install.sh new file mode 100755 index 0000000..aa32a59 --- /dev/null +++ b/monitoring/prometheus/install.sh @@ -0,0 +1,47 @@ +#!/bin/bash +# Install Prometheus/Grafana Stack + +set -e + +NAMESPACE="monitoring" +RELEASE_NAME="prometheus" + +echo "πŸ“Š Installing Prometheus/Grafana Stack..." + +# Check if helm is installed +if ! command -v helm &> /dev/null; then + echo "❌ Helm not found. Please install Helm first." + exit 1 +fi + +# Check if kubectl is installed +if ! command -v kubectl &> /dev/null; then + echo "❌ kubectl not found. Please install kubectl first." + exit 1 +fi + +# Create namespace +echo "πŸ“¦ Creating namespace: $NAMESPACE" +kubectl create namespace "$NAMESPACE" --dry-run=client -o yaml | kubectl apply -f - + +# Add Prometheus Helm repo +echo "πŸ“₯ Adding Prometheus Helm repository..." +helm repo add prometheus-community https://prometheus-community.github.io/helm-charts +helm repo update + +# Install Prometheus Stack +echo "πŸš€ Installing Prometheus Stack..." +helm upgrade --install "$RELEASE_NAME" prometheus-community/kube-prometheus-stack \ + --namespace "$NAMESPACE" \ + --create-namespace \ + --values values.yaml \ + --wait + +echo "βœ… Prometheus/Grafana Stack installed successfully!" +echo "" +echo "πŸ“ Access Grafana:" +echo " kubectl port-forward -n $NAMESPACE svc/$RELEASE_NAME-grafana 3000:80" +echo "" +echo "πŸ“ Access Prometheus:" +echo " kubectl port-forward -n $NAMESPACE svc/$RELEASE_NAME-kube-prom-prometheus 9090:9090" + diff --git a/monitoring/prometheus/values.yaml b/monitoring/prometheus/values.yaml new file mode 100644 index 0000000..874bb38 --- /dev/null +++ b/monitoring/prometheus/values.yaml @@ -0,0 +1,86 @@ +# Prometheus Stack Helm Values +# For use with kube-prometheus-stack + +prometheus: + prometheusSpec: + retention: 30d + retentionSize: 50GB + storageSpec: + volumeClaimTemplate: + spec: + accessModes: ["ReadWriteOnce"] + storageClassName: standard + resources: + requests: + storage: 100Gi + resources: + requests: + memory: 2Gi + cpu: 1000m + limits: + memory: 4Gi + cpu: 2000m + serviceMonitorSelectorNilUsesHelmValues: false + podMonitorSelectorNilUsesHelmValues: false + ruleSelectorNilUsesHelmValues: false + +grafana: + enabled: true + adminPassword: "admin" # Change in production + persistence: + enabled: true + size: 10Gi + resources: + requests: + memory: 256Mi + cpu: 100m + limits: + memory: 512Mi + cpu: 500m + dashboardProviders: + dashboardproviders.yaml: + apiVersion: 1 + providers: + - name: 'default' + orgId: 1 + folder: '' + type: file + disableDelete: false + editable: true + options: + path: /var/lib/grafana/dashboards/default + dashboards: + default: + kubernetes-cluster: + gnetId: 7249 + revision: 1 + datasource: Prometheus + +alertmanager: + enabled: true + config: + global: + resolve_timeout: 5m + route: + group_by: ['alertname'] + group_wait: 10s + group_interval: 10s + repeat_interval: 12h + receiver: 'default' + receivers: + - name: 'default' + email_configs: + - to: 'alerts@example.com' + from: 'prometheus@example.com' + smarthost: 'smtp.example.com:587' + auth_username: 'prometheus' + auth_password: 'password' + headers: + Subject: 'Prometheus Alert' + +kubeStateMetrics: + enabled: true + +nodeExporter: + enabled: true + diff --git a/terraform/README.md b/terraform/README.md new file mode 100644 index 0000000..0164ba7 --- /dev/null +++ b/terraform/README.md @@ -0,0 +1,103 @@ +# Shared Terraform Infrastructure + +**Last Updated**: 2025-01-27 +**Purpose**: Centralized Terraform modules and infrastructure configurations + +--- + +## Overview + +This directory contains shared Terraform modules and infrastructure configurations that can be used across multiple projects. + +--- + +## Structure + +``` +infrastructure/terraform/ +β”œβ”€β”€ modules/ # Reusable Terraform modules +β”‚ β”œβ”€β”€ azure/ # Azure-specific modules +β”‚ β”œβ”€β”€ multi-cloud/ # Multi-cloud modules +β”‚ └── shared/ # Shared utilities +β”œβ”€β”€ environments/ # Environment-specific configurations +β”‚ β”œβ”€β”€ dev/ # Development environment +β”‚ β”œβ”€β”€ staging/ # Staging environment +β”‚ └── prod/ # Production environment +└── README.md # This file +``` + +--- + +## Modules (Planned) + +### Azure Modules + +#### networking +- Virtual networks +- Subnets +- Network security groups +- Application Gateway + +#### kubernetes +- AKS cluster +- Node pools +- Networking integration + +#### storage +- Storage accounts +- Containers +- File shares + +#### keyvault +- Azure Key Vault +- RBAC configuration +- Private endpoints + +#### monitoring +- Log Analytics +- Application Insights +- Alert rules + +### Multi-Cloud Modules + +#### azure +- Azure-specific resources + +#### aws +- AWS-specific resources + +#### gcp +- GCP-specific resources + +#### onprem-hci +- On-premises HCI resources + +--- + +## Usage + +### Using Shared Modules + +```hcl +module "networking" { + source = "../../infrastructure/terraform/modules/azure/networking" + + environment = var.environment + location = var.location + # ... module variables +} +``` + +--- + +## Migration Status + +- **Planning Phase**: Module inventory completed +- **Next Steps**: Begin module consolidation +- **Target**: Standardized, reusable modules + +--- + +**Last Updated**: 2025-01-27 +**Status**: Planning Phase + diff --git a/terraform/examples/namespace-example/main.tf b/terraform/examples/namespace-example/main.tf new file mode 100644 index 0000000..7f24778 --- /dev/null +++ b/terraform/examples/namespace-example/main.tf @@ -0,0 +1,76 @@ +# Example: Using Kubernetes Namespace Module + +terraform { + required_version = ">= 1.0" + + required_providers { + kubernetes = { + source = "hashicorp/kubernetes" + version = "~> 2.0" + } + } +} + +provider "kubernetes" { + # Configure your Kubernetes provider + # config_path = "~/.kube/config" +} + +# Namespace Module +module "namespace" { + source = "../../modules/kubernetes/namespace" + + name = "my-app" + + labels = { + app = "my-app" + env = "production" + managed = "terraform" + team = "platform" + } + + annotations = { + description = "Namespace for my-app production environment" + } + + resource_quota = { + "requests.cpu" = "4" + "requests.memory" = "8Gi" + "limits.cpu" = "8" + "limits.memory" = "16Gi" + "persistentvolumeclaims" = "10" + "services.loadbalancers" = "2" + } + + limit_range = { + default = { + "cpu" = "500m" + "memory" = "1Gi" + } + default_request = { + "cpu" = "100m" + "memory" = "128Mi" + } + max = { + "cpu" = "2" + "memory" = "4Gi" + } + min = { + "cpu" = "50m" + "memory" = "64Mi" + } + max_limit_request_ratio = { + "cpu" = "4" + } + } +} + +# Outputs +output "namespace_name" { + value = module.namespace.namespace_name +} + +output "namespace_id" { + value = module.namespace.namespace_id +} + diff --git a/terraform/examples/networking-example/main.tf b/terraform/examples/networking-example/main.tf new file mode 100644 index 0000000..8ef1415 --- /dev/null +++ b/terraform/examples/networking-example/main.tf @@ -0,0 +1,96 @@ +# Example: Using Azure Networking Module + +terraform { + required_version = ">= 1.0" + + required_providers { + azurerm = { + source = "hashicorp/azurerm" + version = "~> 3.0" + } + } +} + +provider "azurerm" { + features {} +} + +# Resource Group +resource "azurerm_resource_group" "example" { + name = "rg-example" + location = "eastus" +} + +# Networking Module +module "networking" { + source = "../../modules/azure/networking" + + resource_group_name = azurerm_resource_group.example.name + location = azurerm_resource_group.example.location + vnet_name = "vnet-example" + address_space = ["10.0.0.0/16"] + + subnets = { + frontend = { + name = "snet-frontend" + address_prefixes = ["10.0.1.0/24"] + service_endpoints = ["Microsoft.Storage"] + } + backend = { + name = "snet-backend" + address_prefixes = ["10.0.2.0/24"] + service_endpoints = [] + } + database = { + name = "snet-database" + address_prefixes = ["10.0.3.0/24"] + service_endpoints = ["Microsoft.Sql"] + } + } + + network_security_groups = { + frontend_nsg = { + name = "nsg-frontend" + subnet_key = "frontend" + security_rules = [ + { + name = "AllowHTTP" + priority = 100 + direction = "Inbound" + access = "Allow" + protocol = "Tcp" + source_port_range = "*" + destination_port_range = "80" + source_address_prefix = "*" + destination_address_prefix = "*" + }, + { + name = "AllowHTTPS" + priority = 110 + direction = "Inbound" + access = "Allow" + protocol = "Tcp" + source_port_range = "*" + destination_port_range = "443" + source_address_prefix = "*" + destination_address_prefix = "*" + } + ] + } + } + + tags = { + Environment = "example" + ManagedBy = "Terraform" + } +} + +# Outputs +output "vnet_id" { + value = module.networking.vnet_id +} + +output "subnet_ids" { + value = module.networking.subnet_ids +} + diff --git a/terraform/modules/README.md b/terraform/modules/README.md new file mode 100644 index 0000000..197c43e --- /dev/null +++ b/terraform/modules/README.md @@ -0,0 +1,156 @@ +# Shared Terraform Modules + +**Purpose**: Reusable Terraform modules for infrastructure provisioning +**Last Updated**: 2025-01-27 + +--- + +## Overview + +This directory contains shared Terraform modules that can be used across all projects to ensure consistency and reduce duplication. + +--- + +## Module Structure + +``` +modules/ +β”œβ”€β”€ azure/ # Azure-specific modules +β”‚ β”œβ”€β”€ networking/ # Virtual networks, subnets, NSGs +β”‚ β”œβ”€β”€ kubernetes/ # AKS clusters +β”‚ β”œβ”€β”€ keyvault/ # Key Vault with RBAC +β”‚ β”œβ”€β”€ storage/ # Storage accounts +β”‚ └── monitoring/ # Monitoring resources +β”œβ”€β”€ kubernetes/ # Kubernetes modules (multi-cloud) +β”‚ β”œβ”€β”€ namespace/ # Namespace creation +β”‚ β”œβ”€β”€ ingress/ # Ingress configuration +β”‚ └── service/ # Service configuration +└── monitoring/ # Monitoring modules + β”œβ”€β”€ prometheus/ # Prometheus deployment + β”œβ”€β”€ grafana/ # Grafana deployment + └── loki/ # Loki deployment +``` + +--- + +## Usage + +### Example: Using Azure Networking Module + +```hcl +module "networking" { + source = "../../modules/azure/networking" + + resource_group_name = "rg-example" + location = "eastus" + vnet_name = "vnet-example" + address_space = ["10.0.0.0/16"] + + subnets = [ + { + name = "subnet-1" + address_prefix = "10.0.1.0/24" + } + ] +} +``` + +### Example: Using Kubernetes Namespace Module + +```hcl +module "namespace" { + source = "../../modules/kubernetes/namespace" + + name = "example-namespace" + labels = { + environment = "production" + project = "example" + } + annotations = {} +} +``` + +--- + +## Module Development Guidelines + +### 1. Standard Structure + +Each module should follow this structure: + +``` +module-name/ +β”œβ”€β”€ main.tf # Main resources +β”œβ”€β”€ variables.tf # Input variables +β”œβ”€β”€ outputs.tf # Output values +β”œβ”€β”€ README.md # Module documentation +└── versions.tf # Provider versions +``` + +### 2. Documentation + +Each module must include: +- Purpose and use cases +- Input variables documentation +- Output values documentation +- Usage examples +- Requirements + +### 3. Versioning + +- Use semantic versioning (v1.0.0, v1.1.0, etc.) +- Tag releases in git +- Document breaking changes + +--- + +## Available Modules + +### Azure Modules + +#### networking +**Purpose**: Create virtual networks, subnets, and network security groups +**Status**: 🚧 Planned + +#### kubernetes +**Purpose**: Deploy AKS clusters +**Status**: 🚧 Planned + +#### keyvault +**Purpose**: Create Key Vault with RBAC +**Status**: 🚧 Planned + +#### storage +**Purpose**: Create storage accounts and containers +**Status**: 🚧 Planned + +### Kubernetes Modules + +#### namespace +**Purpose**: Create Kubernetes namespaces +**Status**: 🚧 Planned + +#### ingress +**Purpose**: Configure ingress controllers +**Status**: 🚧 Planned + +### Monitoring Modules + +#### prometheus +**Purpose**: Deploy Prometheus +**Status**: 🚧 Planned + +#### grafana +**Purpose**: Deploy Grafana +**Status**: 🚧 Planned + +--- + +## Migration Plan + +See [TERRAFORM_MODULES_CONSOLIDATION.md](../../../docs/TERRAFORM_MODULES_CONSOLIDATION.md) for detailed migration plan. + +--- + +**Last Updated**: 2025-01-27 + diff --git a/terraform/modules/azure/keyvault/README.md b/terraform/modules/azure/keyvault/README.md new file mode 100644 index 0000000..bee2a75 --- /dev/null +++ b/terraform/modules/azure/keyvault/README.md @@ -0,0 +1,61 @@ +# Azure Key Vault Module + +**Purpose**: Create Azure Key Vault with RBAC +**Status**: 🚧 Planned + +--- + +## Usage + +```hcl +module "keyvault" { + source = "../../modules/azure/keyvault" + + resource_group_name = "rg-example" + location = "eastus" + keyvault_name = "kv-example" + + access_policies = [ + { + object_id = var.service_principal_id + key_permissions = ["Get", "List"] + secret_permissions = ["Get", "List"] + } + ] + + tags = { + Environment = "production" + } +} +``` + +--- + +## Inputs + +| Name | Description | Type | Default | Required | +|------|-------------|------|---------|----------| +| resource_group_name | Name of the resource group | string | - | yes | +| location | Azure region | string | - | yes | +| keyvault_name | Name of the Key Vault | string | - | yes | +| sku_name | SKU name (standard or premium) | string | "standard" | no | +| enabled_for_deployment | Enable for VM deployment | bool | false | no | +| enabled_for_disk_encryption | Enable for disk encryption | bool | false | no | +| enabled_for_template_deployment | Enable for template deployment | bool | false | no | +| access_policies | List of access policies | list(object) | [] | no | +| tags | Tags to apply | map(string) | {} | no | + +--- + +## Outputs + +| Name | Description | +|------|-------------| +| keyvault_id | Key Vault ID | +| keyvault_uri | Key Vault URI | +| keyvault_name | Key Vault name | + +--- + +**Status**: 🚧 Planned - Module structure ready, implementation pending + diff --git a/terraform/modules/azure/keyvault/main.tf b/terraform/modules/azure/keyvault/main.tf new file mode 100644 index 0000000..79d1a75 --- /dev/null +++ b/terraform/modules/azure/keyvault/main.tf @@ -0,0 +1,61 @@ +# Azure Key Vault Module +# Main resources + +terraform { + required_providers { + azurerm = { + source = "hashicorp/azurerm" + version = "~> 3.0" + } + } +} + +# Key Vault +resource "azurerm_key_vault" "main" { + name = var.keyvault_name + location = var.location + resource_group_name = var.resource_group_name + tenant_id = var.tenant_id + sku_name = var.sku_name + + enabled_for_deployment = var.enabled_for_deployment + enabled_for_disk_encryption = var.enabled_for_disk_encryption + enabled_for_template_deployment = var.enabled_for_template_deployment + + network_acls { + default_action = var.network_acls.default_action + bypass = var.network_acls.bypass + ip_rules = var.network_acls.ip_rules + virtual_network_subnet_ids = var.network_acls.virtual_network_subnet_ids + } + + tags = var.tags + + lifecycle { + create_before_destroy = true + } +} + +# Access Policies +resource "azurerm_key_vault_access_policy" "policies" { + for_each = { for idx, policy in var.access_policies : idx => policy } + + key_vault_id = azurerm_key_vault.main.id + tenant_id = var.tenant_id + object_id = each.value.object_id + + key_permissions = each.value.key_permissions + secret_permissions = each.value.secret_permissions + certificate_permissions = each.value.certificate_permissions + storage_permissions = each.value.storage_permissions +} + +# RBAC (if enabled) +resource "azurerm_role_assignment" "rbac" { + for_each = var.enable_rbac ? var.rbac_assignments : {} + + scope = azurerm_key_vault.main.id + role_definition_name = each.value.role_definition_name + principal_id = each.value.principal_id +} + diff --git a/terraform/modules/azure/keyvault/outputs.tf b/terraform/modules/azure/keyvault/outputs.tf new file mode 100644 index 0000000..aedd23d --- /dev/null +++ b/terraform/modules/azure/keyvault/outputs.tf @@ -0,0 +1,17 @@ +# Azure Key Vault Module Outputs + +output "keyvault_id" { + description = "Key Vault ID" + value = azurerm_key_vault.main.id +} + +output "keyvault_uri" { + description = "Key Vault URI" + value = azurerm_key_vault.main.vault_uri +} + +output "keyvault_name" { + description = "Key Vault name" + value = azurerm_key_vault.main.name +} + diff --git a/terraform/modules/azure/keyvault/variables.tf b/terraform/modules/azure/keyvault/variables.tf new file mode 100644 index 0000000..ee1323c --- /dev/null +++ b/terraform/modules/azure/keyvault/variables.tf @@ -0,0 +1,95 @@ +# Azure Key Vault Module Variables + +variable "resource_group_name" { + description = "Name of the resource group" + type = string +} + +variable "location" { + description = "Azure region" + type = string +} + +variable "keyvault_name" { + description = "Name of the Key Vault" + type = string +} + +variable "tenant_id" { + description = "Azure tenant ID" + type = string +} + +variable "sku_name" { + description = "SKU name (standard or premium)" + type = string + default = "standard" +} + +variable "enabled_for_deployment" { + description = "Enable for VM deployment" + type = bool + default = false +} + +variable "enabled_for_disk_encryption" { + description = "Enable for disk encryption" + type = bool + default = false +} + +variable "enabled_for_template_deployment" { + description = "Enable for template deployment" + type = bool + default = false +} + +variable "network_acls" { + description = "Network ACLs configuration" + type = object({ + default_action = string + bypass = string + ip_rules = list(string) + virtual_network_subnet_ids = list(string) + }) + default = { + default_action = "Deny" + bypass = "AzureServices" + ip_rules = [] + virtual_network_subnet_ids = [] + } +} + +variable "access_policies" { + description = "List of access policies" + type = list(object({ + object_id = string + key_permissions = list(string) + secret_permissions = list(string) + certificate_permissions = list(string) + storage_permissions = list(string) + })) + default = [] +} + +variable "enable_rbac" { + description = "Enable RBAC for Key Vault" + type = bool + default = false +} + +variable "rbac_assignments" { + description = "RBAC role assignments" + type = map(object({ + role_definition_name = string + principal_id = string + })) + default = {} +} + +variable "tags" { + description = "Tags to apply to resources" + type = map(string) + default = {} +} + diff --git a/terraform/modules/azure/keyvault/versions.tf b/terraform/modules/azure/keyvault/versions.tf new file mode 100644 index 0000000..bba0e7e --- /dev/null +++ b/terraform/modules/azure/keyvault/versions.tf @@ -0,0 +1,13 @@ +# Azure Key Vault Module - Provider Versions + +terraform { + required_version = ">= 1.0" + + required_providers { + azurerm = { + source = "hashicorp/azurerm" + version = "~> 3.0" + } + } +} + diff --git a/terraform/modules/azure/networking/README.md b/terraform/modules/azure/networking/README.md new file mode 100644 index 0000000..eca998b --- /dev/null +++ b/terraform/modules/azure/networking/README.md @@ -0,0 +1,86 @@ +# Azure Networking Module + +**Purpose**: Create Azure Virtual Network with subnets and network security groups +**Status**: βœ… Complete + +--- + +## Usage + +```hcl +module "networking" { + source = "../../modules/azure/networking" + + resource_group_name = "rg-example" + location = "eastus" + vnet_name = "vnet-example" + address_space = ["10.0.0.0/16"] + + subnets = { + frontend = { + name = "snet-frontend" + address_prefixes = ["10.0.1.0/24"] + service_endpoints = ["Microsoft.Storage"] + } + backend = { + name = "snet-backend" + address_prefixes = ["10.0.2.0/24"] + service_endpoints = [] + } + } + + network_security_groups = { + frontend_nsg = { + name = "nsg-frontend" + subnet_key = "frontend" + security_rules = [ + { + name = "AllowHTTP" + priority = 100 + direction = "Inbound" + access = "Allow" + protocol = "Tcp" + source_port_range = "*" + destination_port_range = "80" + source_address_prefix = "*" + destination_address_prefix = "*" + } + ] + } + } + + tags = { + Environment = "production" + } +} +``` + +--- + +## Inputs + +| Name | Description | Type | Default | Required | +|------|-------------|------|---------|----------| +| resource_group_name | Name of the resource group | string | - | yes | +| location | Azure region | string | - | yes | +| vnet_name | Name of the virtual network | string | - | yes | +| address_space | Address space for the virtual network | list(string) | - | yes | +| subnets | Map of subnets to create | map(object) | {} | no | +| network_security_groups | Map of network security groups | map(object) | {} | no | +| tags | Tags to apply | map(string) | {} | no | + +--- + +## Outputs + +| Name | Description | +|------|-------------| +| vnet_id | Virtual network ID | +| vnet_name | Virtual network name | +| subnet_ids | Map of subnet names to IDs | +| subnet_names | Map of subnet names | +| nsg_ids | Map of NSG names to IDs | + +--- + +**Status**: βœ… Complete - Ready for use diff --git a/terraform/modules/azure/networking/main.tf b/terraform/modules/azure/networking/main.tf new file mode 100644 index 0000000..1428d5d --- /dev/null +++ b/terraform/modules/azure/networking/main.tf @@ -0,0 +1,73 @@ +# Azure Networking Module +# Main resources + +terraform { + required_providers { + azurerm = { + source = "hashicorp/azurerm" + version = "~> 3.0" + } + } +} + +# Virtual Network +resource "azurerm_virtual_network" "main" { + name = var.vnet_name + address_space = var.address_space + location = var.location + resource_group_name = var.resource_group_name + tags = var.tags + + lifecycle { + create_before_destroy = true + } +} + +# Subnets +resource "azurerm_subnet" "subnets" { + for_each = var.subnets + + name = each.value.name + resource_group_name = var.resource_group_name + virtual_network_name = azurerm_virtual_network.main.name + address_prefixes = each.value.address_prefixes + service_endpoints = each.value.service_endpoints + + lifecycle { + create_before_destroy = true + } +} + +# Network Security Groups +resource "azurerm_network_security_group" "nsgs" { + for_each = var.network_security_groups + + name = each.value.name + location = var.location + resource_group_name = var.resource_group_name + tags = var.tags + + dynamic "security_rule" { + for_each = each.value.security_rules + content { + name = security_rule.value.name + priority = security_rule.value.priority + direction = security_rule.value.direction + access = security_rule.value.access + protocol = security_rule.value.protocol + source_port_range = security_rule.value.source_port_range + destination_port_range = security_rule.value.destination_port_range + source_address_prefix = security_rule.value.source_address_prefix + destination_address_prefix = security_rule.value.destination_address_prefix + } + } +} + +# Associate NSGs with subnets +resource "azurerm_subnet_network_security_group_association" "nsg_associations" { + for_each = var.network_security_groups + + subnet_id = azurerm_subnet.subnets[each.value.subnet_key].id + network_security_group_id = azurerm_network_security_group.nsgs[each.key].id +} + diff --git a/terraform/modules/azure/networking/outputs.tf b/terraform/modules/azure/networking/outputs.tf new file mode 100644 index 0000000..c407f18 --- /dev/null +++ b/terraform/modules/azure/networking/outputs.tf @@ -0,0 +1,27 @@ +# Azure Networking Module Outputs + +output "vnet_id" { + description = "Virtual network ID" + value = azurerm_virtual_network.main.id +} + +output "vnet_name" { + description = "Virtual network name" + value = azurerm_virtual_network.main.name +} + +output "subnet_ids" { + description = "Map of subnet names to IDs" + value = { for k, v in azurerm_subnet.subnets : k => v.id } +} + +output "subnet_names" { + description = "Map of subnet names" + value = { for k, v in azurerm_subnet.subnets : k => v.name } +} + +output "nsg_ids" { + description = "Map of NSG names to IDs" + value = { for k, v in azurerm_network_security_group.nsgs : k => v.id } +} + diff --git a/terraform/modules/azure/networking/variables.tf b/terraform/modules/azure/networking/variables.tf new file mode 100644 index 0000000..a8411ed --- /dev/null +++ b/terraform/modules/azure/networking/variables.tf @@ -0,0 +1,58 @@ +# Azure Networking Module Variables + +variable "resource_group_name" { + description = "Name of the resource group" + type = string +} + +variable "location" { + description = "Azure region" + type = string +} + +variable "vnet_name" { + description = "Name of the virtual network" + type = string +} + +variable "address_space" { + description = "Address space for the virtual network" + type = list(string) +} + +variable "subnets" { + description = "Map of subnets to create" + type = map(object({ + name = string + address_prefixes = list(string) + service_endpoints = list(string) + })) + default = {} +} + +variable "network_security_groups" { + description = "Map of network security groups to create" + type = map(object({ + name = string + subnet_key = string + security_rules = list(object({ + name = string + priority = number + direction = string + access = string + protocol = string + source_port_range = string + destination_port_range = string + source_address_prefix = string + destination_address_prefix = string + })) + })) + default = {} +} + +variable "tags" { + description = "Tags to apply to resources" + type = map(string) + default = {} +} + diff --git a/terraform/modules/azure/networking/versions.tf b/terraform/modules/azure/networking/versions.tf new file mode 100644 index 0000000..7141f85 --- /dev/null +++ b/terraform/modules/azure/networking/versions.tf @@ -0,0 +1,13 @@ +# Azure Networking Module - Provider Versions + +terraform { + required_version = ">= 1.0" + + required_providers { + azurerm = { + source = "hashicorp/azurerm" + version = "~> 3.0" + } + } +} + diff --git a/terraform/modules/azure/storage/README.md b/terraform/modules/azure/storage/README.md new file mode 100644 index 0000000..3521102 --- /dev/null +++ b/terraform/modules/azure/storage/README.md @@ -0,0 +1,58 @@ +# Azure Storage Module + +**Purpose**: Create storage accounts and containers +**Status**: 🚧 Planned + +--- + +## Usage + +```hcl +module "storage" { + source = "../../modules/azure/storage" + + resource_group_name = "rg-example" + location = "eastus" + storage_account_name = "stexample" + + containers = [ + { + name = "container1" + access_type = "private" + } + ] + + tags = { + Environment = "production" + } +} +``` + +--- + +## Inputs + +| Name | Description | Type | Default | Required | +|------|-------------|------|---------|----------| +| resource_group_name | Name of the resource group | string | - | yes | +| location | Azure region | string | - | yes | +| storage_account_name | Name of the storage account | string | - | yes | +| account_tier | Storage account tier | string | "Standard" | no | +| account_replication_type | Replication type | string | "LRS" | no | +| containers | List of containers to create | list(object) | [] | no | +| tags | Tags to apply | map(string) | {} | no | + +--- + +## Outputs + +| Name | Description | +|------|-------------| +| storage_account_id | Storage account ID | +| storage_account_name | Storage account name | +| primary_connection_string | Primary connection string (sensitive) | + +--- + +**Status**: 🚧 Planned - Module structure ready, implementation pending + diff --git a/terraform/modules/azure/storage/main.tf b/terraform/modules/azure/storage/main.tf new file mode 100644 index 0000000..40f3b94 --- /dev/null +++ b/terraform/modules/azure/storage/main.tf @@ -0,0 +1,81 @@ +# Azure Storage Module +# Main resources + +terraform { + required_providers { + azurerm = { + source = "hashicorp/azurerm" + version = "~> 3.0" + } + } +} + +# Storage Account +resource "azurerm_storage_account" "main" { + name = var.storage_account_name + resource_group_name = var.resource_group_name + location = var.location + account_tier = var.account_tier + account_replication_type = var.account_replication_type + account_kind = var.account_kind + + enable_https_traffic_only = var.enable_https_traffic_only + min_tls_version = var.min_tls_version + + blob_properties { + delete_retention_policy { + days = var.blob_delete_retention_days + } + container_delete_retention_policy { + days = var.container_delete_retention_days + } + } + + network_rules { + default_action = var.network_rules.default_action + bypass = var.network_rules.bypass + ip_rules = var.network_rules.ip_rules + virtual_network_subnet_ids = var.network_rules.virtual_network_subnet_ids + } + + tags = var.tags + + lifecycle { + create_before_destroy = true + } +} + +# Containers +resource "azurerm_storage_container" "containers" { + for_each = var.containers + + name = each.value.name + storage_account_name = azurerm_storage_account.main.name + container_access_type = each.value.access_type +} + +# File Shares +resource "azurerm_storage_share" "shares" { + for_each = var.file_shares + + name = each.value.name + storage_account_name = azurerm_storage_account.main.name + quota = each.value.quota +} + +# Queues +resource "azurerm_storage_queue" "queues" { + for_each = var.queues + + name = each.value.name + storage_account_name = azurerm_storage_account.main.name +} + +# Tables +resource "azurerm_storage_table" "tables" { + for_each = var.tables + + name = each.value.name + storage_account_name = azurerm_storage_account.main.name +} + diff --git a/terraform/modules/azure/storage/outputs.tf b/terraform/modules/azure/storage/outputs.tf new file mode 100644 index 0000000..4fcf12f --- /dev/null +++ b/terraform/modules/azure/storage/outputs.tf @@ -0,0 +1,34 @@ +# Azure Storage Module Outputs + +output "storage_account_id" { + description = "Storage account ID" + value = azurerm_storage_account.main.id +} + +output "storage_account_name" { + description = "Storage account name" + value = azurerm_storage_account.main.name +} + +output "primary_connection_string" { + description = "Primary connection string (sensitive)" + value = azurerm_storage_account.main.primary_connection_string + sensitive = true +} + +output "primary_access_key" { + description = "Primary access key (sensitive)" + value = azurerm_storage_account.main.primary_access_key + sensitive = true +} + +output "primary_blob_endpoint" { + description = "Primary blob endpoint" + value = azurerm_storage_account.main.primary_blob_endpoint +} + +output "container_names" { + description = "Map of container names" + value = { for k, v in azurerm_storage_container.containers : k => v.name } +} + diff --git a/terraform/modules/azure/storage/variables.tf b/terraform/modules/azure/storage/variables.tf new file mode 100644 index 0000000..ecadce2 --- /dev/null +++ b/terraform/modules/azure/storage/variables.tf @@ -0,0 +1,115 @@ +# Azure Storage Module Variables + +variable "resource_group_name" { + description = "Name of the resource group" + type = string +} + +variable "location" { + description = "Azure region" + type = string +} + +variable "storage_account_name" { + description = "Name of the storage account" + type = string +} + +variable "account_tier" { + description = "Storage account tier (Standard or Premium)" + type = string + default = "Standard" +} + +variable "account_replication_type" { + description = "Replication type (LRS, GRS, RAGRS, ZRS)" + type = string + default = "LRS" +} + +variable "account_kind" { + description = "Account kind (StorageV2, BlobStorage, etc.)" + type = string + default = "StorageV2" +} + +variable "enable_https_traffic_only" { + description = "Enable HTTPS traffic only" + type = bool + default = true +} + +variable "min_tls_version" { + description = "Minimum TLS version" + type = string + default = "TLS1_2" +} + +variable "blob_delete_retention_days" { + description = "Blob delete retention days" + type = number + default = 7 +} + +variable "container_delete_retention_days" { + description = "Container delete retention days" + type = number + default = 7 +} + +variable "network_rules" { + description = "Network rules configuration" + type = object({ + default_action = string + bypass = list(string) + ip_rules = list(string) + virtual_network_subnet_ids = list(string) + }) + default = { + default_action = "Allow" + bypass = ["AzureServices"] + ip_rules = [] + virtual_network_subnet_ids = [] + } +} + +variable "containers" { + description = "Map of containers to create" + type = map(object({ + name = string + access_type = string + })) + default = {} +} + +variable "file_shares" { + description = "Map of file shares to create" + type = map(object({ + name = string + quota = number + })) + default = {} +} + +variable "queues" { + description = "Map of queues to create" + type = map(object({ + name = string + })) + default = {} +} + +variable "tables" { + description = "Map of tables to create" + type = map(object({ + name = string + })) + default = {} +} + +variable "tags" { + description = "Tags to apply to resources" + type = map(string) + default = {} +} + diff --git a/terraform/modules/azure/storage/versions.tf b/terraform/modules/azure/storage/versions.tf new file mode 100644 index 0000000..d7063a9 --- /dev/null +++ b/terraform/modules/azure/storage/versions.tf @@ -0,0 +1,13 @@ +# Azure Storage Module - Provider Versions + +terraform { + required_version = ">= 1.0" + + required_providers { + azurerm = { + source = "hashicorp/azurerm" + version = "~> 3.0" + } + } +} + diff --git a/terraform/modules/kubernetes/namespace/README.md b/terraform/modules/kubernetes/namespace/README.md new file mode 100644 index 0000000..bcacf48 --- /dev/null +++ b/terraform/modules/kubernetes/namespace/README.md @@ -0,0 +1,81 @@ +# Kubernetes Namespace Module + +**Purpose**: Create Kubernetes namespace with resource quotas and limit ranges +**Status**: βœ… Complete + +--- + +## Usage + +```hcl +module "namespace" { + source = "../../modules/kubernetes/namespace" + + name = "my-app" + + labels = { + app = "my-app" + env = "production" + managed = "terraform" + } + + annotations = { + description = "Namespace for my-app" + } + + resource_quota = { + "requests.cpu" = "4" + "requests.memory" = "8Gi" + "limits.cpu" = "8" + "limits.memory" = "16Gi" + } + + limit_range = { + default = { + "cpu" = "500m" + "memory" = "1Gi" + } + default_request = { + "cpu" = "100m" + "memory" = "128Mi" + } + max = { + "cpu" = "2" + "memory" = "4Gi" + } + min = { + "cpu" = "50m" + "memory" = "64Mi" + } + max_limit_request_ratio = { + "cpu" = "4" + } + } +} +``` + +--- + +## Inputs + +| Name | Description | Type | Default | Required | +|------|-------------|------|---------|----------| +| name | Namespace name | string | - | yes | +| labels | Labels to apply | map(string) | {} | no | +| annotations | Annotations to apply | map(string) | {} | no | +| resource_quota | Resource quota limits | map(string) | {} | no | +| limit_range | Limit range configuration | object | {} | no | + +--- + +## Outputs + +| Name | Description | +|------|-------------| +| namespace_name | Namespace name | +| namespace_id | Namespace UID | +| resource_quota_id | Resource quota ID (if created) | + +--- + +**Status**: βœ… Complete - Ready for use diff --git a/terraform/modules/kubernetes/namespace/main.tf b/terraform/modules/kubernetes/namespace/main.tf new file mode 100644 index 0000000..f1ca1ac --- /dev/null +++ b/terraform/modules/kubernetes/namespace/main.tf @@ -0,0 +1,55 @@ +# Kubernetes Namespace Module +# Main resources + +terraform { + required_providers { + kubernetes = { + source = "hashicorp/kubernetes" + version = "~> 2.0" + } + } +} + +# Namespace +resource "kubernetes_namespace" "main" { + metadata { + name = var.name + labels = var.labels + annotations = var.annotations + } +} + +# Resource Quota (if specified) +resource "kubernetes_resource_quota" "quota" { + count = length(var.resource_quota) > 0 ? 1 : 0 + + metadata { + name = "${var.name}-quota" + namespace = kubernetes_namespace.main.metadata[0].name + } + + spec { + hard = var.resource_quota + } +} + +# Limit Range (if specified) +resource "kubernetes_limit_range" "limits" { + count = length(var.limit_range) > 0 ? 1 : 0 + + metadata { + name = "${var.name}-limits" + namespace = kubernetes_namespace.main.metadata[0].name + } + + spec { + limit { + default = var.limit_range.default + default_request = var.limit_range.default_request + max = var.limit_range.max + min = var.limit_range.min + max_limit_request_ratio = var.limit_range.max_limit_request_ratio + } + } +} + diff --git a/terraform/modules/kubernetes/namespace/outputs.tf b/terraform/modules/kubernetes/namespace/outputs.tf new file mode 100644 index 0000000..0c5a18c --- /dev/null +++ b/terraform/modules/kubernetes/namespace/outputs.tf @@ -0,0 +1,17 @@ +# Kubernetes Namespace Module Outputs + +output "namespace_name" { + description = "Namespace name" + value = kubernetes_namespace.main.metadata[0].name +} + +output "namespace_id" { + description = "Namespace UID" + value = kubernetes_namespace.main.metadata[0].uid +} + +output "resource_quota_id" { + description = "Resource quota ID (if created)" + value = length(kubernetes_resource_quota.quota) > 0 ? kubernetes_resource_quota.quota[0].metadata[0].uid : null +} + diff --git a/terraform/modules/kubernetes/namespace/variables.tf b/terraform/modules/kubernetes/namespace/variables.tf new file mode 100644 index 0000000..64fca16 --- /dev/null +++ b/terraform/modules/kubernetes/namespace/variables.tf @@ -0,0 +1,43 @@ +# Kubernetes Namespace Module Variables + +variable "name" { + description = "Namespace name" + type = string +} + +variable "labels" { + description = "Labels to apply to namespace" + type = map(string) + default = {} +} + +variable "annotations" { + description = "Annotations to apply to namespace" + type = map(string) + default = {} +} + +variable "resource_quota" { + description = "Resource quota limits" + type = map(string) + default = {} +} + +variable "limit_range" { + description = "Limit range configuration" + type = object({ + default = map(string) + default_request = map(string) + max = map(string) + min = map(string) + max_limit_request_ratio = map(string) + }) + default = { + default = {} + default_request = {} + max = {} + min = {} + max_limit_request_ratio = {} + } +} + diff --git a/terraform/modules/kubernetes/namespace/versions.tf b/terraform/modules/kubernetes/namespace/versions.tf new file mode 100644 index 0000000..857094e --- /dev/null +++ b/terraform/modules/kubernetes/namespace/versions.tf @@ -0,0 +1,13 @@ +# Kubernetes Namespace Module - Provider Versions + +terraform { + required_version = ">= 1.0" + + required_providers { + kubernetes = { + source = "hashicorp/kubernetes" + version = "~> 2.0" + } + } +} +