mirror of
https://github.com/BagelHole/DevOps-Security-Agent-Skills.git
synced 2026-08-22 12:49:53 +02:00
V2
This commit is contained in:
@@ -9,50 +9,489 @@ metadata:
|
||||
|
||||
# Azure SQL
|
||||
|
||||
Deploy managed databases on Azure.
|
||||
Deploy and manage Azure SQL Database, Elastic Pools, and Cosmos DB. Covers server provisioning, firewall rules, geo-replication, backup strategies, performance tuning, security hardening, and Terraform configurations.
|
||||
|
||||
## Create SQL Database
|
||||
## When to Use
|
||||
|
||||
- You need a fully managed relational database on Azure.
|
||||
- Your application requires geo-replication for disaster recovery.
|
||||
- You need elastic scaling across multiple databases with Elastic Pools.
|
||||
- You are migrating on-premises SQL Server workloads to the cloud.
|
||||
- You need a globally distributed NoSQL database (Cosmos DB).
|
||||
|
||||
## Prerequisites
|
||||
|
||||
```bash
|
||||
# Create server
|
||||
az sql server create \
|
||||
--name myserver \
|
||||
--resource-group mygroup \
|
||||
--admin-user sqladmin \
|
||||
--admin-password SecureP@ss123
|
||||
# Install Azure CLI
|
||||
curl -sL https://aka.ms/InstallAzureCLIDeb | sudo bash
|
||||
|
||||
# Create database
|
||||
az sql db create \
|
||||
--resource-group mygroup \
|
||||
--server myserver \
|
||||
--name mydb \
|
||||
--service-objective S1
|
||||
# Login and set subscription
|
||||
az login
|
||||
az account set --subscription "my-subscription-id"
|
||||
|
||||
# Create resource group
|
||||
az group create --name database-rg --location eastus
|
||||
```
|
||||
|
||||
## Firewall Rules
|
||||
## SQL Server and Database Creation
|
||||
|
||||
### Create SQL Server
|
||||
|
||||
```bash
|
||||
# Create logical SQL server
|
||||
az sql server create \
|
||||
--resource-group database-rg \
|
||||
--name myapp-sqlserver \
|
||||
--location eastus \
|
||||
--admin-user sqladmin \
|
||||
--admin-password 'S3cur3P@ssw0rd!' \
|
||||
--enable-public-network false \
|
||||
--minimal-tls-version 1.2
|
||||
|
||||
# Enable Azure AD authentication
|
||||
az sql server ad-admin create \
|
||||
--resource-group database-rg \
|
||||
--server-name myapp-sqlserver \
|
||||
--display-name "SQL Admins" \
|
||||
--object-id "{aad-group-object-id}"
|
||||
|
||||
# Enable Azure AD only authentication (disable SQL auth)
|
||||
az sql server ad-only-auth enable \
|
||||
--resource-group database-rg \
|
||||
--name myapp-sqlserver
|
||||
```
|
||||
|
||||
### Create Databases
|
||||
|
||||
```bash
|
||||
# Create General Purpose database
|
||||
az sql db create \
|
||||
--resource-group database-rg \
|
||||
--server myapp-sqlserver \
|
||||
--name myapp-db \
|
||||
--edition GeneralPurpose \
|
||||
--compute-model Serverless \
|
||||
--auto-pause-delay 60 \
|
||||
--min-capacity 0.5 \
|
||||
--max-size 32GB \
|
||||
--backup-storage-redundancy Geo \
|
||||
--zone-redundant false
|
||||
|
||||
# Create Business Critical database for production
|
||||
az sql db create \
|
||||
--resource-group database-rg \
|
||||
--server myapp-sqlserver \
|
||||
--name myapp-prod-db \
|
||||
--edition BusinessCritical \
|
||||
--service-objective BC_Gen5_4 \
|
||||
--max-size 256GB \
|
||||
--backup-storage-redundancy Geo \
|
||||
--zone-redundant true \
|
||||
--read-scale Enabled
|
||||
|
||||
# Create Hyperscale database for large workloads
|
||||
az sql db create \
|
||||
--resource-group database-rg \
|
||||
--server myapp-sqlserver \
|
||||
--name myapp-analytics-db \
|
||||
--edition Hyperscale \
|
||||
--service-objective HS_Gen5_4 \
|
||||
--ha-replicas 2
|
||||
|
||||
# List databases on server
|
||||
az sql db list \
|
||||
--resource-group database-rg \
|
||||
--server myapp-sqlserver \
|
||||
--output table
|
||||
```
|
||||
|
||||
### Elastic Pools
|
||||
|
||||
```bash
|
||||
# Create elastic pool
|
||||
az sql elastic-pool create \
|
||||
--resource-group database-rg \
|
||||
--server myapp-sqlserver \
|
||||
--name myapp-pool \
|
||||
--edition GeneralPurpose \
|
||||
--capacity 4 \
|
||||
--db-max-capacity 2 \
|
||||
--db-min-capacity 0.25 \
|
||||
--max-size 256GB \
|
||||
--zone-redundant false
|
||||
|
||||
# Move database into elastic pool
|
||||
az sql db update \
|
||||
--resource-group database-rg \
|
||||
--server myapp-sqlserver \
|
||||
--name myapp-db \
|
||||
--elastic-pool myapp-pool
|
||||
|
||||
# Monitor elastic pool usage
|
||||
az sql elastic-pool list-dbs \
|
||||
--resource-group database-rg \
|
||||
--server myapp-sqlserver \
|
||||
--name myapp-pool \
|
||||
--output table
|
||||
```
|
||||
|
||||
## Firewall Rules and Network Security
|
||||
|
||||
```bash
|
||||
# Allow Azure services
|
||||
az sql server firewall-rule create \
|
||||
--resource-group mygroup \
|
||||
--server myserver \
|
||||
--name AllowAzure \
|
||||
--resource-group database-rg \
|
||||
--server myapp-sqlserver \
|
||||
--name AllowAzureServices \
|
||||
--start-ip-address 0.0.0.0 \
|
||||
--end-ip-address 0.0.0.0
|
||||
|
||||
# Allow specific IP range (office network)
|
||||
az sql server firewall-rule create \
|
||||
--resource-group database-rg \
|
||||
--server myapp-sqlserver \
|
||||
--name AllowOffice \
|
||||
--start-ip-address 203.0.113.0 \
|
||||
--end-ip-address 203.0.113.255
|
||||
|
||||
# Allow your current client IP
|
||||
az sql server firewall-rule create \
|
||||
--resource-group database-rg \
|
||||
--server myapp-sqlserver \
|
||||
--name AllowMyIP \
|
||||
--start-ip-address "$(curl -s ifconfig.me)" \
|
||||
--end-ip-address "$(curl -s ifconfig.me)"
|
||||
|
||||
# Create VNet rule for subnet access
|
||||
az sql server vnet-rule create \
|
||||
--resource-group database-rg \
|
||||
--server myapp-sqlserver \
|
||||
--name AllowAppSubnet \
|
||||
--vnet-name spoke-prod-vnet \
|
||||
--subnet app-subnet
|
||||
|
||||
# List firewall rules
|
||||
az sql server firewall-rule list \
|
||||
--resource-group database-rg \
|
||||
--server myapp-sqlserver \
|
||||
--output table
|
||||
|
||||
# Remove a firewall rule
|
||||
az sql server firewall-rule delete \
|
||||
--resource-group database-rg \
|
||||
--server myapp-sqlserver \
|
||||
--name AllowMyIP
|
||||
```
|
||||
|
||||
## Geo-Replication and Failover
|
||||
|
||||
```bash
|
||||
# Create failover group with secondary server
|
||||
az sql server create \
|
||||
--resource-group database-rg \
|
||||
--name myapp-sqlserver-secondary \
|
||||
--location westus \
|
||||
--admin-user sqladmin \
|
||||
--admin-password 'S3cur3P@ssw0rd!'
|
||||
|
||||
az sql failover-group create \
|
||||
--resource-group database-rg \
|
||||
--server myapp-sqlserver \
|
||||
--name myapp-failover-group \
|
||||
--partner-server myapp-sqlserver-secondary \
|
||||
--partner-resource-group database-rg \
|
||||
--failover-policy Automatic \
|
||||
--grace-period 1 \
|
||||
--add-db myapp-prod-db
|
||||
|
||||
# Check failover group status
|
||||
az sql failover-group show \
|
||||
--resource-group database-rg \
|
||||
--server myapp-sqlserver \
|
||||
--name myapp-failover-group \
|
||||
--output table
|
||||
|
||||
# Manual failover (for testing or planned maintenance)
|
||||
az sql failover-group set-primary \
|
||||
--resource-group database-rg \
|
||||
--server myapp-sqlserver-secondary \
|
||||
--name myapp-failover-group
|
||||
|
||||
# Create active geo-replication (without failover group)
|
||||
az sql db replica create \
|
||||
--resource-group database-rg \
|
||||
--server myapp-sqlserver \
|
||||
--name myapp-db \
|
||||
--partner-server myapp-sqlserver-secondary \
|
||||
--partner-resource-group database-rg
|
||||
```
|
||||
|
||||
## Backup and Restore
|
||||
|
||||
```bash
|
||||
# Configure short-term retention (1-35 days)
|
||||
az sql db str-policy set \
|
||||
--resource-group database-rg \
|
||||
--server myapp-sqlserver \
|
||||
--name myapp-prod-db \
|
||||
--retention-days 14 \
|
||||
--diffbackup-hours 12
|
||||
|
||||
# Configure long-term retention
|
||||
az sql db ltr-policy set \
|
||||
--resource-group database-rg \
|
||||
--server myapp-sqlserver \
|
||||
--name myapp-prod-db \
|
||||
--weekly-retention P4W \
|
||||
--monthly-retention P12M \
|
||||
--yearly-retention P5Y \
|
||||
--week-of-year 1
|
||||
|
||||
# Restore database to a point in time
|
||||
az sql db restore \
|
||||
--resource-group database-rg \
|
||||
--server myapp-sqlserver \
|
||||
--name myapp-db-restored \
|
||||
--dest-name myapp-db-restored \
|
||||
--time "2026-03-23T10:00:00Z"
|
||||
|
||||
# Restore from long-term backup
|
||||
az sql db ltr-backup list \
|
||||
--resource-group database-rg \
|
||||
--server myapp-sqlserver \
|
||||
--database myapp-prod-db \
|
||||
--output table
|
||||
|
||||
# Export database to bacpac
|
||||
az sql db export \
|
||||
--resource-group database-rg \
|
||||
--server myapp-sqlserver \
|
||||
--name myapp-db \
|
||||
--admin-user sqladmin \
|
||||
--admin-password 'S3cur3P@ssw0rd!' \
|
||||
--storage-key-type StorageAccessKey \
|
||||
--storage-key "{storage-account-key}" \
|
||||
--storage-uri "https://mystorageacct.blob.core.windows.net/backups/myapp-db.bacpac"
|
||||
```
|
||||
|
||||
## Performance Tuning
|
||||
|
||||
```bash
|
||||
# Enable automatic tuning
|
||||
az sql db update \
|
||||
--resource-group database-rg \
|
||||
--server myapp-sqlserver \
|
||||
--name myapp-prod-db \
|
||||
--set tags.autoTuning=enabled
|
||||
|
||||
# Check database performance recommendations
|
||||
az sql db advisor list \
|
||||
--resource-group database-rg \
|
||||
--server myapp-sqlserver \
|
||||
--database myapp-prod-db \
|
||||
--output table
|
||||
|
||||
# Scale database tier
|
||||
az sql db update \
|
||||
--resource-group database-rg \
|
||||
--server myapp-sqlserver \
|
||||
--name myapp-prod-db \
|
||||
--service-objective BC_Gen5_8
|
||||
|
||||
# Enable Query Store (via SQL)
|
||||
# sqlcmd -S myapp-sqlserver.database.windows.net -d myapp-prod-db -Q "ALTER DATABASE [myapp-prod-db] SET QUERY_STORE = ON"
|
||||
|
||||
# View DTU/vCore usage metrics
|
||||
az monitor metrics list \
|
||||
--resource "/subscriptions/{sub}/resourceGroups/database-rg/providers/Microsoft.Sql/servers/myapp-sqlserver/databases/myapp-prod-db" \
|
||||
--metric "cpu_percent" "dtu_consumption_percent" "storage_percent" \
|
||||
--interval PT1H \
|
||||
--output table
|
||||
```
|
||||
|
||||
## Security Hardening
|
||||
|
||||
```bash
|
||||
# Enable Advanced Threat Protection
|
||||
az sql db threat-policy update \
|
||||
--resource-group database-rg \
|
||||
--server myapp-sqlserver \
|
||||
--name myapp-prod-db \
|
||||
--state Enabled \
|
||||
--email-addresses security@example.com \
|
||||
--email-account-admins true
|
||||
|
||||
# Enable auditing to storage
|
||||
az sql server audit-policy update \
|
||||
--resource-group database-rg \
|
||||
--name myapp-sqlserver \
|
||||
--state Enabled \
|
||||
--storage-account mystorageacct \
|
||||
--retention-days 90
|
||||
|
||||
# Enable auditing to Log Analytics
|
||||
az sql server audit-policy update \
|
||||
--resource-group database-rg \
|
||||
--name myapp-sqlserver \
|
||||
--state Enabled \
|
||||
--lats Enabled \
|
||||
--lawri "/subscriptions/{sub}/resourceGroups/{rg}/providers/Microsoft.OperationalInsights/workspaces/{workspace}"
|
||||
|
||||
# Enable Transparent Data Encryption (enabled by default)
|
||||
az sql db tde set \
|
||||
--resource-group database-rg \
|
||||
--server myapp-sqlserver \
|
||||
--database myapp-prod-db \
|
||||
--status Enabled
|
||||
|
||||
# Enable vulnerability assessment
|
||||
az sql vm update \
|
||||
--resource-group database-rg \
|
||||
--name myapp-sqlserver
|
||||
```
|
||||
|
||||
## Cosmos DB
|
||||
|
||||
```bash
|
||||
# Create Cosmos DB account with SQL API
|
||||
az cosmosdb create \
|
||||
--name mycosmosdb \
|
||||
--resource-group mygroup \
|
||||
--default-consistency-level Session
|
||||
--resource-group database-rg \
|
||||
--name myapp-cosmos \
|
||||
--default-consistency-level Session \
|
||||
--locations regionName=eastus failoverPriority=0 isZoneRedundant=true \
|
||||
--locations regionName=westus failoverPriority=1 isZoneRedundant=false \
|
||||
--enable-automatic-failover true \
|
||||
--enable-multiple-write-locations false
|
||||
|
||||
# Create database
|
||||
az cosmosdb sql database create \
|
||||
--resource-group database-rg \
|
||||
--account-name myapp-cosmos \
|
||||
--name myappdb \
|
||||
--throughput 400
|
||||
|
||||
# Create container with partition key
|
||||
az cosmosdb sql container create \
|
||||
--resource-group database-rg \
|
||||
--account-name myapp-cosmos \
|
||||
--database-name myappdb \
|
||||
--name orders \
|
||||
--partition-key-path "/customerId" \
|
||||
--throughput 400 \
|
||||
--idx @indexing-policy.json
|
||||
|
||||
# Enable autoscale throughput
|
||||
az cosmosdb sql container throughput update \
|
||||
--resource-group database-rg \
|
||||
--account-name myapp-cosmos \
|
||||
--database-name myappdb \
|
||||
--name orders \
|
||||
--max-throughput 4000
|
||||
```
|
||||
|
||||
## Best Practices
|
||||
## Terraform Configuration
|
||||
|
||||
- Enable transparent data encryption
|
||||
- Use Azure AD authentication
|
||||
- Implement geo-replication
|
||||
- Configure automated backups
|
||||
- Use private endpoints
|
||||
```hcl
|
||||
resource "azurerm_mssql_server" "main" {
|
||||
name = "myapp-sqlserver"
|
||||
resource_group_name = azurerm_resource_group.main.name
|
||||
location = azurerm_resource_group.main.location
|
||||
version = "12.0"
|
||||
administrator_login = "sqladmin"
|
||||
administrator_login_password = var.sql_admin_password
|
||||
minimum_tls_version = "1.2"
|
||||
public_network_access_enabled = false
|
||||
|
||||
azuread_administrator {
|
||||
login_username = "SQL Admins"
|
||||
object_id = var.sql_admin_aad_group_id
|
||||
}
|
||||
|
||||
tags = var.tags
|
||||
}
|
||||
|
||||
resource "azurerm_mssql_database" "main" {
|
||||
name = "myapp-prod-db"
|
||||
server_id = azurerm_mssql_server.main.id
|
||||
collation = "SQL_Latin1_General_CP1_CI_AS"
|
||||
license_type = "LicenseIncluded"
|
||||
sku_name = "BC_Gen5_4"
|
||||
max_size_gb = 256
|
||||
zone_redundant = true
|
||||
read_scale = true
|
||||
|
||||
short_term_retention_policy {
|
||||
retention_days = 14
|
||||
backup_interval_in_hours = 12
|
||||
}
|
||||
|
||||
long_term_retention_policy {
|
||||
weekly_retention = "P4W"
|
||||
monthly_retention = "P12M"
|
||||
yearly_retention = "P5Y"
|
||||
week_of_year = 1
|
||||
}
|
||||
|
||||
threat_detection_policy {
|
||||
state = "Enabled"
|
||||
email_addresses = ["security@example.com"]
|
||||
email_account_admins = "Enabled"
|
||||
retention_days = 90
|
||||
storage_endpoint = azurerm_storage_account.audit.primary_blob_endpoint
|
||||
storage_account_access_key = azurerm_storage_account.audit.primary_access_key
|
||||
}
|
||||
|
||||
tags = var.tags
|
||||
}
|
||||
|
||||
resource "azurerm_mssql_failover_group" "main" {
|
||||
name = "myapp-failover-group"
|
||||
server_id = azurerm_mssql_server.main.id
|
||||
databases = [azurerm_mssql_database.main.id]
|
||||
|
||||
partner_server {
|
||||
id = azurerm_mssql_server.secondary.id
|
||||
}
|
||||
|
||||
read_write_endpoint_failover_policy {
|
||||
mode = "Automatic"
|
||||
grace_minutes = 60
|
||||
}
|
||||
|
||||
tags = var.tags
|
||||
}
|
||||
|
||||
resource "azurerm_private_endpoint" "sql" {
|
||||
name = "sql-private-endpoint"
|
||||
location = azurerm_resource_group.main.location
|
||||
resource_group_name = azurerm_resource_group.main.name
|
||||
subnet_id = azurerm_subnet.data.id
|
||||
|
||||
private_service_connection {
|
||||
name = "sql-connection"
|
||||
private_connection_resource_id = azurerm_mssql_server.main.id
|
||||
subresource_names = ["sqlServer"]
|
||||
is_manual_connection = false
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
## Troubleshooting
|
||||
|
||||
| Symptom | Cause | Fix |
|
||||
|---------|-------|-----|
|
||||
| Cannot connect to SQL server | Firewall rule missing or public access disabled | Add client IP with `az sql server firewall-rule create` or use private endpoint |
|
||||
| Login failed for user | Incorrect credentials or Azure AD not configured | Verify admin credentials; enable Azure AD auth on the server |
|
||||
| Database DTU at 100% | Under-provisioned tier or inefficient queries | Scale up service objective; review Query Store for expensive queries |
|
||||
| Geo-replication lag is high | Large transaction volumes or network latency | Monitor with `sys.dm_geo_replication_link_status`; consider Hyperscale |
|
||||
| Point-in-time restore fails | Requested time is outside retention window | Check retention policy; use long-term backups for older data |
|
||||
| Elastic pool running out of eDTUs | Too many active databases in pool | Increase pool capacity or move heavy databases to dedicated tier |
|
||||
| TDE key rotation failure | Key Vault access policy missing | Grant SQL server managed identity GET, WRAP, UNWRAP permissions |
|
||||
| Connection timeout from app | Network path blocked or DNS issue | Use `az network watcher test-connectivity`; verify private DNS resolution |
|
||||
|
||||
## Related Skills
|
||||
|
||||
- `azure-networking` -- Private endpoints and VNet rules for SQL access.
|
||||
- `azure-functions` -- SQL bindings for serverless data access.
|
||||
- `terraform-azure` -- Terraform-based SQL infrastructure provisioning.
|
||||
- `arm-templates` -- Bicep templates for SQL deployments.
|
||||
|
||||
Reference in New Issue
Block a user