├── modules └── databases_users │ ├── terraform.tfvars.ci │ ├── versions.tf │ ├── versions.tofu │ ├── providers.tf │ ├── outputs.tf │ ├── variables.tf │ ├── r-users.tf │ └── README.md ├── .github ├── ISSUE_TEMPLATE │ ├── config.yml │ ├── Documentation.yml │ ├── Feature_Request.yml │ └── Bug_Report.yml ├── CODEOWNERS ├── workflows │ └── github-ci.yml └── pull_request_template.md ├── versions.tf ├── versions.tofu ├── .gitlab └── merge_request_templates │ └── default.md ├── .gitignore ├── .tool-versions ├── locals-tags.tf ├── renovate.json ├── .gitlab-ci.yml ├── locals-naming.tf ├── committed.toml ├── providers.tf ├── examples ├── main │ ├── variables.tf │ ├── versions.tf │ ├── base.tf │ └── modules.tf └── databases_users │ ├── variables.tf │ ├── versions.tf │ ├── base.tf │ └── modules.tf ├── NOTICE ├── variables-tags.tf ├── variables-naming.tf ├── terraform.tfvars.ci ├── variables-logs.tf ├── d-naming.tf ├── r-users.tf ├── m-logs.tf ├── .config ├── tflint.hcl └── terraform-docs.yml ├── .pre-commit-config.yaml ├── locals.tf ├── variables-security.tf ├── r-security.tf ├── outputs.tf ├── r-sql.tf ├── .releaserc ├── CONTRIBUTING.md ├── r-db.tf ├── variables.tf ├── LICENSE ├── CHANGELOG.md └── README.md /modules/databases_users/terraform.tfvars.ci: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/config.yml: -------------------------------------------------------------------------------- 1 | blank_issues_enabled: false 2 | -------------------------------------------------------------------------------- /versions.tf: -------------------------------------------------------------------------------- 1 | terraform { 2 | required_version = ">= 1.3" 3 | } 4 | -------------------------------------------------------------------------------- /versions.tofu: -------------------------------------------------------------------------------- 1 | terraform { 2 | required_version = ">= 1.8" 3 | } 4 | -------------------------------------------------------------------------------- /.github/CODEOWNERS: -------------------------------------------------------------------------------- 1 | * @bzspi @shr3ps @rossifumax @jmapro @maxpoullain 2 | -------------------------------------------------------------------------------- /.gitlab/merge_request_templates/default.md: -------------------------------------------------------------------------------- 1 | @ldap-sync/FR-Git-Cellule-CLD_SRE_AZURE_1 2 | -------------------------------------------------------------------------------- /modules/databases_users/versions.tf: -------------------------------------------------------------------------------- 1 | terraform { 2 | required_version = ">= 1.3" 3 | } 4 | -------------------------------------------------------------------------------- /modules/databases_users/versions.tofu: -------------------------------------------------------------------------------- 1 | terraform { 2 | required_version = ">= 1.8" 3 | } 4 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | .terraform 2 | .terraform.lock.hcl 3 | main.tf 4 | terraform.tfvars 5 | !examples/**/main.tf 6 | !examples/**/terraform.tfvars 7 | -------------------------------------------------------------------------------- /.tool-versions: -------------------------------------------------------------------------------- 1 | pre-commit 4.5.1 2 | opentofu 1.11.1 3 | terraform-docs 0.21.0 4 | tflint 0.60.0 5 | trivy 0.68.2 6 | -------------------------------------------------------------------------------- /locals-tags.tf: -------------------------------------------------------------------------------- 1 | locals { 2 | default_tags = var.default_tags_enabled ? { 3 | env = var.environment 4 | stack = var.stack 5 | } : {} 6 | } 7 | -------------------------------------------------------------------------------- /.github/workflows/github-ci.yml: -------------------------------------------------------------------------------- 1 | name: CI 2 | on: [push, pull_request] 3 | jobs: 4 | ci: 5 | uses: claranet/terraform-modules-ci/.github/workflows/ci-modules.yaml@main 6 | -------------------------------------------------------------------------------- /renovate.json: -------------------------------------------------------------------------------- 1 | { 2 | "$schema": "https://docs.renovatebot.com/renovate-schema.json", 3 | "extends": [ 4 | "local>claranet/projects/cloud/azure/renovatebot-config:automerge" 5 | ] 6 | } 7 | -------------------------------------------------------------------------------- /.gitlab-ci.yml: -------------------------------------------------------------------------------- 1 | --- 2 | variables: 3 | TF_MIN_VERSION: "1.8" 4 | AZURERM_PROVIDER_MIN_VERSION: "4.31" 5 | 6 | include: 7 | - project: 'claranet/projects/cloud/azure/terraform/ci' 8 | ref: master 9 | file: '/pipeline.yml' 10 | ... 11 | -------------------------------------------------------------------------------- /modules/databases_users/providers.tf: -------------------------------------------------------------------------------- 1 | terraform { 2 | required_providers { 3 | random = { 4 | source = "hashicorp/random" 5 | version = ">= 3.4.3" 6 | } 7 | mssql = { 8 | source = "betr-io/mssql" 9 | version = "~> 0.3.0" 10 | } 11 | } 12 | } 13 | -------------------------------------------------------------------------------- /locals-naming.tf: -------------------------------------------------------------------------------- 1 | locals { 2 | # Naming locals/constants 3 | name_prefix = lower(var.name_prefix) 4 | name_suffix = lower(var.name_suffix) 5 | 6 | name = coalesce(var.server_custom_name, data.azurecaf_name.sql.result) 7 | elastic_pool_name = coalesce(var.elastic_pool_custom_name, data.azurecaf_name.sql_pool.result) 8 | } 9 | -------------------------------------------------------------------------------- /committed.toml: -------------------------------------------------------------------------------- 1 | allowed_types = [ 2 | "build", 3 | "chore", 4 | "ci", 5 | "docs", 6 | "feat", 7 | "fix", 8 | "perf", 9 | "refactor", 10 | "revert", 11 | "style", 12 | "test", 13 | ] 14 | line_length = 100 15 | merge_commit = true 16 | style = "conventional" 17 | subject_capitalized = false 18 | subject_length = 96 19 | -------------------------------------------------------------------------------- /modules/databases_users/outputs.tf: -------------------------------------------------------------------------------- 1 | output "name" { 2 | description = "Name of the custom user." 3 | value = var.user_name 4 | } 5 | 6 | output "password" { 7 | description = "Password of the custom user." 8 | value = random_password.main.result 9 | sensitive = true 10 | } 11 | 12 | output "roles" { 13 | description = "Roles of the custom user." 14 | value = var.user_roles 15 | } 16 | -------------------------------------------------------------------------------- /providers.tf: -------------------------------------------------------------------------------- 1 | terraform { 2 | required_providers { 3 | azurerm = { 4 | source = "hashicorp/azurerm" 5 | version = "~> 4.31" 6 | } 7 | azurecaf = { 8 | source = "claranet/azurecaf" 9 | version = ">= 1.2.28" 10 | } 11 | # tflint-ignore: terraform_unused_required_providers 12 | mssql = { 13 | source = "betr-io/mssql" 14 | version = "~> 0.3.0" 15 | } 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /examples/main/variables.tf: -------------------------------------------------------------------------------- 1 | variable "azure_region" { 2 | description = "Azure region to use." 3 | type = string 4 | } 5 | 6 | variable "client_name" { 7 | description = "Client name/account used in naming." 8 | type = string 9 | } 10 | 11 | variable "environment" { 12 | description = "Project environment." 13 | type = string 14 | } 15 | 16 | variable "stack" { 17 | description = "Project stack name." 18 | type = string 19 | } 20 | -------------------------------------------------------------------------------- /examples/databases_users/variables.tf: -------------------------------------------------------------------------------- 1 | variable "azure_region" { 2 | description = "Azure region to use." 3 | type = string 4 | } 5 | 6 | variable "client_name" { 7 | description = "Client name/account used in naming." 8 | type = string 9 | } 10 | 11 | variable "environment" { 12 | description = "Project environment." 13 | type = string 14 | } 15 | 16 | variable "stack" { 17 | description = "Project stack name." 18 | type = string 19 | } 20 | -------------------------------------------------------------------------------- /.github/pull_request_template.md: -------------------------------------------------------------------------------- 1 | Fixes #(issue) . 2 | 3 | ## Type of change 4 | 5 | - [ ] Bug fix (non-breaking change which fixes an issue) 6 | - [ ] New feature (non-breaking change which adds functionality) 7 | - [ ] Breaking change (fix or feature that would cause existing functionality to not work as expected) 8 | - [ ] This change requires a documentation update 9 | 10 | ## Changes proposed in this pull request 11 | 12 | - 13 | - 14 | - 15 | 16 | @claranet/fr-azure-reviewers 17 | -------------------------------------------------------------------------------- /examples/main/versions.tf: -------------------------------------------------------------------------------- 1 | terraform { 2 | required_version = ">= 1.8" 3 | required_providers { 4 | azurerm = { 5 | source = "hashicorp/azurerm" 6 | version = "~> 4.0" 7 | } 8 | mssql = { 9 | source = "betr-io/mssql" 10 | version = ">= 0.2.5" 11 | } 12 | random = { 13 | source = "hashicorp/random" 14 | version = ">= 3.4.3" 15 | } 16 | } 17 | } 18 | 19 | provider "azurerm" { 20 | features {} 21 | } 22 | 23 | provider "mssql" { 24 | # Configuration options 25 | } 26 | -------------------------------------------------------------------------------- /examples/databases_users/versions.tf: -------------------------------------------------------------------------------- 1 | terraform { 2 | required_version = ">= 1.8" 3 | required_providers { 4 | azurerm = { 5 | source = "hashicorp/azurerm" 6 | version = "~> 4.0" 7 | } 8 | mssql = { 9 | source = "betr-io/mssql" 10 | version = ">= 0.2.5" 11 | } 12 | random = { 13 | source = "hashicorp/random" 14 | version = ">= 3.4.3" 15 | } 16 | } 17 | } 18 | 19 | provider "azurerm" { 20 | features {} 21 | } 22 | 23 | provider "mssql" { 24 | # Configuration options 25 | } 26 | -------------------------------------------------------------------------------- /NOTICE: -------------------------------------------------------------------------------- 1 | Copyright (c) 2018-2023 Claranet 2 | 3 | Licensed under the Apache License, Version 2.0 (the "License"); 4 | you may not use this file except in compliance with the License. 5 | You may obtain a copy of the License at 6 | 7 | http://www.apache.org/licenses/LICENSE-2.0 8 | 9 | Unless required by applicable law or agreed to in writing, software 10 | distributed under the License is distributed on an "AS IS" BASIS, 11 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | See the License for the specific language governing permissions and 13 | limitations under the License. 14 | -------------------------------------------------------------------------------- /variables-tags.tf: -------------------------------------------------------------------------------- 1 | variable "default_tags_enabled" { 2 | description = "Option to enable or disable default tags." 3 | type = bool 4 | default = true 5 | } 6 | 7 | variable "extra_tags" { 8 | description = "Extra tags to add." 9 | type = map(string) 10 | default = {} 11 | } 12 | 13 | variable "server_extra_tags" { 14 | description = "Extra tags to add on SQL Server or ElasticPool." 15 | type = map(string) 16 | default = {} 17 | } 18 | 19 | variable "elastic_pool_extra_tags" { 20 | description = "Extra tags to add on ElasticPool." 21 | type = map(string) 22 | default = {} 23 | } 24 | -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/Documentation.yml: -------------------------------------------------------------------------------- 1 | name: Documentation 2 | description: Additions, improvement or patch about documentation 3 | title: "[DOC] ..." 4 | labels: [documentation, enhancement] 5 | body: 6 | - type: textarea 7 | id: description 8 | attributes: 9 | label: Description 10 | description: Please leave a helpful description. 11 | value: | 12 | **Explain what part of documentation is missing or not enough** 13 | Like I don't understand how to do this, or it miss context for that.. 14 | 15 | **Give us some suggestions** 16 | Here are some suggestions or, even better, here is a pull request. 17 | -------------------------------------------------------------------------------- /modules/databases_users/variables.tf: -------------------------------------------------------------------------------- 1 | variable "database_name" { 2 | description = "Name of the database where the custom user should be created." 3 | type = string 4 | } 5 | 6 | variable "user_name" { 7 | description = "Name of the custom user." 8 | type = string 9 | } 10 | 11 | variable "user_roles" { 12 | description = "List of databases roles for the custom user." 13 | type = list(string) 14 | } 15 | 16 | variable "administrator_login" { 17 | description = "Login for the SQL Server administrator." 18 | type = string 19 | } 20 | 21 | variable "administrator_password" { 22 | description = "Password for the SQL Server administrator." 23 | type = string 24 | } 25 | 26 | variable "sql_server_hostname" { 27 | description = "FQDN of the SQL Server." 28 | type = string 29 | } 30 | -------------------------------------------------------------------------------- /examples/main/base.tf: -------------------------------------------------------------------------------- 1 | module "azure_region" { 2 | source = "claranet/regions/azurerm" 3 | version = "x.x.x" 4 | 5 | azure_region = var.azure_region 6 | } 7 | 8 | module "rg" { 9 | source = "claranet/rg/azurerm" 10 | version = "x.x.x" 11 | 12 | location = module.azure_region.location 13 | location_short = module.azure_region.location_short 14 | client_name = var.client_name 15 | environment = var.environment 16 | stack = var.stack 17 | } 18 | 19 | module "logs" { 20 | source = "claranet/run/azurerm//modules/logs" 21 | version = "x.x.x" 22 | 23 | location = module.azure_region.location 24 | location_short = module.azure_region.location_short 25 | client_name = var.client_name 26 | environment = var.environment 27 | stack = var.stack 28 | 29 | resource_group_name = module.rg.name 30 | } 31 | -------------------------------------------------------------------------------- /examples/databases_users/base.tf: -------------------------------------------------------------------------------- 1 | module "azure_region" { 2 | source = "claranet/regions/azurerm" 3 | version = "x.x.x" 4 | 5 | azure_region = var.azure_region 6 | } 7 | 8 | module "rg" { 9 | source = "claranet/rg/azurerm" 10 | version = "x.x.x" 11 | 12 | location = module.azure_region.location 13 | location_short = module.azure_region.location_short 14 | client_name = var.client_name 15 | environment = var.environment 16 | stack = var.stack 17 | } 18 | 19 | module "logs" { 20 | source = "claranet/run/azurerm//modules/logs" 21 | version = "x.x.x" 22 | 23 | location = module.azure_region.location 24 | location_short = module.azure_region.location_short 25 | client_name = var.client_name 26 | environment = var.environment 27 | stack = var.stack 28 | 29 | resource_group_name = module.rg.name 30 | } 31 | -------------------------------------------------------------------------------- /variables-naming.tf: -------------------------------------------------------------------------------- 1 | # Generic naming variables 2 | variable "name_prefix" { 3 | description = "Optional prefix for the generated name." 4 | type = string 5 | default = "" 6 | } 7 | 8 | variable "name_suffix" { 9 | description = "Optional suffix for the generated name." 10 | type = string 11 | default = "" 12 | } 13 | 14 | # Custom naming override 15 | variable "server_custom_name" { 16 | description = "Name of the SQL Server, generated if not set." 17 | type = string 18 | default = "" 19 | } 20 | 21 | variable "elastic_pool_custom_name" { 22 | description = "Name of the SQL Elastic Pool, generated if not set." 23 | type = string 24 | default = "" 25 | } 26 | 27 | variable "use_caf_naming_for_databases" { 28 | description = "Use the Azure CAF naming provider to generate databases names." 29 | type = bool 30 | default = false 31 | } 32 | -------------------------------------------------------------------------------- /terraform.tfvars.ci: -------------------------------------------------------------------------------- 1 | location = "fr-central" 2 | location_short = "frc" 3 | client_name = "test" 4 | environment = "test" 5 | stack = "ci" 6 | resource_group_name = "rg-test" 7 | databases_names = ["users", "documents"] 8 | sku = { 9 | tier = "Standard" 10 | capacity = "100" 11 | } 12 | elastic_pool_max_size = "50" 13 | administrator_login = "claranet" 14 | administrator_password = "claranet" 15 | logs_destinations_ids = [ 16 | "/subscriptions/aaaaaaaa-bbbb-cccc-dddd-eeeeeeeeeeee/resourceGroups/rg-test/providers/Microsoft.Storage/storageAccounts/storageaccountname", 17 | "/subscriptions/aaaaaaaa-bbbb-cccc-dddd-eeeeeeeeeeee/resourceGroups/rg-test/providers/Microsoft.OperationalInsights/workspaces/my-log-analytics-workspace", 18 | ] 19 | enable_advanced_data_security = "true" 20 | enable_advanced_data_security_admin_emails = "true" 21 | advanced_data_security_additional_emails = ["admin@fr.clara.net", "devops@fr.clara.net"] 22 | -------------------------------------------------------------------------------- /variables-logs.tf: -------------------------------------------------------------------------------- 1 | # Diag settings / logs parameters 2 | 3 | variable "logs_destinations_ids" { 4 | type = list(string) 5 | nullable = false 6 | description = <| character. 10 | EOD 11 | } 12 | 13 | variable "logs_categories" { 14 | type = list(string) 15 | description = "Log categories to send to destinations." 16 | default = null 17 | } 18 | 19 | variable "logs_metrics_categories" { 20 | type = list(string) 21 | description = "Metrics categories to send to destinations." 22 | default = null 23 | } 24 | 25 | variable "diagnostic_settings_custom_name" { 26 | description = "Custom name of the diagnostics settings, name will be `default` if not set." 27 | type = string 28 | default = "default" 29 | } 30 | -------------------------------------------------------------------------------- /d-naming.tf: -------------------------------------------------------------------------------- 1 | data "azurecaf_name" "sql" { 2 | name = var.stack 3 | resource_type = "azurerm_mssql_server" 4 | prefixes = var.name_prefix == "" ? null : [local.name_prefix] 5 | suffixes = compact([var.client_name, var.location_short, var.environment, local.name_suffix]) 6 | use_slug = true 7 | clean_input = true 8 | separator = "-" 9 | } 10 | 11 | data "azurecaf_name" "sql_pool" { 12 | name = var.stack 13 | resource_type = "azurerm_mssql_elasticpool" 14 | prefixes = var.name_prefix == "" ? null : [local.name_prefix] 15 | suffixes = compact([var.client_name, var.location_short, var.environment, local.name_suffix]) 16 | use_slug = true 17 | clean_input = true 18 | separator = "-" 19 | } 20 | 21 | data "azurecaf_name" "sql_dbs" { 22 | for_each = try({ for database in var.databases : database.name => database }, {}) 23 | 24 | name = var.stack 25 | resource_type = "azurerm_mssql_database" 26 | prefixes = var.name_prefix == "" ? null : [local.name_prefix] 27 | suffixes = compact([var.client_name, var.location_short, var.environment, local.name_suffix, each.key]) 28 | use_slug = true 29 | clean_input = true 30 | separator = "-" 31 | } 32 | -------------------------------------------------------------------------------- /r-users.tf: -------------------------------------------------------------------------------- 1 | module "databases_users" { 2 | for_each = try({ for user in local.databases_users : format("%s-%s", user.username, user.database) => user }, {}) 3 | 4 | source = "./modules/databases_users" 5 | 6 | depends_on = [ 7 | azurerm_mssql_database.main 8 | ] 9 | 10 | administrator_login = var.administrator_login 11 | administrator_password = var.administrator_password 12 | 13 | sql_server_hostname = azurerm_mssql_server.main.fully_qualified_domain_name 14 | 15 | database_name = each.value.database 16 | user_name = each.value.username 17 | user_roles = each.value.roles 18 | } 19 | 20 | module "custom_users" { 21 | for_each = try({ for custom_user in var.custom_users : format("%s-%s", custom_user.name, custom_user.database) => custom_user }, {}) 22 | 23 | source = "./modules/databases_users" 24 | 25 | depends_on = [ 26 | azurerm_mssql_database.main 27 | ] 28 | 29 | administrator_login = var.administrator_login 30 | administrator_password = var.administrator_password 31 | 32 | sql_server_hostname = azurerm_mssql_server.main.fully_qualified_domain_name 33 | 34 | database_name = azurerm_mssql_database.main[each.value.database].name 35 | user_name = each.value.name 36 | user_roles = each.value.roles 37 | } 38 | -------------------------------------------------------------------------------- /m-logs.tf: -------------------------------------------------------------------------------- 1 | module "pool_logging" { 2 | count = var.logs_destinations_ids != toset([]) && var.elastic_pool_enabled ? 1 : 0 3 | 4 | source = "claranet/diagnostic-settings/azurerm" 5 | version = "~> 8.2.0" 6 | 7 | resource_id = azurerm_mssql_elasticpool.main[0].id 8 | 9 | custom_name = var.diagnostic_settings_custom_name 10 | name_prefix = var.name_prefix 11 | name_suffix = var.name_suffix 12 | 13 | logs_destinations_ids = var.logs_destinations_ids 14 | log_categories = var.logs_categories 15 | metric_categories = var.logs_metrics_categories 16 | } 17 | 18 | module "databases_logging" { 19 | for_each = { for db in var.databases : db.name => db if var.logs_destinations_ids != toset([]) } 20 | 21 | source = "claranet/diagnostic-settings/azurerm" 22 | version = "~> 8.2.0" 23 | 24 | resource_id = azurerm_mssql_database.main[each.key].id 25 | 26 | custom_name = var.diagnostic_settings_custom_name 27 | name_prefix = var.name_prefix 28 | name_suffix = var.name_suffix 29 | 30 | logs_destinations_ids = var.logs_destinations_ids 31 | log_categories = var.logs_categories 32 | metric_categories = var.logs_metrics_categories 33 | } 34 | 35 | moved { 36 | from = module.single_db_logging 37 | to = module.databases_logging 38 | } 39 | -------------------------------------------------------------------------------- /modules/databases_users/r-users.tf: -------------------------------------------------------------------------------- 1 | resource "random_password" "main" { 2 | special = true 3 | override_special = "#$%&-_+{}<>:" 4 | upper = true 5 | lower = true 6 | numeric = true 7 | length = 32 8 | } 9 | 10 | resource "mssql_login" "main" { 11 | server { 12 | host = var.sql_server_hostname 13 | login { 14 | username = var.administrator_login 15 | password = var.administrator_password 16 | } 17 | } 18 | login_name = var.user_name 19 | password = random_password.main.result 20 | } 21 | 22 | resource "mssql_user" "main" { 23 | depends_on = [mssql_login.main] 24 | 25 | server { 26 | host = var.sql_server_hostname 27 | 28 | login { 29 | username = var.administrator_login 30 | password = var.administrator_password 31 | } 32 | } 33 | username = var.user_name 34 | login_name = var.user_name 35 | database = var.database_name 36 | roles = var.user_roles 37 | } 38 | 39 | moved { 40 | from = random_password.custom_user_password 41 | to = random_password.main 42 | } 43 | moved { 44 | from = mssql_login.custom_sql_login 45 | to = mssql_login.main 46 | } 47 | moved { 48 | from = mssql_user.custom_sql_user 49 | to = mssql_user.main 50 | } 51 | -------------------------------------------------------------------------------- /.config/tflint.hcl: -------------------------------------------------------------------------------- 1 | plugin "azurerm" { 2 | enabled = true 3 | source = "github.com/terraform-linters/tflint-ruleset-azurerm" 4 | version = "0.27.0" 5 | } 6 | 7 | config { 8 | call_module_type = "local" 9 | force = false 10 | disabled_by_default = false 11 | plugin_dir = "~/.tflint.d/plugins" 12 | 13 | varfile = ["terraform.tfvars.ci"] 14 | } 15 | 16 | rule "terraform_deprecated_interpolation" { 17 | enabled = true 18 | } 19 | 20 | rule "terraform_deprecated_index" { 21 | enabled = true 22 | } 23 | 24 | rule "terraform_unused_declarations" { 25 | enabled = true 26 | } 27 | 28 | rule "terraform_comment_syntax" { 29 | enabled = true 30 | } 31 | 32 | rule "terraform_documented_outputs" { 33 | enabled = true 34 | } 35 | 36 | rule "terraform_documented_variables" { 37 | enabled = true 38 | } 39 | 40 | rule "terraform_typed_variables" { 41 | enabled = true 42 | } 43 | 44 | rule "terraform_module_pinned_source" { 45 | enabled = true 46 | } 47 | 48 | # Disabled for examples code with unfixed version 49 | rule "terraform_module_version" { 50 | enabled = false 51 | exact = false # default 52 | } 53 | 54 | rule "terraform_naming_convention" { 55 | enabled = true 56 | } 57 | 58 | rule "terraform_required_version" { 59 | enabled = true 60 | } 61 | 62 | rule "terraform_required_providers" { 63 | enabled = true 64 | } 65 | 66 | rule "terraform_unused_required_providers" { 67 | enabled = true 68 | } 69 | 70 | # Disabled since we have files like "variables-xxxx.tf" instead of a single "variables.tf" 71 | rule "terraform_standard_module_structure" { 72 | enabled = false 73 | } 74 | -------------------------------------------------------------------------------- /examples/databases_users/modules.tf: -------------------------------------------------------------------------------- 1 | resource "random_password" "admin_password" { 2 | special = true 3 | override_special = "#$%&-_+{}<>:" 4 | upper = true 5 | lower = true 6 | number = true 7 | length = 32 8 | } 9 | 10 | module "sql_single" { 11 | source = "claranet/db-sql/azurerm" 12 | version = "x.x.x" 13 | 14 | client_name = var.client_name 15 | environment = var.environment 16 | location = module.azure_region.location 17 | location_short = module.azure_region.location_short 18 | stack = var.stack 19 | resource_group_name = module.rg.name 20 | 21 | administrator_login = "adminsqltest" 22 | administrator_password = random_password.admin_password.result 23 | create_databases_users = false 24 | 25 | elastic_pool_enabled = false 26 | 27 | logs_destinations_ids = [ 28 | module.logs.id, 29 | module.logs.storage_account_id, 30 | ] 31 | 32 | databases = [ 33 | { 34 | name = "db1" 35 | max_size_gb = 50 36 | }, 37 | ] 38 | } 39 | 40 | module "users" { 41 | for_each = { 42 | "app-db1" = { 43 | name = "app" 44 | database = "db1" 45 | roles = ["db_accessadmin", "db_securityadmin"] 46 | } 47 | } 48 | 49 | source = "claranet/db-sql/azurerm//modules/databases_users" 50 | version = "x.x.x" 51 | 52 | administrator_login = "adminsqltest" 53 | administrator_password = random_password.admin_password.result 54 | 55 | sql_server_hostname = module.sql_single.databases_resource["db1"].fully_qualified_domain_name 56 | 57 | database_name = each.value.database 58 | user_name = each.value.name 59 | user_roles = each.value.roles 60 | } 61 | -------------------------------------------------------------------------------- /.pre-commit-config.yaml: -------------------------------------------------------------------------------- 1 | default_install_hook_types: [commit-msg, pre-commit] 2 | repos: 3 | - repo: https://github.com/pre-commit/pre-commit-hooks 4 | rev: v6.0.0 5 | hooks: 6 | - id: trailing-whitespace 7 | stages: [pre-commit] 8 | - id: end-of-file-fixer 9 | stages: [pre-commit] 10 | - id: check-json 11 | stages: [pre-commit] 12 | - id: check-yaml 13 | stages: [pre-commit] 14 | args: 15 | - --unsafe 16 | - id: check-symlinks 17 | stages: [pre-commit] 18 | - id: check-added-large-files 19 | stages: [pre-commit] 20 | args: 21 | - --maxkb=15000 22 | - id: detect-private-key 23 | stages: [pre-commit] 24 | 25 | - repo: https://github.com/tofuutils/pre-commit-opentofu 26 | rev: v2.2.2 27 | hooks: 28 | - id: tofu_fmt 29 | stages: [pre-commit] 30 | - id: tofu_docs 31 | stages: [pre-commit] 32 | args: 33 | - --args=--config=.config/terraform-docs.yml 34 | exclude: "^modules|^example|^tools" 35 | - id: tofu_validate 36 | stages: [pre-commit] 37 | exclude: ^examples 38 | args: 39 | - --tf-init-args=-upgrade 40 | - --hook-config=--retry-once-with-cleanup=true 41 | - id: tofu_tflint 42 | stages: [pre-commit] 43 | exclude: ^examples 44 | args: 45 | - --args=--config=__GIT_WORKING_DIR__/.config/tflint.hcl 46 | - --env-vars=TFLINT_LOG="info" 47 | - id: tofu_trivy 48 | stages: [pre-commit] 49 | args: 50 | - --args=--severity HIGH,CRITICAL 51 | - --args=--skip-dirs '**/.terraform' 52 | 53 | - repo: https://github.com/crate-ci/committed 54 | rev: v1.1.8 55 | hooks: 56 | - id: committed 57 | stages: [commit-msg] 58 | -------------------------------------------------------------------------------- /locals.tf: -------------------------------------------------------------------------------- 1 | locals { 2 | vcore_tiers = { 3 | GeneralPurpose = "GP" 4 | BusinessCritical = "BC" 5 | Hyperscale = "HS" 6 | } 7 | elastic_pool_vcore_family = try(var.elastic_pool_sku.family, "Gen5") 8 | elastic_pool_vcore_sku_name = var.elastic_pool_sku != null ? format("%s_%s", local.vcore_tiers[var.elastic_pool_sku.tier], local.elastic_pool_vcore_family) : null 9 | elastic_pool_dtu_sku_name = var.elastic_pool_sku != null ? format("%sPool", var.elastic_pool_sku.tier) : null 10 | elastic_pool_sku = var.elastic_pool_sku != null ? { 11 | name = contains(keys(local.vcore_tiers), var.elastic_pool_sku.tier) ? local.elastic_pool_vcore_sku_name : local.elastic_pool_dtu_sku_name 12 | capacity = var.elastic_pool_sku.capacity 13 | tier = var.elastic_pool_sku.tier 14 | family = contains(keys(local.vcore_tiers), var.elastic_pool_sku.tier) ? local.elastic_pool_vcore_family : null 15 | } : null 16 | 17 | allowed_subnets = [ 18 | for id in var.allowed_subnets_ids : { 19 | name = split("/", id)[10] 20 | subnet_id = id 21 | } 22 | ] 23 | 24 | databases_users = var.create_databases_users ? [ 25 | for db in var.databases : { 26 | username = format("%s_user", replace(db.name, "-", "_")) 27 | database = db.name 28 | roles = ["db_owner"] 29 | } 30 | ] : [] 31 | 32 | standard_allowed_create_mode = { 33 | "a" = "Default" 34 | "b" = "Copy" 35 | "c" = "Secondary" 36 | "d" = "PointInTimeRestore" 37 | "e" = "Restore" 38 | "f" = "Recovery" 39 | "g" = "RestoreExternalBackup" 40 | "h" = "RestoreExternalBackup" 41 | "i" = "RestoreLongTermRetentionBackup" 42 | "j" = "OnlineSecondary" 43 | } 44 | 45 | datawarehouse_allowed_create_mode = { 46 | "a" = "Default" 47 | "b" = "PointInTimeRestore" 48 | "c" = "Restore" 49 | "d" = "Recovery" 50 | "e" = "RestoreExternalBackup" 51 | "f" = "RestoreExternalBackup" 52 | "g" = "OnlineSecondary" 53 | } 54 | } 55 | -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/Feature_Request.yml: -------------------------------------------------------------------------------- 1 | name: Feature Request 2 | description: I have a suggestion (and might want to implement myself)! 3 | title: "[FEAT] ..." 4 | labels: [feature, enhancement] 5 | body: 6 | - type: textarea 7 | id: community 8 | attributes: 9 | label: Community Note 10 | description: This note is for the community, please leave and skip this. 11 | value: | 12 | 13 | 14 | * Please vote on this issue by adding a :thumbsup: [reaction](https://blog.github.com/2016-03-10-add-reactions-to-pull-requests-issues-and-comments/) to the original issue to help the community and maintainers prioritize this request 15 | * Please do not leave "+1" or "me too" comments, they generate extra noise for issue followers and do not help prioritize the request 16 | * If you are interested in working on this issue or have submitted a pull request, please leave a comment 17 | 18 | 19 | validations: 20 | required: true 21 | - type: textarea 22 | id: description 23 | attributes: 24 | label: Description 25 | description: Please leave a helpful description of the feature request here. 26 | validations: 27 | required: true 28 | - type: input 29 | id: resource 30 | attributes: 31 | label: New or Affected Resource(s)/Data Source(s) 32 | description: Please list the new or affected resources and/or data sources. 33 | placeholder: azurerm_XXXXX 34 | validations: 35 | required: true 36 | - type: textarea 37 | id: config 38 | attributes: 39 | label: Potential OpenTofu Configuration 40 | description: Please provide an example of what the new resource or enhancement could look like in a OpenTofu/HCL config. 41 | render: hcl 42 | - type: textarea 43 | id: references 44 | attributes: 45 | label: References 46 | description: | 47 | Information about referencing Github Issues: https://help.github.com/articles/basic-writing-and-formatting-syntax/#referencing-issues-and-pull-requests 48 | -------------------------------------------------------------------------------- /variables-security.tf: -------------------------------------------------------------------------------- 1 | variable "alerting_email_addresses" { 2 | description = "List of email addresses to send reports for threat detection and vulnerability assessment." 3 | type = list(string) 4 | default = [] 5 | } 6 | 7 | variable "threat_detection_policy_enabled" { 8 | description = "True to enable thread detection policy on the databases." 9 | type = bool 10 | default = false 11 | } 12 | 13 | variable "threat_detection_policy_retention_days" { 14 | description = "Specifies the number of days to keep in the Threat Detection audit logs." 15 | type = number 16 | default = 7 17 | } 18 | 19 | variable "threat_detection_policy_disabled_alerts" { 20 | description = "Specifies a list of alerts which should be disabled. Possible values include `Access_Anomaly`, `Sql_Injection` and `Sql_Injection_Vulnerability`." 21 | type = list(string) 22 | default = [] 23 | } 24 | 25 | variable "express_vulnerability_assessment_enabled" { 26 | description = "True to enable express vulnerability assessment for this SQL Server." 27 | type = bool 28 | default = false 29 | } 30 | 31 | variable "sql_server_vulnerability_assessment_enabled" { 32 | description = "True to enable classic vulnerability assessment for this SQL Server." 33 | type = bool 34 | default = false 35 | } 36 | 37 | variable "databases_extended_auditing_enabled" { 38 | description = "True to enable extended auditing for SQL databases." 39 | type = bool 40 | default = false 41 | } 42 | 43 | variable "sql_server_extended_auditing_enabled" { 44 | description = "True to enable extended auditing for SQL Server." 45 | type = bool 46 | default = false 47 | } 48 | 49 | variable "sql_server_security_alerting_enabled" { 50 | description = "True to enable security alerting for this SQL Server." 51 | type = bool 52 | default = false 53 | } 54 | 55 | variable "sql_server_extended_auditing_retention_days" { 56 | description = "Server extended auditing logs retention." 57 | type = number 58 | default = 30 59 | } 60 | 61 | variable "databases_extended_auditing_retention_days" { 62 | description = "Databases extended auditing logs retention." 63 | type = number 64 | default = 30 65 | } 66 | -------------------------------------------------------------------------------- /.config/terraform-docs.yml: -------------------------------------------------------------------------------- 1 | --- 2 | # This file is automatically maintained within this module repository -- DO NOT EDIT 3 | formatter: "markdown" 4 | 5 | settings: 6 | anchor: false 7 | lockfile: false 8 | 9 | output: 10 | file: "README.md" 11 | 12 | sections: 13 | hide: [requirements] 14 | 15 | content: |- 16 | ## Global versioning rule for Claranet Azure modules 17 | 18 | | Module version | Terraform version | OpenTofu version | AzureRM version | 19 | | -------------- | ----------------- | ---------------- | --------------- | 20 | | >= 8.x.x | **Unverified** | 1.8.x | >= 4.0 | 21 | | >= 7.x.x | 1.3.x | | >= 3.0 | 22 | | >= 6.x.x | 1.x | | >= 3.0 | 23 | | >= 5.x.x | 0.15.x | | >= 2.0 | 24 | | >= 4.x.x | 0.13.x / 0.14.x | | >= 2.0 | 25 | | >= 3.x.x | 0.12.x | | >= 2.0 | 26 | | >= 2.x.x | 0.12.x | | < 2.0 | 27 | | < 2.x.x | 0.11.x | | < 2.0 | 28 | 29 | ## Contributing 30 | 31 | If you want to contribute to this repository, feel free to use our [pre-commit](https://pre-commit.com/) git hook configuration 32 | which will help you automatically update and format some files for you by enforcing our Terraform code module best-practices. 33 | 34 | More details are available in the [CONTRIBUTING.md](./CONTRIBUTING.md#pull-request-process) file. 35 | 36 | ## Usage 37 | 38 | This module is optimized to work with the [Claranet terraform-wrapper](https://github.com/claranet/terraform-wrapper) tool 39 | which set some terraform variables in the environment needed by this module. 40 | More details about variables set by the `terraform-wrapper` available in the [documentation](https://github.com/claranet/terraform-wrapper#environment). 41 | 42 | ⚠️ Since modules version v8.0.0, we do not maintain/check anymore the compatibility with 43 | [Hashicorp Terraform](https://github.com/hashicorp/terraform/). Instead, we recommend to use [OpenTofu](https://github.com/opentofu/opentofu/). 44 | 45 | ```hcl 46 | {{ include "examples/main/modules.tf" }} 47 | ``` 48 | 49 | {{ .Providers }} 50 | 51 | {{ .Modules }} 52 | 53 | {{ .Resources }} 54 | 55 | {{ .Inputs }} 56 | 57 | {{ .Outputs }} 58 | ... 59 | -------------------------------------------------------------------------------- /r-security.tf: -------------------------------------------------------------------------------- 1 | resource "azurerm_mssql_server_security_alert_policy" "main" { 2 | count = var.sql_server_security_alerting_enabled ? 1 : 0 3 | 4 | resource_group_name = var.resource_group_name 5 | server_name = azurerm_mssql_server.main.name 6 | state = "Enabled" 7 | } 8 | 9 | resource "azurerm_mssql_server_vulnerability_assessment" "main" { 10 | count = var.sql_server_vulnerability_assessment_enabled ? 1 : 0 11 | 12 | server_security_alert_policy_id = azurerm_mssql_server_security_alert_policy.main[0].id 13 | storage_container_path = format("%s%s/", var.security_storage_account_blob_endpoint, var.security_storage_account_container_name) 14 | storage_account_access_key = var.security_storage_account_access_key 15 | 16 | recurring_scans { 17 | enabled = true 18 | email_subscription_admins = true 19 | emails = var.alerting_email_addresses 20 | } 21 | } 22 | 23 | resource "azurerm_mssql_server_extended_auditing_policy" "main" { 24 | count = var.sql_server_extended_auditing_enabled ? 1 : 0 25 | 26 | server_id = azurerm_mssql_server.main.id 27 | storage_endpoint = var.security_storage_account_blob_endpoint 28 | storage_account_access_key = var.security_storage_account_access_key 29 | storage_account_access_key_is_secondary = false 30 | retention_in_days = var.sql_server_extended_auditing_retention_days 31 | } 32 | 33 | resource "azurerm_mssql_database_extended_auditing_policy" "db" { 34 | for_each = var.databases_extended_auditing_enabled ? try({ for db in var.databases : db.name => db }, {}) : {} 35 | 36 | database_id = azurerm_mssql_database.main[each.key].id 37 | storage_endpoint = var.security_storage_account_blob_endpoint 38 | storage_account_access_key = var.security_storage_account_access_key 39 | storage_account_access_key_is_secondary = false 40 | retention_in_days = var.databases_extended_auditing_retention_days 41 | } 42 | 43 | moved { 44 | from = azurerm_mssql_server_security_alert_policy.sql_server["enabled"] 45 | to = azurerm_mssql_server_security_alert_policy.main[0] 46 | } 47 | moved { 48 | from = azurerm_mssql_server_vulnerability_assessment.sql_server["enabled"] 49 | to = azurerm_mssql_server_vulnerability_assessment.main[0] 50 | } 51 | moved { 52 | from = azurerm_mssql_server_extended_auditing_policy.sql_server["enabled"] 53 | to = azurerm_mssql_server_extended_auditing_policy.main[0] 54 | } 55 | 56 | moved { 57 | from = azurerm_mssql_database_extended_auditing_policy.single_db 58 | to = azurerm_mssql_database_extended_auditing_policy.db 59 | } 60 | -------------------------------------------------------------------------------- /examples/main/modules.tf: -------------------------------------------------------------------------------- 1 | resource "random_password" "admin_password" { 2 | special = true 3 | override_special = "#$%&-_+{}<>:" 4 | upper = true 5 | lower = true 6 | number = true 7 | length = 32 8 | } 9 | 10 | # Elastic Pool 11 | module "sql_elastic" { 12 | source = "claranet/db-sql/azurerm" 13 | version = "x.x.x" 14 | 15 | client_name = var.client_name 16 | environment = var.environment 17 | location = module.azure_region.location 18 | location_short = module.azure_region.location_short 19 | stack = var.stack 20 | resource_group_name = module.rg.name 21 | 22 | administrator_login = "adminsqltest" 23 | administrator_password = random_password.admin_password.result 24 | create_databases_users = true 25 | 26 | elastic_pool_enabled = true 27 | elastic_pool_max_size = "50" 28 | elastic_pool_sku = { 29 | tier = "GeneralPurpose" 30 | capacity = 2 31 | } 32 | 33 | allowed_cidrs = ["1.2.3.4/32", "5.6.7.8/16"] 34 | 35 | logs_destinations_ids = [ 36 | module.logs.id, 37 | module.logs.storage_account_id, 38 | ] 39 | 40 | databases = [ 41 | { 42 | name = "db1" 43 | max_size_gb = 50 44 | }, 45 | { 46 | name = "db2" 47 | max_size_gb = 180 48 | } 49 | ] 50 | 51 | custom_users = [ 52 | { 53 | database = "db1" 54 | name = "db1_custom1" 55 | roles = ["db_accessadmin", "db_securityadmin"] 56 | }, 57 | { 58 | database = "db1" 59 | name = "db1_custom2" 60 | roles = ["db_accessadmin", "db_securityadmin"] 61 | }, 62 | { 63 | database = "db2" 64 | name = "db2_custom1" 65 | roles = [] 66 | }, 67 | { 68 | database = "db2" 69 | name = "db2_custom2" 70 | roles = ["db_accessadmin", "db_securityadmin"] 71 | } 72 | ] 73 | } 74 | 75 | # Single Database 76 | module "sql_single" { 77 | source = "claranet/db-sql/azurerm" 78 | version = "x.x.x" 79 | 80 | client_name = var.client_name 81 | environment = var.environment 82 | location = module.azure_region.location 83 | location_short = module.azure_region.location_short 84 | stack = var.stack 85 | resource_group_name = module.rg.name 86 | 87 | administrator_login = "adminsqltest" 88 | administrator_password = random_password.admin_password.result 89 | create_databases_users = true 90 | 91 | elastic_pool_enabled = false 92 | 93 | allowed_cidrs = { 94 | "foo" = "1.2.3.4/32" 95 | "bar" = "5.6.7.8/16" 96 | } 97 | 98 | logs_destinations_ids = [ 99 | module.logs.id, 100 | module.logs.storage_account_id, 101 | ] 102 | 103 | databases = [ 104 | { 105 | name = "db1" 106 | max_size_gb = 50 107 | }, 108 | { 109 | name = "db2" 110 | max_size_gb = 180 111 | } 112 | ] 113 | 114 | custom_users = [ 115 | { 116 | database = "db1" 117 | name = "db1_custom1" 118 | roles = ["db_accessadmin", "db_securityadmin"] 119 | }, 120 | { 121 | database = "db1" 122 | name = "db1_custom2" 123 | roles = ["db_accessadmin", "db_securityadmin"] 124 | }, 125 | { 126 | database = "db2" 127 | name = "db2_custom1" 128 | roles = [] 129 | }, 130 | { 131 | database = "db2" 132 | name = "db2_custom2" 133 | roles = ["db_accessadmin", "db_securityadmin"] 134 | } 135 | ] 136 | } 137 | -------------------------------------------------------------------------------- /outputs.tf: -------------------------------------------------------------------------------- 1 | output "resource" { 2 | description = "SQL Server resource object." 3 | value = azurerm_mssql_server.main 4 | sensitive = true 5 | } 6 | 7 | output "administrator_login" { 8 | description = "SQL Administrator login." 9 | value = var.administrator_login 10 | sensitive = true 11 | } 12 | 13 | output "administrator_password" { 14 | description = "SQL Administrator password." 15 | value = var.administrator_password 16 | sensitive = true 17 | } 18 | 19 | output "elastic_pool_resource" { 20 | description = "SQL Elastic Pool resource." 21 | value = one(azurerm_mssql_elasticpool.main[*]) 22 | } 23 | 24 | output "databases_resource" { 25 | description = "SQL Databases resource list." 26 | value = azurerm_mssql_database.main 27 | } 28 | 29 | output "elastic_pool_id" { 30 | description = "ID of the SQL Elastic Pool." 31 | value = one(azurerm_mssql_elasticpool.main[*].id) 32 | } 33 | 34 | output "databases_id" { 35 | description = "Map of the SQL Databases names => IDs." 36 | value = { for db in azurerm_mssql_database.main : db.name => db.id } 37 | } 38 | 39 | output "default_administrator_databases_connection_strings" { 40 | description = "Map of the SQL Databases with administrator credentials connection strings" 41 | value = { 42 | for db in azurerm_mssql_database.main : db.name => formatlist( 43 | "Server=tcp:%s;Database=%s;User ID=%s;Password=%s;Encrypt=true;", 44 | azurerm_mssql_server.main.fully_qualified_domain_name, 45 | db.name, 46 | var.administrator_login, 47 | var.administrator_password 48 | ) 49 | } 50 | sensitive = true 51 | } 52 | 53 | output "default_databases_users" { 54 | description = "Map of the SQL Databases dedicated users" 55 | value = { 56 | for db_user in local.databases_users : 57 | db_user.database => { "user_name" = db_user.username, "password" = module.databases_users[format("%s-%s", db_user.username, db_user.database)].database_user_password } 58 | } 59 | sensitive = true 60 | } 61 | 62 | output "custom_databases_users" { 63 | description = "Map of the custom SQL Databases users" 64 | value = { 65 | for custom_user in var.custom_users : 66 | custom_user.database => { "user_name" = custom_user.name, "password" = module.custom_users[format("%s-%s", custom_user.name, custom_user.database)].database_user_password }... 67 | } 68 | sensitive = true 69 | } 70 | 71 | output "custom_databases_users_roles" { 72 | description = "Map of the custom SQL Databases users roles" 73 | value = { 74 | for custom_user in var.custom_users : 75 | join("-", [custom_user.name, custom_user.database]) => module.custom_users[join("-", [custom_user.name, custom_user.database])].database_user_roles 76 | } 77 | } 78 | 79 | output "identity_principal_id" { 80 | description = "SQL Server system identity principal ID." 81 | value = try(azurerm_mssql_server.main.identity[0].principal_id, null) 82 | } 83 | 84 | output "security_alert_policy_id" { 85 | description = "ID of the MS SQL Server Security Alert Policy" 86 | value = one(azurerm_mssql_server_security_alert_policy.main[*].id) 87 | } 88 | 89 | output "vulnerability_assessment_id" { 90 | description = "ID of the MS SQL Server Vulnerability Assessment." 91 | value = one(azurerm_mssql_server_vulnerability_assessment.main[*].id) 92 | } 93 | 94 | output "terraform_module" { 95 | description = "Information about this Terraform module." 96 | value = { 97 | name = "db-sql" 98 | provider = "azurerm" 99 | maintainer = "claranet" 100 | } 101 | } 102 | -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/Bug_Report.yml: -------------------------------------------------------------------------------- 1 | name: Bug Report 2 | description: If something isn't working as expected. 3 | title: "[BUG] ..." 4 | labels: [bug] 5 | body: 6 | - type: textarea 7 | id: community 8 | attributes: 9 | label: Community Note 10 | description: This note is for the community, please leave and skip this. 11 | value: | 12 | 13 | 14 | * Please vote on this issue by adding a :thumbsup: [reaction](https://blog.github.com/2016-03-10-add-reactions-to-pull-requests-issues-and-comments/) to the original issue to help the community and maintainers prioritize this request 15 | * Please do not leave "+1" or "me too" comments, they generate extra noise for issue followers and do not help prioritize the request 16 | * If you are interested in working on this issue or have submitted a pull request, please leave a comment 17 | 18 | 19 | validations: 20 | required: true 21 | - type: input 22 | id: terraform 23 | attributes: 24 | label: OpenTofu Version 25 | description: Which OpenTofu/Terraform version are you using? 26 | placeholder: 1.9.0 27 | validations: 28 | required: true 29 | - type: input 30 | id: azurerm 31 | attributes: 32 | label: AzureRM Provider Version 33 | description: Which AzureRM Provider version are you using? 34 | placeholder: 4.0.0 35 | validations: 36 | required: true 37 | - type: input 38 | id: resource 39 | attributes: 40 | label: Affected Resource(s)/Data Source(s) 41 | description: Please list the affected resources and/or data sources. 42 | placeholder: azurerm_XXXXX 43 | validations: 44 | required: true 45 | - type: textarea 46 | id: config 47 | attributes: 48 | label: OpenTofu Configuration Files 49 | description: | 50 | Please provide a minimal OpenTofu/HCL code configuration that can reproduce the issue. 51 | 52 | For large OpenTofu configs, please use a public Github repository. 53 | render: hcl 54 | validations: 55 | required: true 56 | - type: textarea 57 | id: debug 58 | attributes: 59 | label: Debug Output/Panic Output 60 | description: | 61 | For long debug logs please provide a link to a GitHub Gist containing the complete debug output. Please do NOT paste the debug output in the issue; just paste a link to the Gist. 62 | 63 | To obtain the debug output, see the [OpenTofu documentation on debugging](https://opentofu.org/docs/internals/debugging/) or [Terraform documentation on debugging](https://www.terraform.io/docs/internals/debugging.html). 64 | render: shell 65 | validations: 66 | required: true 67 | - type: textarea 68 | id: expected 69 | attributes: 70 | label: Expected Behaviour 71 | description: What should have happened? 72 | - type: textarea 73 | id: actual 74 | attributes: 75 | label: Actual Behaviour 76 | description: What actually happened? 77 | - type: textarea 78 | id: reproduce 79 | attributes: 80 | label: Steps to Reproduce 81 | description: | 82 | Please list the steps required to reproduce the issue, e.g: 83 | 84 | 1. `tofu apply` 85 | - type: input 86 | id: facts 87 | attributes: 88 | label: Important Factoids 89 | description: | 90 | Are there anything atypical about your accounts that we should know? For example: Running in a Azure China/Germany/Government? 91 | - type: textarea 92 | id: references 93 | attributes: 94 | label: References 95 | description: | 96 | Information about referencing Github Issues: https://help.github.com/articles/basic-writing-and-formatting-syntax/#referencing-issues-and-pull-requests 97 | 98 | Are there any other GitHub issues (open or closed) or pull requests that should be linked here? Such as vendor documentation? 99 | -------------------------------------------------------------------------------- /r-sql.tf: -------------------------------------------------------------------------------- 1 | #tfsec:ignore:azure-database-enable-audit 2 | resource "azurerm_mssql_server" "main" { 3 | name = local.name 4 | resource_group_name = var.resource_group_name 5 | location = var.location 6 | 7 | version = var.server_version 8 | connection_policy = var.connection_policy 9 | minimum_tls_version = var.tls_minimum_version 10 | public_network_access_enabled = var.public_network_access_enabled 11 | outbound_network_restriction_enabled = var.outbound_network_restriction_enabled 12 | 13 | # Express vulnerability assessment setting cannot be applied along with classic SQL vulnerability assessment 14 | express_vulnerability_assessment_enabled = var.express_vulnerability_assessment_enabled 15 | 16 | administrator_login = var.administrator_login 17 | administrator_login_password = var.administrator_password 18 | dynamic "azuread_administrator" { 19 | for_each = var.azuread_administrator[*] 20 | content { 21 | login_username = var.azuread_administrator.login_username 22 | object_id = var.azuread_administrator.object_id 23 | tenant_id = var.azuread_administrator.tenant_id 24 | azuread_authentication_only = var.azuread_administrator.azuread_authentication_only 25 | } 26 | } 27 | 28 | primary_user_assigned_identity_id = var.primary_user_assigned_identity_id 29 | 30 | dynamic "identity" { 31 | for_each = var.identity[*] 32 | content { 33 | type = var.identity.type 34 | identity_ids = endswith(var.identity.type, "UserAssigned") ? var.identity.identity_ids : null 35 | } 36 | } 37 | 38 | tags = merge(local.default_tags, var.extra_tags, var.server_extra_tags) 39 | 40 | lifecycle { 41 | precondition { 42 | condition = !(var.express_vulnerability_assessment_enabled && var.sql_server_vulnerability_assessment_enabled) 43 | error_message = "Classic SQL vulnerability assessment cannot be enabled when express vulnerability assessment is enabled." 44 | } 45 | } 46 | } 47 | 48 | resource "azurerm_mssql_firewall_rule" "main" { 49 | for_each = can(tomap(var.allowed_cidrs)) ? tomap(var.allowed_cidrs) : { for idx, cidr in var.allowed_cidrs : "rule-${idx}" => cidr } 50 | 51 | name = each.key 52 | server_id = azurerm_mssql_server.main.id 53 | 54 | start_ip_address = cidrhost(each.value, 0) 55 | end_ip_address = cidrhost(each.value, -1) 56 | } 57 | 58 | resource "azurerm_mssql_elasticpool" "main" { 59 | count = var.elastic_pool_enabled ? 1 : 0 60 | 61 | name = local.elastic_pool_name 62 | 63 | location = var.location 64 | resource_group_name = var.resource_group_name 65 | 66 | license_type = var.elastic_pool_license_type 67 | 68 | server_name = azurerm_mssql_server.main.name 69 | 70 | per_database_settings { 71 | max_capacity = coalesce(var.elastic_pool_databases_max_capacity, var.elastic_pool_sku.capacity) 72 | min_capacity = var.elastic_pool_databases_min_capacity 73 | } 74 | 75 | max_size_gb = var.elastic_pool_max_size 76 | zone_redundant = var.elastic_pool_zone_redundant 77 | 78 | sku { 79 | capacity = local.elastic_pool_sku.capacity 80 | name = local.elastic_pool_sku.name 81 | tier = local.elastic_pool_sku.tier 82 | family = local.elastic_pool_sku.family 83 | } 84 | 85 | tags = merge(local.default_tags, var.extra_tags, var.elastic_pool_extra_tags) 86 | } 87 | 88 | resource "azurerm_mssql_virtual_network_rule" "main" { 89 | for_each = try({ for subnet in local.allowed_subnets : subnet.name => subnet }, {}) 90 | name = each.key 91 | server_id = azurerm_mssql_server.main.id 92 | subnet_id = each.value.subnet_id 93 | } 94 | 95 | 96 | moved { 97 | from = azurerm_mssql_server.sql 98 | to = azurerm_mssql_server.main 99 | } 100 | moved { 101 | from = azurerm_mssql_firewall_rule.firewall_rule 102 | to = azurerm_mssql_firewall_rule.main 103 | } 104 | moved { 105 | from = azurerm_mssql_elasticpool.elastic_pool 106 | to = azurerm_mssql_elasticpool.main 107 | } 108 | moved { 109 | from = azurerm_mssql_virtual_network_rule.vnet_rule 110 | to = azurerm_mssql_virtual_network_rule.main 111 | } 112 | -------------------------------------------------------------------------------- /.releaserc: -------------------------------------------------------------------------------- 1 | { 2 | "branches": [ 3 | "master", 4 | "main" 5 | ], 6 | "tagFormat": "v${version}", 7 | "plugins": [ 8 | [ 9 | "@semantic-release/commit-analyzer", 10 | { 11 | "preset": "conventionalcommits", 12 | "releaseRules": [ 13 | { 14 | "type": "docs", 15 | "release": "patch" 16 | }, 17 | { 18 | "type": "refactor", 19 | "release": "patch" 20 | }, 21 | { 22 | "type": "test", 23 | "release": "patch" 24 | }, 25 | { 26 | "type": "style", 27 | "release": "patch" 28 | }, 29 | { 30 | "type": "revert", 31 | "release": "patch" 32 | } 33 | ], 34 | "parserOpts": { 35 | "noteKeywords": [ 36 | "BREAKING CHANGE", 37 | "BREAKING CHANGES", 38 | "BREAKING" 39 | ] 40 | } 41 | } 42 | ], 43 | [ 44 | "@semantic-release/release-notes-generator", 45 | { 46 | "linkReferences": false, 47 | "linkCompare": false, 48 | "preset": "conventionalcommits", 49 | "parserOpts": { 50 | "noteKeywords": [ 51 | "BREAKING CHANGE", 52 | "BREAKING CHANGES", 53 | "BREAKING" 54 | ] 55 | }, 56 | "presetConfig": { 57 | "types": [ 58 | { 59 | "type": "feat", 60 | "section": "Features", 61 | "hidden": false 62 | }, 63 | { 64 | "type": "fix", 65 | "section": "Bug Fixes", 66 | "hidden": false 67 | }, 68 | { 69 | "type": "docs", 70 | "section": "Documentation", 71 | "hidden": false 72 | }, 73 | { 74 | "type": "style", 75 | "section": "Styles", 76 | "hidden": false 77 | }, 78 | { 79 | "type": "refactor", 80 | "section": "Code Refactoring", 81 | "hidden": false 82 | }, 83 | { 84 | "type": "perf", 85 | "section": "Performance Improvements", 86 | "hidden": false 87 | }, 88 | { 89 | "type": "test", 90 | "section": "Tests", 91 | "hidden": false 92 | }, 93 | { 94 | "type": "ci", 95 | "section": "Continuous Integration", 96 | "hidden": false 97 | }, 98 | { 99 | "type": "chore", 100 | "section": "Miscellaneous Chores", 101 | "hidden": false 102 | }, 103 | { 104 | "type": "revert", 105 | "section": "Revert", 106 | "hidden": false 107 | } 108 | ] 109 | } 110 | } 111 | ], 112 | [ 113 | "@semantic-release/changelog", 114 | { 115 | "changelogFile": "CHANGELOG.md" 116 | } 117 | ], 118 | [ 119 | "@semantic-release/git", 120 | { 121 | "assets": [ 122 | "CHANGELOG.md" 123 | ] 124 | } 125 | ], 126 | [ 127 | "@semantic-release/gitlab", 128 | { 129 | "gitlabUrl": "https://git.fr.clara.net", 130 | "assets": [ 131 | "CHANGELOG.md" 132 | ] 133 | } 134 | ], 135 | [ 136 | "semantic-release-slack-bot", 137 | { 138 | "notifyOnSuccess": true, 139 | "notifyOnFail": true, 140 | "markdownReleaseNotes": true, 141 | "onSuccessTemplate": { 142 | "text": "New Azure TF module release", 143 | "blocks": [ 144 | { 145 | "type": "section", 146 | "text": { 147 | "type": "mrkdwn", 148 | "text": ":dancing-tofu: New :azure3: <$repo_url|module $package_name> *$npm_package_version* version out! :dancing-tofu:" 149 | } 150 | }, 151 | { 152 | "type": "section", 153 | "text": { 154 | "type": "mrkdwn", 155 | "text": "Module path: $repo_path" 156 | } 157 | }, 158 | { 159 | "type": "section", 160 | "text": { 161 | "type": "mrkdwn", 162 | "text": "$release_notes" 163 | } 164 | } 165 | ] 166 | } 167 | } 168 | ] 169 | ] 170 | } 171 | -------------------------------------------------------------------------------- /modules/databases_users/README.md: -------------------------------------------------------------------------------- 1 | # MS SQL Server database users creation module 2 | 3 | 4 | ## Global versioning rule for Claranet Azure modules 5 | 6 | | Module version | Terraform version | OpenTofu version | AzureRM version | 7 | | -------------- | ----------------- | ---------------- | --------------- | 8 | | >= 8.x.x | **Unverified** | 1.8.x | >= 4.0 | 9 | | >= 7.x.x | 1.3.x | | >= 3.0 | 10 | | >= 6.x.x | 1.x | | >= 3.0 | 11 | | >= 5.x.x | 0.15.x | | >= 2.0 | 12 | | >= 4.x.x | 0.13.x / 0.14.x | | >= 2.0 | 13 | | >= 3.x.x | 0.12.x | | >= 2.0 | 14 | | >= 2.x.x | 0.12.x | | < 2.0 | 15 | | < 2.x.x | 0.11.x | | < 2.0 | 16 | 17 | ## Contributing 18 | 19 | If you want to contribute to this repository, feel free to use our [pre-commit](https://pre-commit.com/) git hook configuration 20 | which will help you automatically update and format some files for you by enforcing our Terraform code module best-practices. 21 | 22 | More details are available in the [CONTRIBUTING.md](../../CONTRIBUTING.md#pull-request-process) file. 23 | 24 | ## Usage 25 | 26 | This module is optimized to work with the [Claranet terraform-wrapper](https://github.com/claranet/terraform-wrapper) tool 27 | which set some terraform variables in the environment needed by this module. 28 | More details about variables set by the `terraform-wrapper` available in the [documentation](https://github.com/claranet/terraform-wrapper#environment). 29 | 30 | ⚠️ Since modules version v8.0.0, we do not maintain/check anymore the compatibility with 31 | [Hashicorp Terraform](https://github.com/hashicorp/terraform/). Instead, we recommend to use [OpenTofu](https://github.com/opentofu/opentofu/). 32 | 33 | ```hcl 34 | resource "random_password" "admin_password" { 35 | special = true 36 | override_special = "#$%&-_+{}<>:" 37 | upper = true 38 | lower = true 39 | number = true 40 | length = 32 41 | } 42 | 43 | module "sql_single" { 44 | source = "claranet/db-sql/azurerm" 45 | version = "x.x.x" 46 | 47 | client_name = var.client_name 48 | environment = var.environment 49 | location = module.azure_region.location 50 | location_short = module.azure_region.location_short 51 | stack = var.stack 52 | resource_group_name = module.rg.name 53 | 54 | administrator_login = "adminsqltest" 55 | administrator_password = random_password.admin_password.result 56 | create_databases_users = false 57 | 58 | elastic_pool_enabled = false 59 | 60 | logs_destinations_ids = [ 61 | module.logs.id, 62 | module.logs.storage_account_id, 63 | ] 64 | 65 | databases = [ 66 | { 67 | name = "db1" 68 | max_size_gb = 50 69 | }, 70 | ] 71 | } 72 | 73 | module "users" { 74 | for_each = { 75 | "app-db1" = { 76 | name = "app" 77 | database = "db1" 78 | roles = ["db_accessadmin", "db_securityadmin"] 79 | } 80 | } 81 | 82 | source = "claranet/db-sql/azurerm//modules/databases_users" 83 | version = "x.x.x" 84 | 85 | administrator_login = "adminsqltest" 86 | administrator_password = random_password.admin_password.result 87 | 88 | sql_server_hostname = module.sql_single.databases_resource["db1"].fully_qualified_domain_name 89 | 90 | database_name = each.value.database 91 | user_name = each.value.name 92 | user_roles = each.value.roles 93 | } 94 | ``` 95 | 96 | ## Providers 97 | 98 | | Name | Version | 99 | |------|---------| 100 | | mssql | ~> 0.3.0 | 101 | | random | >= 3.4.3 | 102 | 103 | ## Modules 104 | 105 | No modules. 106 | 107 | ## Resources 108 | 109 | | Name | Type | 110 | |------|------| 111 | | [mssql_login.main](https://registry.terraform.io/providers/betr-io/mssql/latest/docs/resources/login) | resource | 112 | | [mssql_user.main](https://registry.terraform.io/providers/betr-io/mssql/latest/docs/resources/user) | resource | 113 | | [random_password.main](https://registry.terraform.io/providers/hashicorp/random/latest/docs/resources/password) | resource | 114 | 115 | ## Inputs 116 | 117 | | Name | Description | Type | Default | Required | 118 | |------|-------------|------|---------|:--------:| 119 | | administrator\_login | Login for the SQL Server administrator. | `string` | n/a | yes | 120 | | administrator\_password | Password for the SQL Server administrator. | `string` | n/a | yes | 121 | | database\_name | Name of the database where the custom user should be created. | `string` | n/a | yes | 122 | | sql\_server\_hostname | FQDN of the SQL Server. | `string` | n/a | yes | 123 | | user\_name | Name of the custom user. | `string` | n/a | yes | 124 | | user\_roles | List of databases roles for the custom user. | `list(string)` | n/a | yes | 125 | 126 | ## Outputs 127 | 128 | | Name | Description | 129 | |------|-------------| 130 | | name | Name of the custom user. | 131 | | password | Password of the custom user. | 132 | | roles | Roles of the custom user. | 133 | 134 | -------------------------------------------------------------------------------- /CONTRIBUTING.md: -------------------------------------------------------------------------------- 1 | # Contributing 2 | 3 | When contributing to this repository, please first discuss the change you wish to make via an issue, 4 | an email, or any other method with the owners of this repository before making a change. 5 | 6 | Please note we have a code of conduct, please follow it in all your interactions with the project. 7 | 8 | ## Pull Request Process 9 | 10 | 1. Ensure any installed or built dependencies are removed before the end of the layer when doing a 11 | Pull Request. Ensure also that your code is clean and production ready. 12 | 2. Update the [README.md](./README.md) with details of changes to the module, including variables, outputs 13 | or changes to [examples](./examples). 14 | 3. Update the [CHANGELOG.md](./CHANGELOG.md) with a new entry block starting with `# Unreleased` 15 | followed by a description of your new feature, bug fix or change. 16 | 4. The Github Actions CI must pass. It ensures that our Terraform module codestyle rules are followed. 17 | 5. Please wait for maintainers to review your code, they will merge and release your changes once every 18 | discussions or implementation details are satisfied. 19 | 20 | ### Pre-commit usage 21 | 22 | We recommend using `pre-commit` ([the famous python git hooks tool](https://pre-commit.com/#intro)) 23 | when you start a contribution. It will automatically trigger hooks which ensure our codestyle rules are followed, 24 | files are formatted and linted, and that your README.md file is proprerly generated and updated. 25 | 26 | Installation on your local system: 27 | ```bash 28 | $ pipx install pre-commit 29 | ``` 30 | or 31 | ```bash 32 | $ pip3 install pre-commit --user 33 | ``` 34 | 35 | and then, configure and enable our hooks: 36 | ```bash 37 | $ cd path_to_the_git_cloned_module/ 38 | $ pre-commit install 39 | ``` 40 | 41 | Do your changes as usual, hooks will be triggered by `pre-commit` every time you use the `git commit` command. 42 | 43 | To have all `pre-commit` hooks working you will have to setup thoses dependencies locally: 44 | - latest version of [terraform](https://releases.hashicorp.com/terraform/) 45 | - [tfdocs](https://github.com/terraform-docs/terraform-docs) 46 | - [tflint](https://github.com/terraform-linters/tflint) 47 | - [tfsec](https://github.com/aquasecurity/tfsec) 48 | 49 | ## Code of Conduct 50 | 51 | ### Our Pledge 52 | 53 | In the interest of fostering an open and welcoming environment, we as 54 | contributors and maintainers pledge to making participation in our project and 55 | our community a harassment-free experience for everyone, regardless of age, body 56 | size, disability, ethnicity, gender identity and expression, level of experience, 57 | nationality, personal appearance, race, religion, or sexual identity and 58 | orientation. 59 | 60 | ### Our Standards 61 | 62 | Examples of behavior that contribute to creating a positive environment 63 | include: 64 | 65 | * Using a welcoming and inclusive language 66 | * Being respectful of differing viewpoints and experiences 67 | * Gracefully accepting constructive criticism 68 | * Focusing on what is best for the community 69 | * Showing empathy towards other community members 70 | 71 | Examples of unacceptable behavior by participants include: 72 | 73 | * The use of sexualized language or imagery and unwelcome sexual attentions or 74 | advances 75 | * Trolling, insulting/derogatory comments, and personal or political attacks 76 | * Public or private harassment 77 | * Publishing others' private information, such as a physical or electronic 78 | address, without explicit permission 79 | * Other conduct which could reasonably be considered inappropriate in a 80 | professional setting 81 | 82 | ### Our Responsibilities 83 | 84 | Project maintainers are responsible for clarifying the standards of acceptable 85 | behavior and are expected to take appropriate and fair corrective actions in 86 | response to any instance of unacceptable behavior. 87 | 88 | Project maintainers have the right and responsibility to remove, edit, or 89 | reject comments, commits, code, wiki edits, issues, and other contributions 90 | that are not aligned to this Code of Conduct, to temporarily or permanently 91 | ban any contributor for other behaviors that they deem inappropriate, 92 | threatening, offensive, or harmful. 93 | 94 | ### Scope 95 | 96 | This Code of Conduct applies both within project spaces and in public spaces 97 | when an individual is representing the project or its community. Examples of 98 | representing a project or community include using an official project e-mail 99 | address, posting via an official social media account, or acting as an appointed 100 | representative at an online or offline event. Representation of a project may be 101 | further defined and clarified by project maintainers. 102 | 103 | ### Enforcement 104 | 105 | Instances of abusive, harassing, or otherwise unacceptable behavior may be 106 | reported by contacting the project team at [FR-CloudPublic-github@fr.clara.net]. All 107 | complaints will be reviewed and investigated and will result in a response that 108 | is deemed necessary and appropriate to the circumstances. The project team is 109 | obligated to maintain confidentiality with regard to the reporter of an incident. 110 | Further details of specific enforcement policies may be posted separately. 111 | 112 | Project maintainers who do not follow or enforce the Code of Conduct in good 113 | faith may face temporary or permanent repercussions as determined by other 114 | members of the project's leadership. 115 | 116 | ### Attribution 117 | 118 | This Code of Conduct is adapted from the [Contributor Covenant][homepage], version 1.4, 119 | available at [http://contributor-covenant.org/version/1/4][version] 120 | 121 | [homepage]: http://contributor-covenant.org 122 | [version]: http://contributor-covenant.org/version/1/4/ 123 | -------------------------------------------------------------------------------- /r-db.tf: -------------------------------------------------------------------------------- 1 | # This resource represents both single databases and elastic pool databases 2 | # The configuration is dynamically adjusted based on whether elastic_pool_enabled is true or false 3 | resource "azurerm_mssql_database" "main" { 4 | # Include all databases in a single resource with a unified for_each 5 | for_each = try({ for db in var.databases : db.name => db }, {}) 6 | 7 | # Common parameters for both single and elastic pool databases 8 | name = var.use_caf_naming_for_databases ? data.azurecaf_name.sql_dbs[each.key].result : each.key 9 | server_id = azurerm_mssql_server.main.id 10 | 11 | # SKU name is conditionally set based on elastic pool status 12 | # For elastic pool databases: "ElasticPool" 13 | # For single databases: Use the provided SKU name or default 14 | sku_name = var.elastic_pool_enabled ? "ElasticPool" : coalesce(each.value.sku_name, var.single_databases_sku_name) 15 | license_type = each.value.license_type 16 | 17 | # Elastic pool ID is only set for elastic pool databases 18 | elastic_pool_id = var.elastic_pool_enabled ? one(azurerm_mssql_elasticpool.main[*].id) : null 19 | 20 | # Common database configuration parameters 21 | collation = coalesce(each.value.collation, var.databases_collation) 22 | max_size_gb = can(regex("Secondary|OnlineSecondary", each.value.create_mode)) ? null : each.value.max_size_gb 23 | zone_redundant = can(regex("^DW", var.single_databases_sku_name)) && var.databases_zone_redundant != null ? var.databases_zone_redundant : false 24 | 25 | # Serverless configuration parameters - only applicable for single databases with specific SKUs 26 | min_capacity = !var.elastic_pool_enabled && can(regex("^GP_S|HS", var.single_databases_sku_name)) ? each.value.min_capacity : null 27 | 28 | auto_pause_delay_in_minutes = !var.elastic_pool_enabled && can(regex("^GP_S", var.single_databases_sku_name)) ? each.value.auto_pause_delay_in_minutes : null 29 | 30 | # Read scale configuration - only applicable for single databases with specific SKUs 31 | read_scale = !var.elastic_pool_enabled && can(regex("^P|BC|HS", var.single_databases_sku_name)) && each.value.read_scale != null ? each.value.read_scale : false 32 | 33 | # Read replica count - different conditions for single vs elastic pool databases 34 | read_replica_count = ( 35 | var.elastic_pool_enabled ? 36 | (startswith(try(local.elastic_pool_sku.name, ""), "HS") ? each.value.read_replica_count : null) : 37 | (can(regex("^HS", var.single_databases_sku_name)) ? each.value.read_replica_count : null) 38 | ) 39 | 40 | # Create mode - different logic for single databases with data warehouse SKUs 41 | # https://docs.microsoft.com/en-us/dotnet/api/microsoft.azure.management.sql.models.database.createmode?view=azure-dotnet 42 | create_mode = !var.elastic_pool_enabled && can(regex("^DW", var.single_databases_sku_name)) ? try(local.datawarehouse_allowed_create_mode[each.value.create_mode], "Default") : try(local.standard_allowed_create_mode[each.value.create_mode], "Default") 43 | 44 | # Common restore and recovery parameters 45 | creation_source_database_id = can(regex("Copy|Secondary|PointInTimeRestore|Recovery|RestoreExternalBackup|Restore|RestoreExternalBackupSecondary", each.value.create_mode)) ? each.value.creation_source_database_id : null 46 | 47 | restore_point_in_time = each.value.create_mode == "PointInTimeRestore" ? each.value.restore_point_in_time : null 48 | recover_database_id = each.value.create_mode == "Recovery" ? each.value.recover_database_id : null 49 | restore_dropped_database_id = each.value.create_mode == "Restore" ? each.value.restore_dropped_database_id : null 50 | 51 | # Storage configuration 52 | storage_account_type = each.value.storage_account_type 53 | 54 | dynamic "identity" { 55 | for_each = length(each.value.identity_ids) > 0 ? ["UserAssigned"] : [] 56 | content { 57 | type = "UserAssigned" 58 | identity_ids = each.value.identity_ids 59 | } 60 | } 61 | 62 | # Threat detection policy - same for both types 63 | dynamic "threat_detection_policy" { 64 | for_each = var.threat_detection_policy_enabled ? ["enabled"] : [] 65 | content { 66 | state = "Enabled" 67 | email_account_admins = "Enabled" 68 | email_addresses = var.alerting_email_addresses 69 | retention_days = var.threat_detection_policy_retention_days 70 | disabled_alerts = var.threat_detection_policy_disabled_alerts 71 | storage_endpoint = var.security_storage_account_blob_endpoint 72 | storage_account_access_key = var.security_storage_account_access_key 73 | } 74 | } 75 | 76 | # Short-term retention policy - different implementation for elastic pool vs single databases 77 | # For elastic pool databases: Use dynamic block with condition 78 | # For single databases: Always include the block 79 | dynamic "short_term_retention_policy" { 80 | # For elastic pool databases, exclude the block for HS SKUs 81 | # For single databases, always include the block 82 | for_each = var.elastic_pool_enabled && try(startswith(local.elastic_pool_sku.name, "HS"), false) ? [] : ["enabled"] 83 | content { 84 | retention_days = var.point_in_time_restore_retention_days 85 | # backup_interval_in_hours is only supported for elastic pool databases 86 | backup_interval_in_hours = var.elastic_pool_enabled ? var.point_in_time_backup_interval_in_hours : null 87 | } 88 | } 89 | 90 | # Long-term retention policy - same for both types 91 | dynamic "long_term_retention_policy" { 92 | for_each = coalesce( 93 | try(var.backup_retention.weekly_retention, ""), 94 | try(var.backup_retention.monthly_retention, ""), 95 | try(var.backup_retention.yearly_retention, ""), 96 | try(var.backup_retention.week_of_year, ""), 97 | "empty" 98 | ) == "empty" ? [] : ["enabled"] 99 | content { 100 | weekly_retention = try(format("P%sW", var.backup_retention.weekly_retention), null) 101 | monthly_retention = try(format("P%sM", var.backup_retention.monthly_retention), null) 102 | yearly_retention = try(format("P%sY", var.backup_retention.yearly_retention), null) 103 | week_of_year = var.backup_retention.week_of_year 104 | } 105 | } 106 | 107 | # Tags - same for both types 108 | tags = merge(local.default_tags, var.extra_tags, try(each.value.database_extra_tags, {})) 109 | } 110 | 111 | moved { 112 | from = azurerm_mssql_database.single_database 113 | to = azurerm_mssql_database.main 114 | } 115 | -------------------------------------------------------------------------------- /variables.tf: -------------------------------------------------------------------------------- 1 | variable "location" { 2 | description = "Azure location." 3 | type = string 4 | } 5 | 6 | variable "location_short" { 7 | description = "Short string for Azure location." 8 | type = string 9 | } 10 | 11 | variable "client_name" { 12 | description = "Client name/account used in naming." 13 | type = string 14 | } 15 | 16 | variable "environment" { 17 | description = "Project environment." 18 | type = string 19 | } 20 | 21 | variable "stack" { 22 | description = "Project stack name." 23 | type = string 24 | } 25 | 26 | variable "resource_group_name" { 27 | description = "Resource group name." 28 | type = string 29 | } 30 | 31 | variable "server_version" { 32 | description = "Version of the SQL Server. Valid values are: 2.0 (for v11 server) and 12.0 (for v12 server). See [documentation](https://registry.terraform.io/providers/hashicorp/azurerm/latest/docs/resources/mssql_server#version-1)." 33 | type = string 34 | default = "12.0" 35 | } 36 | 37 | variable "allowed_cidrs" { 38 | description = "List/map of allowed CIDR ranges to access the SQL server. Default to all Azure services." 39 | type = any 40 | nullable = false 41 | default = { azure-services = "0.0.0.0/32" } 42 | 43 | validation { 44 | condition = can(tomap(var.allowed_cidrs)) || can(tolist(var.allowed_cidrs)) 45 | error_message = "The `allowed_cidrs` argument must either be list(string) or map(string) of CIDRs." 46 | } 47 | } 48 | 49 | variable "elastic_pool_enabled" { 50 | description = "True to deploy the databases in an ElasticPool, single databases are deployed otherwise." 51 | type = bool 52 | default = false 53 | } 54 | 55 | variable "elastic_pool_sku" { 56 | description = <= 7 && var.point_in_time_restore_retention_days <= 35 239 | error_message = "The PITR retention should be between 7 and 35 days." 240 | } 241 | } 242 | 243 | variable "point_in_time_backup_interval_in_hours" { 244 | description = "The hours between each differential backup. This is only applicable to live databases but not dropped databases. Value has to be 12 or 24. Defaults to 12 hours." 245 | type = number 246 | default = 12 247 | validation { 248 | condition = var.point_in_time_backup_interval_in_hours == 12 || var.point_in_time_backup_interval_in_hours == 24 249 | error_message = "The PITR retention should be 12 or 24 hours." 250 | } 251 | } 252 | 253 | variable "security_storage_account_blob_endpoint" { 254 | description = "Storage Account blob endpoint used to store security logs and reports." 255 | type = string 256 | default = null 257 | } 258 | 259 | variable "security_storage_account_access_key" { 260 | description = "Storage Account access key used to store security logs and reports." 261 | type = string 262 | default = null 263 | } 264 | 265 | variable "security_storage_account_container_name" { 266 | description = "Storage Account container name where to store SQL Server vulnerability assessment." 267 | type = string 268 | default = null 269 | } 270 | 271 | variable "identity" { 272 | description = "Identity block information." 273 | type = object({ 274 | type = optional(string, "SystemAssigned") 275 | identity_ids = optional(list(string)) 276 | }) 277 | default = {} 278 | nullable = false 279 | } 280 | 281 | variable "primary_user_assigned_identity_id" { 282 | description = "Specifies the primary user managed identity id. Required if type within the identity block is set to either SystemAssigned, UserAssigned or UserAssigned and should be set at same time as setting identity_ids." 283 | type = string 284 | default = null 285 | } 286 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | Apache License 2 | Version 2.0, January 2004 3 | http://www.apache.org/licenses/ 4 | 5 | TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION 6 | 7 | 1. Definitions. 8 | 9 | "License" shall mean the terms and conditions for use, reproduction, 10 | and distribution as defined by Sections 1 through 9 of this document. 11 | 12 | "Licensor" shall mean the copyright owner or entity authorized by 13 | the copyright owner that is granting the License. 14 | 15 | "Legal Entity" shall mean the union of the acting entity and all 16 | other entities that control, are controlled by, or are under common 17 | control with that entity. For the purposes of this definition, 18 | "control" means (i) the power, direct or indirect, to cause the 19 | direction or management of such entity, whether by contract or 20 | otherwise, or (ii) ownership of fifty percent (50%) or more of the 21 | outstanding shares, or (iii) beneficial ownership of such entity. 22 | 23 | "You" (or "Your") shall mean an individual or Legal Entity 24 | exercising permissions granted by this License. 25 | 26 | "Source" form shall mean the preferred form for making modifications, 27 | including but not limited to software source code, documentation 28 | source, and configuration files. 29 | 30 | "Object" form shall mean any form resulting from mechanical 31 | transformation or translation of a Source form, including but 32 | not limited to compiled object code, generated documentation, 33 | and conversions to other media types. 34 | 35 | "Work" shall mean the work of authorship, whether in Source or 36 | Object form, made available under the License, as indicated by a 37 | copyright notice that is included in or attached to the work 38 | (an example is provided in the Appendix below). 39 | 40 | "Derivative Works" shall mean any work, whether in Source or Object 41 | form, that is based on (or derived from) the Work and for which the 42 | editorial revisions, annotations, elaborations, or other modifications 43 | represent, as a whole, an original work of authorship. For the purposes 44 | of this License, Derivative Works shall not include works that remain 45 | separable from, or merely link (or bind by name) to the interfaces of, 46 | the Work and Derivative Works thereof. 47 | 48 | "Contribution" shall mean any work of authorship, including 49 | the original version of the Work and any modifications or additions 50 | to that Work or Derivative Works thereof, that is intentionally 51 | submitted to Licensor for inclusion in the Work by the copyright owner 52 | or by an individual or Legal Entity authorized to submit on behalf of 53 | the copyright owner. For the purposes of this definition, "submitted" 54 | means any form of electronic, verbal, or written communication sent 55 | to the Licensor or its representatives, including but not limited to 56 | communication on electronic mailing lists, source code control systems, 57 | and issue tracking systems that are managed by, or on behalf of, the 58 | Licensor for the purpose of discussing and improving the Work, but 59 | excluding communication that is conspicuously marked or otherwise 60 | designated in writing by the copyright owner as "Not a Contribution." 61 | 62 | "Contributor" shall mean Licensor and any individual or Legal Entity 63 | on behalf of whom a Contribution has been received by Licensor and 64 | subsequently incorporated within the Work. 65 | 66 | 2. Grant of Copyright License. Subject to the terms and conditions of 67 | this License, each Contributor hereby grants to You a perpetual, 68 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable 69 | copyright license to reproduce, prepare Derivative Works of, 70 | publicly display, publicly perform, sublicense, and distribute the 71 | Work and such Derivative Works in Source or Object form. 72 | 73 | 3. Grant of Patent License. Subject to the terms and conditions of 74 | this License, each Contributor hereby grants to You a perpetual, 75 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable 76 | (except as stated in this section) patent license to make, have made, 77 | use, offer to sell, sell, import, and otherwise transfer the Work, 78 | where such license applies only to those patent claims licensable 79 | by such Contributor that are necessarily infringed by their 80 | Contribution(s) alone or by combination of their Contribution(s) 81 | with the Work to which such Contribution(s) was submitted. If You 82 | institute patent litigation against any entity (including a 83 | cross-claim or counterclaim in a lawsuit) alleging that the Work 84 | or a Contribution incorporated within the Work constitutes direct 85 | or contributory patent infringement, then any patent licenses 86 | granted to You under this License for that Work shall terminate 87 | as of the date such litigation is filed. 88 | 89 | 4. Redistribution. You may reproduce and distribute copies of the 90 | Work or Derivative Works thereof in any medium, with or without 91 | modifications, and in Source or Object form, provided that You 92 | meet the following conditions: 93 | 94 | (a) You must give any other recipients of the Work or 95 | Derivative Works a copy of this License; and 96 | 97 | (b) You must cause any modified files to carry prominent notices 98 | stating that You changed the files; and 99 | 100 | (c) You must retain, in the Source form of any Derivative Works 101 | that You distribute, all copyright, patent, trademark, and 102 | attribution notices from the Source form of the Work, 103 | excluding those notices that do not pertain to any part of 104 | the Derivative Works; and 105 | 106 | (d) If the Work includes a "NOTICE" text file as part of its 107 | distribution, then any Derivative Works that You distribute must 108 | include a readable copy of the attribution notices contained 109 | within such NOTICE file, excluding those notices that do not 110 | pertain to any part of the Derivative Works, in at least one 111 | of the following places: within a NOTICE text file distributed 112 | as part of the Derivative Works; within the Source form or 113 | documentation, if provided along with the Derivative Works; or, 114 | within a display generated by the Derivative Works, if and 115 | wherever such third-party notices normally appear. The contents 116 | of the NOTICE file are for informational purposes only and 117 | do not modify the License. You may add Your own attribution 118 | notices within Derivative Works that You distribute, alongside 119 | or as an addendum to the NOTICE text from the Work, provided 120 | that such additional attribution notices cannot be construed 121 | as modifying the License. 122 | 123 | You may add Your own copyright statement to Your modifications and 124 | may provide additional or different license terms and conditions 125 | for use, reproduction, or distribution of Your modifications, or 126 | for any such Derivative Works as a whole, provided Your use, 127 | reproduction, and distribution of the Work otherwise complies with 128 | the conditions stated in this License. 129 | 130 | 5. Submission of Contributions. Unless You explicitly state otherwise, 131 | any Contribution intentionally submitted for inclusion in the Work 132 | by You to the Licensor shall be under the terms and conditions of 133 | this License, without any additional terms or conditions. 134 | Notwithstanding the above, nothing herein shall supersede or modify 135 | the terms of any separate license agreement you may have executed 136 | with Licensor regarding such Contributions. 137 | 138 | 6. Trademarks. This License does not grant permission to use the trade 139 | names, trademarks, service marks, or product names of the Licensor, 140 | except as required for reasonable and customary use in describing the 141 | origin of the Work and reproducing the content of the NOTICE file. 142 | 143 | 7. Disclaimer of Warranty. Unless required by applicable law or 144 | agreed to in writing, Licensor provides the Work (and each 145 | Contributor provides its Contributions) on an "AS IS" BASIS, 146 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or 147 | implied, including, without limitation, any warranties or conditions 148 | of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A 149 | PARTICULAR PURPOSE. You are solely responsible for determining the 150 | appropriateness of using or redistributing the Work and assume any 151 | risks associated with Your exercise of permissions under this License. 152 | 153 | 8. Limitation of Liability. In no event and under no legal theory, 154 | whether in tort (including negligence), contract, or otherwise, 155 | unless required by applicable law (such as deliberate and grossly 156 | negligent acts) or agreed to in writing, shall any Contributor be 157 | liable to You for damages, including any direct, indirect, special, 158 | incidental, or consequential damages of any character arising as a 159 | result of this License or out of the use or inability to use the 160 | Work (including but not limited to damages for loss of goodwill, 161 | work stoppage, computer failure or malfunction, or any and all 162 | other commercial damages or losses), even if such Contributor 163 | has been advised of the possibility of such damages. 164 | 165 | 9. Accepting Warranty or Additional Liability. While redistributing 166 | the Work or Derivative Works thereof, You may choose to offer, 167 | and charge a fee for, acceptance of support, warranty, indemnity, 168 | or other liability obligations and/or rights consistent with this 169 | License. However, in accepting such obligations, You may act only 170 | on Your own behalf and on Your sole responsibility, not on behalf 171 | of any other Contributor, and only if You agree to indemnify, 172 | defend, and hold each Contributor harmless for any liability 173 | incurred by, or claims asserted against, such Contributor by reason 174 | of your accepting any such warranty or additional liability. 175 | 176 | END OF TERMS AND CONDITIONS 177 | 178 | APPENDIX: How to apply the Apache License to your work. 179 | 180 | To apply the Apache License to your work, attach the following 181 | boilerplate notice, with the fields enclosed by brackets "[]" 182 | replaced with your own identifying information. (Don't include 183 | the brackets!) The text should be enclosed in the appropriate 184 | comment syntax for the file format. We also recommend that a 185 | file or class name and description of purpose be included on the 186 | same "printed page" as the copyright notice for easier 187 | identification within third-party archives. 188 | 189 | Copyright (c) 2018-2023 Claranet 190 | 191 | Licensed under the Apache License, Version 2.0 (the "License"); 192 | you may not use this file except in compliance with the License. 193 | You may obtain a copy of the License at 194 | 195 | http://www.apache.org/licenses/LICENSE-2.0 196 | 197 | Unless required by applicable law or agreed to in writing, software 198 | distributed under the License is distributed on an "AS IS" BASIS, 199 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 200 | See the License for the specific language governing permissions and 201 | limitations under the License. 202 | -------------------------------------------------------------------------------- /CHANGELOG.md: -------------------------------------------------------------------------------- 1 | ## 8.4.1 (2025-09-30) 2 | 3 | ### Code Refactoring 4 | 5 | * **deps:** 🔗 update claranet/azurecaf to ~> 1.3.0 🔧 00ec186 6 | 7 | ### Miscellaneous Chores 8 | 9 | * **deps:** update dependency opentofu to v1.10.6 cb9ccd5 10 | * **deps:** update dependency tflint to v0.59.1 e5db8cc 11 | * **deps:** update dependency trivy to v0.66.0 18c435f 12 | * **deps:** update dependency trivy to v0.67.0 d39c04c 13 | * **deps:** update terraform claranet/diagnostic-settings/azurerm to ~> 8.2.0 27a697f 14 | 15 | ## 8.4.0 (2025-08-29) 16 | 17 | ### Features 18 | 19 | * **AZ-1603:** Add express vuln assessment 1780cee 20 | 21 | ### Miscellaneous Chores 22 | 23 | * **⚙️:** ✏️ update template identifier for MR review b58420f 24 | * 🔒️ apply more suggestions 42c54c6 25 | * 🗑️ remove old commitlint configuration files 1cbb865 26 | * apply descriptions suggestions 98d50ef 27 | * **deps:** 🔗 bump AzureRM provider version to v4.31+ 233c599 28 | * **deps:** update dependency claranet/diagnostic-settings/azurerm to ~> 8.1.0 3747f8e 29 | * **deps:** update dependency opentofu to v1.10.0 f5d9a2e 30 | * **deps:** update dependency opentofu to v1.10.1 5f6429e 31 | * **deps:** update dependency opentofu to v1.10.3 6415556 32 | * **deps:** update dependency tflint to v0.58.1 9deddbe 33 | * **deps:** update pre-commit hook pre-commit/pre-commit-hooks to v6 49b2690 34 | * **deps:** update pre-commit hook tofuutils/pre-commit-opentofu to v2.2.1 557cf84 35 | * **deps:** update tools 71a5f0f 36 | * **deps:** update tools bc3f9aa 37 | * **deps:** update tools 0d9c4bd 38 | 39 | ## 8.3.0 (2025-06-06) 40 | 41 | ### Features 42 | 43 | * **AZ-1568:** add variable allowed_cidrs c1577bd 44 | 45 | ### Miscellaneous Chores 46 | 47 | * **deps:** update dependency opentofu to v1.9.1 0303d59 48 | * **deps:** update dependency tflint to v0.57.0 f08a408 49 | * **deps:** update dependency tflint to v0.58.0 9315bba 50 | * **deps:** update dependency trivy to v0.62.0 1ebdb96 51 | * **deps:** update dependency trivy to v0.62.1 b994fce 52 | * **deps:** update dependency trivy to v0.63.0 74b2a1e 53 | 54 | ## 8.2.1 (2025-04-22) 55 | 56 | ### Bug Fixes 57 | 58 | * 🐛 add missing primary_user_assigned_identity_id parameter required for UserAssigned identity b097db0 59 | * 🐛 null error 55bc345 60 | 61 | ### Documentation 62 | 63 | * 📚️ update README 0faa585 64 | * description dot a0af195 65 | 66 | ### Miscellaneous Chores 67 | 68 | * **deps:** update dependency trivy to v0.61.1 10e8b2e 69 | 70 | ## 8.2.0 (2025-04-18) 71 | 72 | ### Features 73 | 74 | * **GH-3:** merge single_database and elastic_pools 3872098 75 | 76 | ### Code Refactoring 77 | 78 | * **GH-3:** revamp module c48ad05 79 | 80 | ### Miscellaneous Chores 81 | 82 | * moved blocks fffedf1 83 | 84 | ## 8.1.1 (2025-04-14) 85 | 86 | ### Bug Fixes 87 | 88 | * parametrize SQL DB identity ([#9](https://git.fr.clara.net/claranet/projects/cloud/azure/terraform/modules/db-sql/issues/9)) 4169302 89 | 90 | ### Documentation 91 | 92 | * **GH-9:** update README 9f1b77f 93 | 94 | ## 8.1.0 (2025-04-14) 95 | 96 | ### Features 97 | 98 | * **GH-7:** add option to modify SQL server identity 08b98b1 99 | * unhardcode SQL server identity 848122b 100 | 101 | ### Code Refactoring 102 | 103 | * code lint 40638ab 104 | 105 | ### Miscellaneous Chores 106 | 107 | * **deps:** update dependency pre-commit to v4.2.0 9a89513 108 | * **deps:** update dependency terraform-docs to v0.20.0 7f33940 109 | * **deps:** update dependency tflint to v0.55.1 1c2ea43 110 | * **deps:** update dependency trivy to v0.59.0 6ff6f63 111 | * **deps:** update dependency trivy to v0.59.1 f58c891 112 | * **deps:** update dependency trivy to v0.60.0 3220d91 113 | * **deps:** update pre-commit hook alessandrojcm/commitlint-pre-commit-hook to v9.21.0 7e9b69f 114 | * **deps:** update pre-commit hook alessandrojcm/commitlint-pre-commit-hook to v9.22.0 271b542 115 | * **deps:** update pre-commit hook tofuutils/pre-commit-opentofu to v2.2.0 5fce321 116 | * **deps:** update terraform mssql to ~> 0.3.0 752d22c 117 | * **deps:** update tools 54f875f 118 | * update Github templates de4cc08 119 | 120 | ## 8.0.0 (2025-01-31) 121 | 122 | ### ⚠ BREAKING CHANGES 123 | 124 | * **AZ-1088:** module v8 structure and updates 125 | 126 | ### Features 127 | 128 | * **AZ-1088:** module v8 structure and updates f1bba72 129 | 130 | ### Miscellaneous Chores 131 | 132 | * **deps:** update dependency claranet/diagnostic-settings/azurerm to v7 2dada57 133 | * **deps:** update dependency opentofu to v1.8.3 19bcc58 134 | * **deps:** update dependency opentofu to v1.8.4 fe9a947 135 | * **deps:** update dependency opentofu to v1.8.6 ef69712 136 | * **deps:** update dependency opentofu to v1.8.8 4b5f1f9 137 | * **deps:** update dependency opentofu to v1.9.0 d26595f 138 | * **deps:** update dependency pre-commit to v4 bc6c3ad 139 | * **deps:** update dependency pre-commit to v4.1.0 7a36210 140 | * **deps:** update dependency tflint to v0.54.0 6da88c5 141 | * **deps:** update dependency tflint to v0.55.0 448f3be 142 | * **deps:** update dependency trivy to v0.56.1 287ebc5 143 | * **deps:** update dependency trivy to v0.56.2 dae1e99 144 | * **deps:** update dependency trivy to v0.57.1 ec288f3 145 | * **deps:** update dependency trivy to v0.58.1 0c83981 146 | * **deps:** update dependency trivy to v0.58.2 c3bb0d9 147 | * **deps:** update pre-commit hook alessandrojcm/commitlint-pre-commit-hook to v9.19.0 154b211 148 | * **deps:** update pre-commit hook alessandrojcm/commitlint-pre-commit-hook to v9.20.0 6c70802 149 | * **deps:** update pre-commit hook pre-commit/pre-commit-hooks to v5 9181a9f 150 | * **deps:** update pre-commit hook tofuutils/pre-commit-opentofu to v2.1.0 8a6c345 151 | * **deps:** update tools 037d46f 152 | * **deps:** update tools 124b78d 153 | * prepare for new examples structure 7c17e42 154 | * update examples structure 46105cb 155 | * update submodule READMEs with latest template 90932ed 156 | * update tflint config for v0.55.0 52f5770 157 | 158 | ## 7.12.0 (2024-10-03) 159 | 160 | ### Features 161 | 162 | * use Claranet "azurecaf" provider e34bdec 163 | 164 | ### Documentation 165 | 166 | * update README badge to use OpenTofu registry 1fb419b 167 | * update README with `terraform-docs` v0.19.0 7cfbae4 168 | 169 | ### Miscellaneous Chores 170 | 171 | * **deps:** update dependency opentofu to v1.7.3 82ae5cd 172 | * **deps:** update dependency opentofu to v1.8.0 a3ff664 173 | * **deps:** update dependency opentofu to v1.8.1 8e0aec1 174 | * **deps:** update dependency pre-commit to v3.8.0 6f0a6ac 175 | * **deps:** update dependency tflint to v0.52.0 633cd0c 176 | * **deps:** update dependency tflint to v0.53.0 793bc42 177 | * **deps:** update dependency trivy to v0.54.1 1486980 178 | * **deps:** update dependency trivy to v0.55.0 06b2d88 179 | * **deps:** update dependency trivy to v0.55.1 687d11d 180 | * **deps:** update dependency trivy to v0.55.2 9e4ba99 181 | * **deps:** update dependency trivy to v0.56.0 6a62a35 182 | * **deps:** update pre-commit hook alessandrojcm/commitlint-pre-commit-hook to v9.17.0 7186fd4 183 | * **deps:** update pre-commit hook alessandrojcm/commitlint-pre-commit-hook to v9.18.0 6b50794 184 | * **deps:** update pre-commit hook antonbabenko/pre-commit-terraform to v1.92.1 0db7dda 185 | * **deps:** update pre-commit hook antonbabenko/pre-commit-terraform to v1.92.2 8a48961 186 | * **deps:** update pre-commit hook antonbabenko/pre-commit-terraform to v1.92.3 98b7b4c 187 | * **deps:** update pre-commit hook antonbabenko/pre-commit-terraform to v1.93.0 ffb830d 188 | * **deps:** update pre-commit hook antonbabenko/pre-commit-terraform to v1.94.0 82ef21c 189 | * **deps:** update pre-commit hook antonbabenko/pre-commit-terraform to v1.94.1 ea33d3e 190 | * **deps:** update pre-commit hook antonbabenko/pre-commit-terraform to v1.94.3 5bdc9f4 191 | * **deps:** update pre-commit hook antonbabenko/pre-commit-terraform to v1.95.0 2eca800 192 | * **deps:** update pre-commit hook antonbabenko/pre-commit-terraform to v1.96.0 a77a077 193 | * **deps:** update tools 71f83c5 194 | * **deps:** update tools 0b3a3e4 195 | 196 | ## 7.11.0 (2024-07-05) 197 | 198 | 199 | ### Features 200 | 201 | * **AZ-1434:** add collation elastic pool db c73aa63 202 | 203 | 204 | ### Miscellaneous Chores 205 | 206 | * **deps:** update dependency tflint to v0.51.2 df311d5 207 | * **deps:** update dependency trivy to v0.53.0 d8f5af0 208 | 209 | ## 7.10.0 (2024-06-21) 210 | 211 | 212 | ### Features 213 | 214 | * **AZ-1426:** add parameters for elastic and single databases 4d3376a 215 | 216 | 217 | ### Miscellaneous Chores 218 | 219 | * **deps:** update dependency trivy to v0.52.2 b691eb7 220 | * **deps:** update pre-commit hook antonbabenko/pre-commit-terraform to v1.92.0 3ce3620 221 | 222 | ## 7.9.0 (2024-06-14) 223 | 224 | 225 | ### Features 226 | 227 | * add hyperscale tier support for elastic pool b2ca9f8 228 | 229 | 230 | ### Miscellaneous Chores 231 | 232 | * **deps:** update dependency trivy to v0.52.1 875e687 233 | 234 | ## 7.8.0 (2024-06-07) 235 | 236 | 237 | ### Features 238 | 239 | * optional max_size_gb for databases configuration e11be1b 240 | 241 | 242 | ### Miscellaneous Chores 243 | 244 | * **deps:** update dependency opentofu to v1.7.0 4a3997e 245 | * **deps:** update dependency opentofu to v1.7.1 638f40e 246 | * **deps:** update dependency opentofu to v1.7.2 736d4a7 247 | * **deps:** update dependency pre-commit to v3.7.1 836d380 248 | * **deps:** update dependency terraform-docs to v0.18.0 15278e3 249 | * **deps:** update dependency tflint to v0.51.0 3a82ce1 250 | * **deps:** update dependency tflint to v0.51.1 9f0ee2f 251 | * **deps:** update dependency trivy to v0.51.0 f7fee1a 252 | * **deps:** update dependency trivy to v0.51.1 38f6178 253 | * **deps:** update dependency trivy to v0.51.2 819cdbb 254 | * **deps:** update dependency trivy to v0.51.4 1ec4e37 255 | * **deps:** update dependency trivy to v0.52.0 ef812ab 256 | 257 | ## 7.7.2 (2024-04-26) 258 | 259 | 260 | ### Styles 261 | 262 | * **output:** remove unused version from outputs-module 9cb5fd6 263 | 264 | 265 | ### Continuous Integration 266 | 267 | * **AZ-1391:** enable semantic-release [skip ci] 4181b16 268 | * **AZ-1391:** update semantic-release config [skip ci] 9538279 269 | 270 | 271 | ### Miscellaneous Chores 272 | 273 | * **deps:** add renovate.json 0418ae5 274 | * **deps:** enable automerge on renovate 84ab1a1 275 | * **deps:** update dependency trivy to v0.50.2 0817d82 276 | * **deps:** update dependency trivy to v0.50.4 67e261e 277 | * **deps:** update renovate.json 468ca2d 278 | * **pre-commit:** update commitlint hook 5e6cb47 279 | * **release:** remove legacy `VERSION` file bc29a21 280 | 281 | # v7.7.1 - 2024-01-12 282 | 283 | Fixed 284 | * AZ-1304: Terraform lint fixes 285 | 286 | # v7.7.0 - 2024-01-05 287 | 288 | Added 289 | * AZ-1304: Add `family` possible parameter to `elastic_pool_sku` variable. Fixes [GITHUB-4](https://github.com/claranet/terraform-azurerm-db-sql/issues/4) 290 | 291 | # v7.6.0 - 2023-12-01 292 | 293 | Added 294 | * AZ-1260: Add `sku_name` on `databases` 295 | 296 | # v7.5.0 - 2023-10-27 297 | 298 | Breaking 299 | * AZ-1226: Changed virtual network rule resource name (deprecation) in anticipation of AzureRM provider v4.0 300 | 301 | # v7.4.0 - 2023-10-20 302 | 303 | Breaking 304 | * AZ-1210: Remove `retention_days` parameters, it must be handled at destination level now. (for reference: [Provider issue](https://github.com/hashicorp/terraform-provider-azurerm/issues/23051)) 305 | 306 | # v7.3.0 - 2023-10-13 307 | 308 | Added 309 | * AZ-1204: Add `backup_interval_in_hours` on `short_term_retention parameter` 310 | 311 | # v7.2.5 - 2023-07-13 312 | 313 | Fixed 314 | * AZ-1113: Update sub-modules READMEs (according to their example) 315 | 316 | # v7.2.4 - 2023-04-26 317 | 318 | Fixed 319 | * AZ-387: Fix README 320 | * [GH-2](https://github.com/claranet/terraform-azurerm-db-sql/pull/2): Fix databases usernames 321 | 322 | # v7.2.3 - 2023-04-20 323 | 324 | Fixed 325 | * [GH-1](https://github.com/claranet/terraform-azurerm-db-sql/pull/1): Fix default collation 326 | 327 | # v7.2.2 - 2023-01-27 328 | 329 | Fixed 330 | * AZ-988: Fix wrong `elastic_pool_sku` variable description 331 | 332 | # v7.2.1 - 2022-12-23 333 | 334 | Fixed 335 | * AZ-945: Fix bug in with loop in `r-naming.tf` 336 | 337 | # v7.2.0 - 2022-11-25 338 | 339 | Breaking 340 | * AZ-908: Implement Azure CAF naming (using Microsoft provider) 341 | 342 | Changed 343 | * AZ-908: Bump `diagnostics-settings` 344 | * AZ-908: Rework and optimize module HCL code 345 | 346 | # v7.1.0 - 2022-11-18 347 | 348 | Changed 349 | * AZ-901: Change default value for `public_network_access_enabled` variable to `false` 350 | 351 | Added 352 | * AZ-896: Adding setting for users passwords 353 | 354 | Fixed 355 | * AZ-896: Fix `backup_retention` variables format 356 | 357 | Breaking 358 | * AZ-896: Replace `azurerm_sql_firewall_rule` by `azurerm_mssql_firewall_rule` 359 | 360 | # v7.0.0 - 2022-09-30 361 | 362 | Breaking 363 | * AZ-840: Update to Terraform `v1.3` 364 | 365 | Changed 366 | * AZ-843: Update to AzureRM `v3.0+` 367 | 368 | # v4.4.1 - 2022-08-12 369 | 370 | Fixed 371 | * AZ-400: Fix CI 372 | 373 | # v4.4.0 - 2022-08-12 374 | 375 | Fixed 376 | * AZ-387: Implement most of the `azurerm_mssql_database` resource parameters 377 | * AZ-387: Allow to configure specific tags per database 378 | 379 | Breaking 380 | * AZ-400: Rebuild module with new resources and simplify interface 381 | * AZ-387: Rework user creation, replace Python and pymssql dependency by Terraform provider 382 | * AZ-387: Split custom users creation in a submodule 383 | * AZ-387: Remove Powershell dependency for db backup configuration 384 | 385 | # v4.3.0 - 2022-07-01 386 | 387 | Added 388 | * AZ-615: Add an option to enable or disable default tags 389 | * AZ-770: Add Terraform module info in output 390 | 391 | Fixed 392 | * AZ-772: Fix deprecated terraform code with `v1.2.3` 393 | 394 | # v4.2.1 - 2022-01-18 395 | 396 | Fixed 397 | * AZ-669 : Fix long_term_retention_policy monthly_retention 398 | 399 | # v4.2.0 - 2021-12-28 400 | 401 | Fixed 402 | * AZ-636: Fix LTR retention settings for single databases 403 | 404 | Added 405 | * AZ-622: Allow specifying databases license type 406 | 407 | # v4.1.2 - 2021-11-23 408 | 409 | Fixed 410 | * AZ-589: Avoid plan drift when specifying Diagnostic Settings categories 411 | * AZ-600: Fix variable type for retention parameters in single database 412 | 413 | # v4.1.1 - 2021-10-19 414 | 415 | Changed 416 | * AZ-570: Bump pymssql module used for users management to v2.2.2 417 | * AZ-572: Revamp examples and improve CI 418 | 419 | # v4.1.0 - 2021-08-30 420 | 421 | Breaking 422 | * AZ-530: Cleanup module, fix linter errors 423 | 424 | Changed 425 | * AZ-532: Revamp README with latest `terraform-docs` tool 426 | 427 | # v4.0.0 - 2021-03-10 428 | 429 | Breaking 430 | * AZ-273: Use `for_each` to iterate over databases 431 | * AZ-160: Revamp diagnostic settings 432 | * AZ-351: Allow usage of vCore model 433 | * AZ-372: Deploy single database instead of elasticpool 434 | 435 | Added 436 | * AZ-354: Allow do add vnet rules 437 | * AZ-362: Allow to create custom login/users with builtin roles assigned on database 438 | 439 | Changed 440 | * AZ-273: Terraform 0.13+ compatible 441 | * AZ-398: Force lowercase on default generated name 442 | 443 | # v2.1.2/v3.0.1 - 2020-07-29 444 | 445 | Changed 446 | * AZ-243: Fix README 447 | 448 | # v2.1.1/v3.0.0 - 2020-07-13 449 | 450 | Changed 451 | * AZ-198: Update README and tag module compatible both AzureRM provider < 2.0 and >= 2.0 452 | 453 | # v2.1.0 - 2020-03-27 454 | 455 | Added 456 | * AZ-138: Allow to configure SQL Server PITR retention 457 | 458 | Changed 459 | * AZ-140: Make SQL user creation idempotent 460 | * AZ-133: Use 3rd party logging module 461 | 462 | # v2.0.0 - 2019-09-06 463 | 464 | Breaking 465 | * AZ-94: Terraform 0.12 / HCL2 format 466 | 467 | Added 468 | * AZ-107: Manage databases users creation 469 | * AZ-118: Add LICENSE, NOTICE & Github badges 470 | 471 | # v1.1.0 - 2019-06-18 472 | 473 | Changed 474 | * AZ-94: Rename `version` input to `server_version` for Terraform 0.12 compatibility 475 | 476 | # v1.0.0 - 2019-05-14 477 | 478 | Added 479 | * AZ-70: First version 480 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Azure SQL 2 | 3 | [![Changelog](https://img.shields.io/badge/changelog-release-green.svg)](CHANGELOG.md) [![Notice](https://img.shields.io/badge/notice-copyright-blue.svg)](NOTICE) [![Apache V2 License](https://img.shields.io/badge/license-Apache%20V2-orange.svg)](LICENSE) [![OpenTofu Registry](https://img.shields.io/badge/opentofu-registry-yellow.svg)](https://search.opentofu.org/module/claranet/db-sql/azurerm/) 4 | 5 | This Terraform module creates an [Azure SQL Server](https://docs.microsoft.com/en-us/azure/sql-database/sql-database-servers) 6 | and associated databases in an optional [SQL Elastic Pool](https://docs.microsoft.com/en-us/azure/sql-database/sql-database-elastic-pool) 7 | with [DTU purchasing model](https://docs.microsoft.com/en-us/azure/sql-database/sql-database-service-tiers-dtu) or [vCore purchasing model](https://docs.microsoft.com/en-us/azure/azure-sql/database/resource-limits-vcore-elastic-pools) 8 | only along with [Firewall rules](https://docs.microsoft.com/en-us/azure/sql-database/sql-database-firewall-configure) 9 | and [Diagnostic settings](https://docs.microsoft.com/en-us/azure/sql-database/sql-database-metrics-diag-logging) 10 | enabled. 11 | 12 | ## Migration from 8.x.x to 8.3.x 13 | 14 | The variable `allowed_cidr_list` variable has been renamed to `allowed_cidrs` and the resource `azurerm_mssql_firewall_rule.main` is now using a `for_each` loop to create the firewall rules (was using a `count` before). 15 | In order to migrate your state without recreating the firewall rules, you can run : 16 | 17 | ```bash 18 | tofu state rm module.sql.azurerm_mssql_firewall_rule.main 19 | ``` 20 | 21 | Then add to your IAC this code : 22 | 23 | ```hcl 24 | import { 25 | for_each = local.allowed_cidrs 26 | to = module.sql.azurerm_mssql_firewall_rule.main[each.key] 27 | id = "${nonsensitive(module.sql.resource.id)}/firewallRules/${each.key}" 28 | } 29 | ``` 30 | 31 | 32 | ## Global versioning rule for Claranet Azure modules 33 | 34 | | Module version | Terraform version | OpenTofu version | AzureRM version | 35 | | -------------- | ----------------- | ---------------- | --------------- | 36 | | >= 8.x.x | **Unverified** | 1.8.x | >= 4.0 | 37 | | >= 7.x.x | 1.3.x | | >= 3.0 | 38 | | >= 6.x.x | 1.x | | >= 3.0 | 39 | | >= 5.x.x | 0.15.x | | >= 2.0 | 40 | | >= 4.x.x | 0.13.x / 0.14.x | | >= 2.0 | 41 | | >= 3.x.x | 0.12.x | | >= 2.0 | 42 | | >= 2.x.x | 0.12.x | | < 2.0 | 43 | | < 2.x.x | 0.11.x | | < 2.0 | 44 | 45 | ## Contributing 46 | 47 | If you want to contribute to this repository, feel free to use our [pre-commit](https://pre-commit.com/) git hook configuration 48 | which will help you automatically update and format some files for you by enforcing our Terraform code module best-practices. 49 | 50 | More details are available in the [CONTRIBUTING.md](./CONTRIBUTING.md#pull-request-process) file. 51 | 52 | ## Usage 53 | 54 | This module is optimized to work with the [Claranet terraform-wrapper](https://github.com/claranet/terraform-wrapper) tool 55 | which set some terraform variables in the environment needed by this module. 56 | More details about variables set by the `terraform-wrapper` available in the [documentation](https://github.com/claranet/terraform-wrapper#environment). 57 | 58 | ⚠️ Since modules version v8.0.0, we do not maintain/check anymore the compatibility with 59 | [Hashicorp Terraform](https://github.com/hashicorp/terraform/). Instead, we recommend to use [OpenTofu](https://github.com/opentofu/opentofu/). 60 | 61 | ```hcl 62 | resource "random_password" "admin_password" { 63 | special = true 64 | override_special = "#$%&-_+{}<>:" 65 | upper = true 66 | lower = true 67 | number = true 68 | length = 32 69 | } 70 | 71 | # Elastic Pool 72 | module "sql_elastic" { 73 | source = "claranet/db-sql/azurerm" 74 | version = "x.x.x" 75 | 76 | client_name = var.client_name 77 | environment = var.environment 78 | location = module.azure_region.location 79 | location_short = module.azure_region.location_short 80 | stack = var.stack 81 | resource_group_name = module.rg.name 82 | 83 | administrator_login = "adminsqltest" 84 | administrator_password = random_password.admin_password.result 85 | create_databases_users = true 86 | 87 | elastic_pool_enabled = true 88 | elastic_pool_max_size = "50" 89 | elastic_pool_sku = { 90 | tier = "GeneralPurpose" 91 | capacity = 2 92 | } 93 | 94 | allowed_cidrs = ["1.2.3.4/32", "5.6.7.8/16"] 95 | 96 | logs_destinations_ids = [ 97 | module.logs.id, 98 | module.logs.storage_account_id, 99 | ] 100 | 101 | databases = [ 102 | { 103 | name = "db1" 104 | max_size_gb = 50 105 | }, 106 | { 107 | name = "db2" 108 | max_size_gb = 180 109 | } 110 | ] 111 | 112 | custom_users = [ 113 | { 114 | database = "db1" 115 | name = "db1_custom1" 116 | roles = ["db_accessadmin", "db_securityadmin"] 117 | }, 118 | { 119 | database = "db1" 120 | name = "db1_custom2" 121 | roles = ["db_accessadmin", "db_securityadmin"] 122 | }, 123 | { 124 | database = "db2" 125 | name = "db2_custom1" 126 | roles = [] 127 | }, 128 | { 129 | database = "db2" 130 | name = "db2_custom2" 131 | roles = ["db_accessadmin", "db_securityadmin"] 132 | } 133 | ] 134 | } 135 | 136 | # Single Database 137 | module "sql_single" { 138 | source = "claranet/db-sql/azurerm" 139 | version = "x.x.x" 140 | 141 | client_name = var.client_name 142 | environment = var.environment 143 | location = module.azure_region.location 144 | location_short = module.azure_region.location_short 145 | stack = var.stack 146 | resource_group_name = module.rg.name 147 | 148 | administrator_login = "adminsqltest" 149 | administrator_password = random_password.admin_password.result 150 | create_databases_users = true 151 | 152 | elastic_pool_enabled = false 153 | 154 | allowed_cidrs = { 155 | "foo" = "1.2.3.4/32" 156 | "bar" = "5.6.7.8/16" 157 | } 158 | 159 | logs_destinations_ids = [ 160 | module.logs.id, 161 | module.logs.storage_account_id, 162 | ] 163 | 164 | databases = [ 165 | { 166 | name = "db1" 167 | max_size_gb = 50 168 | }, 169 | { 170 | name = "db2" 171 | max_size_gb = 180 172 | } 173 | ] 174 | 175 | custom_users = [ 176 | { 177 | database = "db1" 178 | name = "db1_custom1" 179 | roles = ["db_accessadmin", "db_securityadmin"] 180 | }, 181 | { 182 | database = "db1" 183 | name = "db1_custom2" 184 | roles = ["db_accessadmin", "db_securityadmin"] 185 | }, 186 | { 187 | database = "db2" 188 | name = "db2_custom1" 189 | roles = [] 190 | }, 191 | { 192 | database = "db2" 193 | name = "db2_custom2" 194 | roles = ["db_accessadmin", "db_securityadmin"] 195 | } 196 | ] 197 | } 198 | ``` 199 | 200 | ## Providers 201 | 202 | | Name | Version | 203 | |------|---------| 204 | | azurecaf | >= 1.2.28 | 205 | | azurerm | ~> 4.31 | 206 | 207 | ## Modules 208 | 209 | | Name | Source | Version | 210 | |------|--------|---------| 211 | | custom\_users | ./modules/databases_users | n/a | 212 | | databases\_logging | claranet/diagnostic-settings/azurerm | ~> 8.2.0 | 213 | | databases\_users | ./modules/databases_users | n/a | 214 | | pool\_logging | claranet/diagnostic-settings/azurerm | ~> 8.2.0 | 215 | 216 | ## Resources 217 | 218 | | Name | Type | 219 | |------|------| 220 | | [azurerm_mssql_database.main](https://registry.terraform.io/providers/hashicorp/azurerm/latest/docs/resources/mssql_database) | resource | 221 | | [azurerm_mssql_database_extended_auditing_policy.db](https://registry.terraform.io/providers/hashicorp/azurerm/latest/docs/resources/mssql_database_extended_auditing_policy) | resource | 222 | | [azurerm_mssql_elasticpool.main](https://registry.terraform.io/providers/hashicorp/azurerm/latest/docs/resources/mssql_elasticpool) | resource | 223 | | [azurerm_mssql_firewall_rule.main](https://registry.terraform.io/providers/hashicorp/azurerm/latest/docs/resources/mssql_firewall_rule) | resource | 224 | | [azurerm_mssql_server.main](https://registry.terraform.io/providers/hashicorp/azurerm/latest/docs/resources/mssql_server) | resource | 225 | | [azurerm_mssql_server_extended_auditing_policy.main](https://registry.terraform.io/providers/hashicorp/azurerm/latest/docs/resources/mssql_server_extended_auditing_policy) | resource | 226 | | [azurerm_mssql_server_security_alert_policy.main](https://registry.terraform.io/providers/hashicorp/azurerm/latest/docs/resources/mssql_server_security_alert_policy) | resource | 227 | | [azurerm_mssql_server_vulnerability_assessment.main](https://registry.terraform.io/providers/hashicorp/azurerm/latest/docs/resources/mssql_server_vulnerability_assessment) | resource | 228 | | [azurerm_mssql_virtual_network_rule.main](https://registry.terraform.io/providers/hashicorp/azurerm/latest/docs/resources/mssql_virtual_network_rule) | resource | 229 | | [azurecaf_name.sql](https://registry.terraform.io/providers/claranet/azurecaf/latest/docs/data-sources/name) | data source | 230 | | [azurecaf_name.sql_dbs](https://registry.terraform.io/providers/claranet/azurecaf/latest/docs/data-sources/name) | data source | 231 | | [azurecaf_name.sql_pool](https://registry.terraform.io/providers/claranet/azurecaf/latest/docs/data-sources/name) | data source | 232 | 233 | ## Inputs 234 | 235 | | Name | Description | Type | Default | Required | 236 | |------|-------------|------|---------|:--------:| 237 | | administrator\_login | Administrator login for SQL Server. | `string` | n/a | yes | 238 | | administrator\_password | Administrator password for SQL Server. | `string` | n/a | yes | 239 | | alerting\_email\_addresses | List of email addresses to send reports for threat detection and vulnerability assessment. | `list(string)` | `[]` | no | 240 | | allowed\_cidrs | List/map of allowed CIDR ranges to access the SQL server. Default to all Azure services. | `any` |
{
"azure-services": "0.0.0.0/32"
}
| no | 241 | | allowed\_subnets\_ids | List of Subnet ID to allow to connect to the SQL Instance. | `list(string)` | `[]` | no | 242 | | azuread\_administrator | Azure AD Administrator configuration block of this SQL Server. |
object({
login_username = optional(string)
object_id = optional(string)
tenant_id = optional(string)
azuread_authentication_only = optional(bool)
})
| `null` | no | 243 | | backup\_retention | Definition of long term backup retention for all the databases in this SQL Server. |
object({
weekly_retention = optional(number)
monthly_retention = optional(number)
yearly_retention = optional(number)
week_of_year = optional(number)
})
| `{}` | no | 244 | | client\_name | Client name/account used in naming. | `string` | n/a | yes | 245 | | connection\_policy | The connection policy the server will use. Possible values are `Default`, `Proxy`, and `Redirect`. | `string` | `"Default"` | no | 246 | | create\_databases\_users | True to create a user named \_user on each database with generated password and role db\_owner. | `bool` | `true` | no | 247 | | custom\_users | List of objects for custom users creation.
Password are generated.
These users are created within the "custom\_users" submodule. |
list(object({
name = string
database = string
roles = optional(list(string))
}))
| `[]` | no | 248 | | databases | List of the databases configurations for this server. |
list(object({
name = string
license_type = optional(string)
sku_name = optional(string)
identity_ids = optional(list(string), [])
max_size_gb = optional(number)
create_mode = optional(string)
min_capacity = optional(number)
auto_pause_delay_in_minutes = optional(number)
read_scale = optional(string)
read_replica_count = optional(number)
creation_source_database_id = optional(string)
restore_point_in_time = optional(string)
recover_database_id = optional(string)
restore_dropped_database_id = optional(string)
collation = optional(string)
storage_account_type = optional(string, "Geo")
database_extra_tags = optional(map(string), {})
}))
| `[]` | no | 249 | | databases\_collation | SQL Collation for the databases. | `string` | `"SQL_Latin1_General_CP1_CI_AS"` | no | 250 | | databases\_extended\_auditing\_enabled | True to enable extended auditing for SQL databases. | `bool` | `false` | no | 251 | | databases\_extended\_auditing\_retention\_days | Databases extended auditing logs retention. | `number` | `30` | no | 252 | | databases\_zone\_redundant | True to have databases zone redundant, which means the replicas of the databases will be spread across multiple availability zones. This property is only settable for `Premium` and `Business Critical` databases. | `bool` | `null` | no | 253 | | default\_tags\_enabled | Option to enable or disable default tags. | `bool` | `true` | no | 254 | | diagnostic\_settings\_custom\_name | Custom name of the diagnostics settings, name will be `default` if not set. | `string` | `"default"` | no | 255 | | elastic\_pool\_custom\_name | Name of the SQL Elastic Pool, generated if not set. | `string` | `""` | no | 256 | | elastic\_pool\_databases\_max\_capacity | The maximum capacity (DTU or vCore) any one database can consume in the Elastic Pool. Default to the max Elastic Pool capacity. | `number` | `null` | no | 257 | | elastic\_pool\_databases\_min\_capacity | The minimum capacity (DTU or vCore) all databases are guaranteed in the Elastic Pool. Defaults to 0. | `number` | `0` | no | 258 | | elastic\_pool\_enabled | True to deploy the databases in an ElasticPool, single databases are deployed otherwise. | `bool` | `false` | no | 259 | | elastic\_pool\_extra\_tags | Extra tags to add on ElasticPool. | `map(string)` | `{}` | no | 260 | | elastic\_pool\_license\_type | Specifies the license type applied to this database. Possible values are `LicenseIncluded` and `BasePrice`. | `string` | `null` | no | 261 | | elastic\_pool\_max\_size | Maximum size of the Elastic Pool in gigabytes. | `string` | `null` | no | 262 | | elastic\_pool\_sku | SKU for the Elastic Pool with tier and eDTUs capacity. Premium tier with zone redundancy is mandatory for high availability.
Possible values for tier are `GeneralPurpose`, `BusinessCritical` for vCore models and `Basic`, `Standard`, or `Premium` for DTU based models.
See [documentation](https://learn.microsoft.com/en-us/azure/azure-sql/database/resource-limits-dtu-elastic-pools?view=azuresql)." |
object({
tier = string,
capacity = number,
family = optional(string, "Gen5")
})
| `null` | no | 263 | | elastic\_pool\_zone\_redundant | True to have the Elastic Pool zone redundant, SKU tier must be Premium to use it. This is mandatory for high availability. | `bool` | `false` | no | 264 | | environment | Project environment. | `string` | n/a | yes | 265 | | express\_vulnerability\_assessment\_enabled | True to enable express vulnerability assessment for this SQL Server. | `bool` | `false` | no | 266 | | extra\_tags | Extra tags to add. | `map(string)` | `{}` | no | 267 | | identity | Identity block information. |
object({
type = optional(string, "SystemAssigned")
identity_ids = optional(list(string))
})
| `{}` | no | 268 | | location | Azure location. | `string` | n/a | yes | 269 | | location\_short | Short string for Azure location. | `string` | n/a | yes | 270 | | logs\_categories | Log categories to send to destinations. | `list(string)` | `null` | no | 271 | | logs\_destinations\_ids | List of destination resources IDs for logs diagnostic destination.
Can be `Storage Account`, `Log Analytics Workspace` and `Event Hub`. No more than one of each can be set.
If you want to use Azure EventHub as a destination, you must provide a formatted string containing both the EventHub Namespace authorization send ID and the EventHub name (name of the queue to use in the Namespace) separated by the | character. | `list(string)` | n/a | yes | 272 | | logs\_metrics\_categories | Metrics categories to send to destinations. | `list(string)` | `null` | no | 273 | | name\_prefix | Optional prefix for the generated name. | `string` | `""` | no | 274 | | name\_suffix | Optional suffix for the generated name. | `string` | `""` | no | 275 | | outbound\_network\_restriction\_enabled | Whether outbound network traffic is restricted for this server. | `bool` | `false` | no | 276 | | point\_in\_time\_backup\_interval\_in\_hours | The hours between each differential backup. This is only applicable to live databases but not dropped databases. Value has to be 12 or 24. Defaults to 12 hours. | `number` | `12` | no | 277 | | point\_in\_time\_restore\_retention\_days | Point In Time Restore configuration. Value has to be between `7` and `35`. | `number` | `7` | no | 278 | | primary\_user\_assigned\_identity\_id | Specifies the primary user managed identity id. Required if type within the identity block is set to either SystemAssigned, UserAssigned or UserAssigned and should be set at same time as setting identity\_ids. | `string` | `null` | no | 279 | | public\_network\_access\_enabled | True to allow public network access for this server. | `bool` | `false` | no | 280 | | resource\_group\_name | Resource group name. | `string` | n/a | yes | 281 | | security\_storage\_account\_access\_key | Storage Account access key used to store security logs and reports. | `string` | `null` | no | 282 | | security\_storage\_account\_blob\_endpoint | Storage Account blob endpoint used to store security logs and reports. | `string` | `null` | no | 283 | | security\_storage\_account\_container\_name | Storage Account container name where to store SQL Server vulnerability assessment. | `string` | `null` | no | 284 | | server\_custom\_name | Name of the SQL Server, generated if not set. | `string` | `""` | no | 285 | | server\_extra\_tags | Extra tags to add on SQL Server or ElasticPool. | `map(string)` | `{}` | no | 286 | | server\_version | Version of the SQL Server. Valid values are: 2.0 (for v11 server) and 12.0 (for v12 server). See [documentation](https://registry.terraform.io/providers/hashicorp/azurerm/latest/docs/resources/mssql_server#version-1). | `string` | `"12.0"` | no | 287 | | single\_databases\_sku\_name | Specifies the name of the SKU used by the database. For example, `GP_S_Gen5_2`, `HS_Gen4_1`, `BC_Gen5_2`. Use only if `elastic_pool_enabled` variable is set to `false`. More documentation [here](https://docs.microsoft.com/en-us/azure/azure-sql/database/service-tiers-general-purpose-business-critical) | `string` | `"GP_Gen5_2"` | no | 288 | | sql\_server\_extended\_auditing\_enabled | True to enable extended auditing for SQL Server. | `bool` | `false` | no | 289 | | sql\_server\_extended\_auditing\_retention\_days | Server extended auditing logs retention. | `number` | `30` | no | 290 | | sql\_server\_security\_alerting\_enabled | True to enable security alerting for this SQL Server. | `bool` | `false` | no | 291 | | sql\_server\_vulnerability\_assessment\_enabled | True to enable classic vulnerability assessment for this SQL Server. | `bool` | `false` | no | 292 | | stack | Project stack name. | `string` | n/a | yes | 293 | | threat\_detection\_policy\_disabled\_alerts | Specifies a list of alerts which should be disabled. Possible values include `Access_Anomaly`, `Sql_Injection` and `Sql_Injection_Vulnerability`. | `list(string)` | `[]` | no | 294 | | threat\_detection\_policy\_enabled | True to enable thread detection policy on the databases. | `bool` | `false` | no | 295 | | threat\_detection\_policy\_retention\_days | Specifies the number of days to keep in the Threat Detection audit logs. | `number` | `7` | no | 296 | | tls\_minimum\_version | The TLS minimum version for all SQL Database associated with the server. Valid values are: `1.0`, `1.1` and `1.2`. | `string` | `"1.2"` | no | 297 | | use\_caf\_naming\_for\_databases | Use the Azure CAF naming provider to generate databases names. | `bool` | `false` | no | 298 | 299 | ## Outputs 300 | 301 | | Name | Description | 302 | |------|-------------| 303 | | administrator\_login | SQL Administrator login. | 304 | | administrator\_password | SQL Administrator password. | 305 | | custom\_databases\_users | Map of the custom SQL Databases users | 306 | | custom\_databases\_users\_roles | Map of the custom SQL Databases users roles | 307 | | databases\_id | Map of the SQL Databases names => IDs. | 308 | | databases\_resource | SQL Databases resource list. | 309 | | default\_administrator\_databases\_connection\_strings | Map of the SQL Databases with administrator credentials connection strings | 310 | | default\_databases\_users | Map of the SQL Databases dedicated users | 311 | | elastic\_pool\_id | ID of the SQL Elastic Pool. | 312 | | elastic\_pool\_resource | SQL Elastic Pool resource. | 313 | | identity\_principal\_id | SQL Server system identity principal ID. | 314 | | resource | SQL Server resource object. | 315 | | security\_alert\_policy\_id | ID of the MS SQL Server Security Alert Policy | 316 | | terraform\_module | Information about this Terraform module. | 317 | | vulnerability\_assessment\_id | ID of the MS SQL Server Vulnerability Assessment. | 318 | 319 | 320 | ## Related documentation 321 | 322 | Microsoft Azure root documentation: [docs.microsoft.com/en-us/azure/sql-database/](https://docs.microsoft.com/en-us/azure/sql-database/) 323 | --------------------------------------------------------------------------------