├── .commitlintrc.yml ├── .config ├── terraform-docs.yml └── tflint.hcl ├── .github ├── CODEOWNERS ├── ISSUE_TEMPLATE │ ├── Bug_Report.yml │ ├── Documentation.yml │ ├── Feature_Request.yml │ └── config.yml ├── pull_request_template.md └── workflows │ └── github-ci.yml ├── .gitignore ├── .gitlab-ci.yml ├── .gitlab └── merge_request_templates │ └── default.md ├── .pre-commit-config.yaml ├── .releaserc ├── .tool-versions ├── CHANGELOG.md ├── CONTRIBUTING.md ├── LICENSE ├── NOTICE ├── README.md ├── d-naming.tf ├── examples ├── databases_users │ ├── base.tf │ ├── modules.tf │ ├── variables.tf │ └── versions.tf └── main │ ├── base.tf │ ├── modules.tf │ ├── variables.tf │ └── versions.tf ├── locals-naming.tf ├── locals-tags.tf ├── locals.tf ├── m-logs.tf ├── modules └── databases_users │ ├── README.md │ ├── outputs.tf │ ├── providers.tf │ ├── r-users.tf │ ├── terraform.tfvars.ci │ ├── variables.tf │ ├── versions.tf │ └── versions.tofu ├── outputs.tf ├── providers.tf ├── r-db.tf ├── r-security.tf ├── r-sql.tf ├── r-users.tf ├── renovate.json ├── terraform.tfvars.ci ├── variables-logs.tf ├── variables-naming.tf ├── variables-tags.tf ├── variables.tf ├── versions.tf └── versions.tofu /.commitlintrc.yml: -------------------------------------------------------------------------------- 1 | extends: 2 | - '@commitlint/config-conventional' 3 | rules: 4 | header-max-length: [0, "always", 120] 5 | -------------------------------------------------------------------------------- /.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 | -------------------------------------------------------------------------------- /.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 | -------------------------------------------------------------------------------- /.github/CODEOWNERS: -------------------------------------------------------------------------------- 1 | * @bzspi @shr3ps @rossifumax @jmapro @maxpoullain 2 | -------------------------------------------------------------------------------- /.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 | -------------------------------------------------------------------------------- /.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 | -------------------------------------------------------------------------------- /.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 | -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/config.yml: -------------------------------------------------------------------------------- 1 | blank_issues_enabled: false 2 | -------------------------------------------------------------------------------- /.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 | -------------------------------------------------------------------------------- /.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 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | .terraform 2 | .terraform.lock.hcl 3 | main.tf 4 | terraform.tfvars 5 | !examples/**/main.tf 6 | !examples/**/terraform.tfvars 7 | -------------------------------------------------------------------------------- /.gitlab-ci.yml: -------------------------------------------------------------------------------- 1 | --- 2 | variables: 3 | TF_MIN_VERSION: "1.8" 4 | AZURERM_PROVIDER_MIN_VERSION: "4.0" 5 | 6 | include: 7 | - project: 'claranet/projects/cloud/azure/terraform/ci' 8 | ref: master 9 | file: '/pipeline.yml' 10 | ... 11 | -------------------------------------------------------------------------------- /.gitlab/merge_request_templates/default.md: -------------------------------------------------------------------------------- 1 | @ldap-sync/FR-Git-Cellule-Cloud-Azure 2 | -------------------------------------------------------------------------------- /.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: v5.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.0 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/alessandrojcm/commitlint-pre-commit-hook 54 | rev: v9.22.0 55 | hooks: 56 | - id: commitlint 57 | stages: [commit-msg] 58 | additional_dependencies: ["@commitlint/config-conventional"] 59 | -------------------------------------------------------------------------------- /.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 | -------------------------------------------------------------------------------- /.tool-versions: -------------------------------------------------------------------------------- 1 | pre-commit 4.2.0 2 | opentofu 1.9.1 3 | terraform-docs 0.20.0 4 | tflint 0.58.0 5 | trivy 0.63.0 6 | -------------------------------------------------------------------------------- /CHANGELOG.md: -------------------------------------------------------------------------------- 1 | ## 8.3.0 (2025-06-06) 2 | 3 | ### Features 4 | 5 | * **AZ-1568:** add variable allowed_cidrs c1577bd 6 | 7 | ### Miscellaneous Chores 8 | 9 | * **deps:** update dependency opentofu to v1.9.1 0303d59 10 | * **deps:** update dependency tflint to v0.57.0 f08a408 11 | * **deps:** update dependency tflint to v0.58.0 9315bba 12 | * **deps:** update dependency trivy to v0.62.0 1ebdb96 13 | * **deps:** update dependency trivy to v0.62.1 b994fce 14 | * **deps:** update dependency trivy to v0.63.0 74b2a1e 15 | 16 | ## 8.2.1 (2025-04-22) 17 | 18 | ### Bug Fixes 19 | 20 | * 🐛 add missing primary_user_assigned_identity_id parameter required for UserAssigned identity b097db0 21 | * 🐛 null error 55bc345 22 | 23 | ### Documentation 24 | 25 | * 📚️ update README 0faa585 26 | * description dot a0af195 27 | 28 | ### Miscellaneous Chores 29 | 30 | * **deps:** update dependency trivy to v0.61.1 10e8b2e 31 | 32 | ## 8.2.0 (2025-04-18) 33 | 34 | ### Features 35 | 36 | * **GH-3:** merge single_database and elastic_pools 3872098 37 | 38 | ### Code Refactoring 39 | 40 | * **GH-3:** revamp module c48ad05 41 | 42 | ### Miscellaneous Chores 43 | 44 | * moved blocks fffedf1 45 | 46 | ## 8.1.1 (2025-04-14) 47 | 48 | ### Bug Fixes 49 | 50 | * parametrize SQL DB identity ([#9](https://git.fr.clara.net/claranet/projects/cloud/azure/terraform/modules/db-sql/issues/9)) 4169302 51 | 52 | ### Documentation 53 | 54 | * **GH-9:** update README 9f1b77f 55 | 56 | ## 8.1.0 (2025-04-14) 57 | 58 | ### Features 59 | 60 | * **GH-7:** add option to modify SQL server identity 08b98b1 61 | * unhardcode SQL server identity 848122b 62 | 63 | ### Code Refactoring 64 | 65 | * code lint 40638ab 66 | 67 | ### Miscellaneous Chores 68 | 69 | * **deps:** update dependency pre-commit to v4.2.0 9a89513 70 | * **deps:** update dependency terraform-docs to v0.20.0 7f33940 71 | * **deps:** update dependency tflint to v0.55.1 1c2ea43 72 | * **deps:** update dependency trivy to v0.59.0 6ff6f63 73 | * **deps:** update dependency trivy to v0.59.1 f58c891 74 | * **deps:** update dependency trivy to v0.60.0 3220d91 75 | * **deps:** update pre-commit hook alessandrojcm/commitlint-pre-commit-hook to v9.21.0 7e9b69f 76 | * **deps:** update pre-commit hook alessandrojcm/commitlint-pre-commit-hook to v9.22.0 271b542 77 | * **deps:** update pre-commit hook tofuutils/pre-commit-opentofu to v2.2.0 5fce321 78 | * **deps:** update terraform mssql to ~> 0.3.0 752d22c 79 | * **deps:** update tools 54f875f 80 | * update Github templates de4cc08 81 | 82 | ## 8.0.0 (2025-01-31) 83 | 84 | ### ⚠ BREAKING CHANGES 85 | 86 | * **AZ-1088:** module v8 structure and updates 87 | 88 | ### Features 89 | 90 | * **AZ-1088:** module v8 structure and updates f1bba72 91 | 92 | ### Miscellaneous Chores 93 | 94 | * **deps:** update dependency claranet/diagnostic-settings/azurerm to v7 2dada57 95 | * **deps:** update dependency opentofu to v1.8.3 19bcc58 96 | * **deps:** update dependency opentofu to v1.8.4 fe9a947 97 | * **deps:** update dependency opentofu to v1.8.6 ef69712 98 | * **deps:** update dependency opentofu to v1.8.8 4b5f1f9 99 | * **deps:** update dependency opentofu to v1.9.0 d26595f 100 | * **deps:** update dependency pre-commit to v4 bc6c3ad 101 | * **deps:** update dependency pre-commit to v4.1.0 7a36210 102 | * **deps:** update dependency tflint to v0.54.0 6da88c5 103 | * **deps:** update dependency tflint to v0.55.0 448f3be 104 | * **deps:** update dependency trivy to v0.56.1 287ebc5 105 | * **deps:** update dependency trivy to v0.56.2 dae1e99 106 | * **deps:** update dependency trivy to v0.57.1 ec288f3 107 | * **deps:** update dependency trivy to v0.58.1 0c83981 108 | * **deps:** update dependency trivy to v0.58.2 c3bb0d9 109 | * **deps:** update pre-commit hook alessandrojcm/commitlint-pre-commit-hook to v9.19.0 154b211 110 | * **deps:** update pre-commit hook alessandrojcm/commitlint-pre-commit-hook to v9.20.0 6c70802 111 | * **deps:** update pre-commit hook pre-commit/pre-commit-hooks to v5 9181a9f 112 | * **deps:** update pre-commit hook tofuutils/pre-commit-opentofu to v2.1.0 8a6c345 113 | * **deps:** update tools 037d46f 114 | * **deps:** update tools 124b78d 115 | * prepare for new examples structure 7c17e42 116 | * update examples structure 46105cb 117 | * update submodule READMEs with latest template 90932ed 118 | * update tflint config for v0.55.0 52f5770 119 | 120 | ## 7.12.0 (2024-10-03) 121 | 122 | ### Features 123 | 124 | * use Claranet "azurecaf" provider e34bdec 125 | 126 | ### Documentation 127 | 128 | * update README badge to use OpenTofu registry 1fb419b 129 | * update README with `terraform-docs` v0.19.0 7cfbae4 130 | 131 | ### Miscellaneous Chores 132 | 133 | * **deps:** update dependency opentofu to v1.7.3 82ae5cd 134 | * **deps:** update dependency opentofu to v1.8.0 a3ff664 135 | * **deps:** update dependency opentofu to v1.8.1 8e0aec1 136 | * **deps:** update dependency pre-commit to v3.8.0 6f0a6ac 137 | * **deps:** update dependency tflint to v0.52.0 633cd0c 138 | * **deps:** update dependency tflint to v0.53.0 793bc42 139 | * **deps:** update dependency trivy to v0.54.1 1486980 140 | * **deps:** update dependency trivy to v0.55.0 06b2d88 141 | * **deps:** update dependency trivy to v0.55.1 687d11d 142 | * **deps:** update dependency trivy to v0.55.2 9e4ba99 143 | * **deps:** update dependency trivy to v0.56.0 6a62a35 144 | * **deps:** update pre-commit hook alessandrojcm/commitlint-pre-commit-hook to v9.17.0 7186fd4 145 | * **deps:** update pre-commit hook alessandrojcm/commitlint-pre-commit-hook to v9.18.0 6b50794 146 | * **deps:** update pre-commit hook antonbabenko/pre-commit-terraform to v1.92.1 0db7dda 147 | * **deps:** update pre-commit hook antonbabenko/pre-commit-terraform to v1.92.2 8a48961 148 | * **deps:** update pre-commit hook antonbabenko/pre-commit-terraform to v1.92.3 98b7b4c 149 | * **deps:** update pre-commit hook antonbabenko/pre-commit-terraform to v1.93.0 ffb830d 150 | * **deps:** update pre-commit hook antonbabenko/pre-commit-terraform to v1.94.0 82ef21c 151 | * **deps:** update pre-commit hook antonbabenko/pre-commit-terraform to v1.94.1 ea33d3e 152 | * **deps:** update pre-commit hook antonbabenko/pre-commit-terraform to v1.94.3 5bdc9f4 153 | * **deps:** update pre-commit hook antonbabenko/pre-commit-terraform to v1.95.0 2eca800 154 | * **deps:** update pre-commit hook antonbabenko/pre-commit-terraform to v1.96.0 a77a077 155 | * **deps:** update tools 71f83c5 156 | * **deps:** update tools 0b3a3e4 157 | 158 | ## 7.11.0 (2024-07-05) 159 | 160 | 161 | ### Features 162 | 163 | * **AZ-1434:** add collation elastic pool db c73aa63 164 | 165 | 166 | ### Miscellaneous Chores 167 | 168 | * **deps:** update dependency tflint to v0.51.2 df311d5 169 | * **deps:** update dependency trivy to v0.53.0 d8f5af0 170 | 171 | ## 7.10.0 (2024-06-21) 172 | 173 | 174 | ### Features 175 | 176 | * **AZ-1426:** add parameters for elastic and single databases 4d3376a 177 | 178 | 179 | ### Miscellaneous Chores 180 | 181 | * **deps:** update dependency trivy to v0.52.2 b691eb7 182 | * **deps:** update pre-commit hook antonbabenko/pre-commit-terraform to v1.92.0 3ce3620 183 | 184 | ## 7.9.0 (2024-06-14) 185 | 186 | 187 | ### Features 188 | 189 | * add hyperscale tier support for elastic pool b2ca9f8 190 | 191 | 192 | ### Miscellaneous Chores 193 | 194 | * **deps:** update dependency trivy to v0.52.1 875e687 195 | 196 | ## 7.8.0 (2024-06-07) 197 | 198 | 199 | ### Features 200 | 201 | * optional max_size_gb for databases configuration e11be1b 202 | 203 | 204 | ### Miscellaneous Chores 205 | 206 | * **deps:** update dependency opentofu to v1.7.0 4a3997e 207 | * **deps:** update dependency opentofu to v1.7.1 638f40e 208 | * **deps:** update dependency opentofu to v1.7.2 736d4a7 209 | * **deps:** update dependency pre-commit to v3.7.1 836d380 210 | * **deps:** update dependency terraform-docs to v0.18.0 15278e3 211 | * **deps:** update dependency tflint to v0.51.0 3a82ce1 212 | * **deps:** update dependency tflint to v0.51.1 9f0ee2f 213 | * **deps:** update dependency trivy to v0.51.0 f7fee1a 214 | * **deps:** update dependency trivy to v0.51.1 38f6178 215 | * **deps:** update dependency trivy to v0.51.2 819cdbb 216 | * **deps:** update dependency trivy to v0.51.4 1ec4e37 217 | * **deps:** update dependency trivy to v0.52.0 ef812ab 218 | 219 | ## 7.7.2 (2024-04-26) 220 | 221 | 222 | ### Styles 223 | 224 | * **output:** remove unused version from outputs-module 9cb5fd6 225 | 226 | 227 | ### Continuous Integration 228 | 229 | * **AZ-1391:** enable semantic-release [skip ci] 4181b16 230 | * **AZ-1391:** update semantic-release config [skip ci] 9538279 231 | 232 | 233 | ### Miscellaneous Chores 234 | 235 | * **deps:** add renovate.json 0418ae5 236 | * **deps:** enable automerge on renovate 84ab1a1 237 | * **deps:** update dependency trivy to v0.50.2 0817d82 238 | * **deps:** update dependency trivy to v0.50.4 67e261e 239 | * **deps:** update renovate.json 468ca2d 240 | * **pre-commit:** update commitlint hook 5e6cb47 241 | * **release:** remove legacy `VERSION` file bc29a21 242 | 243 | # v7.7.1 - 2024-01-12 244 | 245 | Fixed 246 | * AZ-1304: Terraform lint fixes 247 | 248 | # v7.7.0 - 2024-01-05 249 | 250 | Added 251 | * AZ-1304: Add `family` possible parameter to `elastic_pool_sku` variable. Fixes [GITHUB-4](https://github.com/claranet/terraform-azurerm-db-sql/issues/4) 252 | 253 | # v7.6.0 - 2023-12-01 254 | 255 | Added 256 | * AZ-1260: Add `sku_name` on `databases` 257 | 258 | # v7.5.0 - 2023-10-27 259 | 260 | Breaking 261 | * AZ-1226: Changed virtual network rule resource name (deprecation) in anticipation of AzureRM provider v4.0 262 | 263 | # v7.4.0 - 2023-10-20 264 | 265 | Breaking 266 | * 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)) 267 | 268 | # v7.3.0 - 2023-10-13 269 | 270 | Added 271 | * AZ-1204: Add `backup_interval_in_hours` on `short_term_retention parameter` 272 | 273 | # v7.2.5 - 2023-07-13 274 | 275 | Fixed 276 | * AZ-1113: Update sub-modules READMEs (according to their example) 277 | 278 | # v7.2.4 - 2023-04-26 279 | 280 | Fixed 281 | * AZ-387: Fix README 282 | * [GH-2](https://github.com/claranet/terraform-azurerm-db-sql/pull/2): Fix databases usernames 283 | 284 | # v7.2.3 - 2023-04-20 285 | 286 | Fixed 287 | * [GH-1](https://github.com/claranet/terraform-azurerm-db-sql/pull/1): Fix default collation 288 | 289 | # v7.2.2 - 2023-01-27 290 | 291 | Fixed 292 | * AZ-988: Fix wrong `elastic_pool_sku` variable description 293 | 294 | # v7.2.1 - 2022-12-23 295 | 296 | Fixed 297 | * AZ-945: Fix bug in with loop in `r-naming.tf` 298 | 299 | # v7.2.0 - 2022-11-25 300 | 301 | Breaking 302 | * AZ-908: Implement Azure CAF naming (using Microsoft provider) 303 | 304 | Changed 305 | * AZ-908: Bump `diagnostics-settings` 306 | * AZ-908: Rework and optimize module HCL code 307 | 308 | # v7.1.0 - 2022-11-18 309 | 310 | Changed 311 | * AZ-901: Change default value for `public_network_access_enabled` variable to `false` 312 | 313 | Added 314 | * AZ-896: Adding setting for users passwords 315 | 316 | Fixed 317 | * AZ-896: Fix `backup_retention` variables format 318 | 319 | Breaking 320 | * AZ-896: Replace `azurerm_sql_firewall_rule` by `azurerm_mssql_firewall_rule` 321 | 322 | # v7.0.0 - 2022-09-30 323 | 324 | Breaking 325 | * AZ-840: Update to Terraform `v1.3` 326 | 327 | Changed 328 | * AZ-843: Update to AzureRM `v3.0+` 329 | 330 | # v4.4.1 - 2022-08-12 331 | 332 | Fixed 333 | * AZ-400: Fix CI 334 | 335 | # v4.4.0 - 2022-08-12 336 | 337 | Fixed 338 | * AZ-387: Implement most of the `azurerm_mssql_database` resource parameters 339 | * AZ-387: Allow to configure specific tags per database 340 | 341 | Breaking 342 | * AZ-400: Rebuild module with new resources and simplify interface 343 | * AZ-387: Rework user creation, replace Python and pymssql dependency by Terraform provider 344 | * AZ-387: Split custom users creation in a submodule 345 | * AZ-387: Remove Powershell dependency for db backup configuration 346 | 347 | # v4.3.0 - 2022-07-01 348 | 349 | Added 350 | * AZ-615: Add an option to enable or disable default tags 351 | * AZ-770: Add Terraform module info in output 352 | 353 | Fixed 354 | * AZ-772: Fix deprecated terraform code with `v1.2.3` 355 | 356 | # v4.2.1 - 2022-01-18 357 | 358 | Fixed 359 | * AZ-669 : Fix long_term_retention_policy monthly_retention 360 | 361 | # v4.2.0 - 2021-12-28 362 | 363 | Fixed 364 | * AZ-636: Fix LTR retention settings for single databases 365 | 366 | Added 367 | * AZ-622: Allow specifying databases license type 368 | 369 | # v4.1.2 - 2021-11-23 370 | 371 | Fixed 372 | * AZ-589: Avoid plan drift when specifying Diagnostic Settings categories 373 | * AZ-600: Fix variable type for retention parameters in single database 374 | 375 | # v4.1.1 - 2021-10-19 376 | 377 | Changed 378 | * AZ-570: Bump pymssql module used for users management to v2.2.2 379 | * AZ-572: Revamp examples and improve CI 380 | 381 | # v4.1.0 - 2021-08-30 382 | 383 | Breaking 384 | * AZ-530: Cleanup module, fix linter errors 385 | 386 | Changed 387 | * AZ-532: Revamp README with latest `terraform-docs` tool 388 | 389 | # v4.0.0 - 2021-03-10 390 | 391 | Breaking 392 | * AZ-273: Use `for_each` to iterate over databases 393 | * AZ-160: Revamp diagnostic settings 394 | * AZ-351: Allow usage of vCore model 395 | * AZ-372: Deploy single database instead of elasticpool 396 | 397 | Added 398 | * AZ-354: Allow do add vnet rules 399 | * AZ-362: Allow to create custom login/users with builtin roles assigned on database 400 | 401 | Changed 402 | * AZ-273: Terraform 0.13+ compatible 403 | * AZ-398: Force lowercase on default generated name 404 | 405 | # v2.1.2/v3.0.1 - 2020-07-29 406 | 407 | Changed 408 | * AZ-243: Fix README 409 | 410 | # v2.1.1/v3.0.0 - 2020-07-13 411 | 412 | Changed 413 | * AZ-198: Update README and tag module compatible both AzureRM provider < 2.0 and >= 2.0 414 | 415 | # v2.1.0 - 2020-03-27 416 | 417 | Added 418 | * AZ-138: Allow to configure SQL Server PITR retention 419 | 420 | Changed 421 | * AZ-140: Make SQL user creation idempotent 422 | * AZ-133: Use 3rd party logging module 423 | 424 | # v2.0.0 - 2019-09-06 425 | 426 | Breaking 427 | * AZ-94: Terraform 0.12 / HCL2 format 428 | 429 | Added 430 | * AZ-107: Manage databases users creation 431 | * AZ-118: Add LICENSE, NOTICE & Github badges 432 | 433 | # v1.1.0 - 2019-06-18 434 | 435 | Changed 436 | * AZ-94: Rename `version` input to `server_version` for Terraform 0.12 compatibility 437 | 438 | # v1.0.0 - 2019-05-14 439 | 440 | Added 441 | * AZ-70: First version 442 | -------------------------------------------------------------------------------- /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 | -------------------------------------------------------------------------------- /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 | -------------------------------------------------------------------------------- /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 | -------------------------------------------------------------------------------- /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.0 | 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.0.0 | 213 | | databases\_users | ./modules/databases_users | n/a | 214 | | pool\_logging | claranet/diagnostic-settings/azurerm | ~> 8.0.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 | | extra\_tags | Extra tags to add. | `map(string)` | `{}` | no | 266 | | identity | Identity block information. |
object({
type = optional(string, "SystemAssigned")
identity_ids = optional(list(string))
})
| `{}` | no | 267 | | location | Azure location. | `string` | n/a | yes | 268 | | location\_short | Short string for Azure location. | `string` | n/a | yes | 269 | | logs\_categories | Log categories to send to destinations. | `list(string)` | `null` | no | 270 | | 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 | 271 | | logs\_metrics\_categories | Metrics categories to send to destinations. | `list(string)` | `null` | no | 272 | | name\_prefix | Optional prefix for the generated name. | `string` | `""` | no | 273 | | name\_suffix | Optional suffix for the generated name. | `string` | `""` | no | 274 | | outbound\_network\_restriction\_enabled | Whether outbound network traffic is restricted for this server. | `bool` | `false` | no | 275 | | 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 | 276 | | point\_in\_time\_restore\_retention\_days | Point In Time Restore configuration. Value has to be between `7` and `35`. | `number` | `7` | no | 277 | | 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 | 278 | | public\_network\_access\_enabled | True to allow public network access for this server. | `bool` | `false` | no | 279 | | resource\_group\_name | Resource group name. | `string` | n/a | yes | 280 | | security\_storage\_account\_access\_key | Storage Account access key used to store security logs and reports. | `string` | `null` | no | 281 | | security\_storage\_account\_blob\_endpoint | Storage Account blob endpoint used to store security logs and reports. | `string` | `null` | no | 282 | | security\_storage\_account\_container\_name | Storage Account container name where to store SQL Server vulnerability assessment. | `string` | `null` | no | 283 | | server\_custom\_name | Name of the SQL Server, generated if not set. | `string` | `""` | no | 284 | | server\_extra\_tags | Extra tags to add on SQL Server or ElasticPool. | `map(string)` | `{}` | no | 285 | | 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 | 286 | | 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 | 287 | | sql\_server\_extended\_auditing\_enabled | True to enable extended auditing for SQL Server. | `bool` | `false` | no | 288 | | sql\_server\_extended\_auditing\_retention\_days | Server extended auditing logs retention. | `number` | `30` | no | 289 | | sql\_server\_security\_alerting\_enabled | True to enable security alerting for this SQL Server. | `bool` | `false` | no | 290 | | sql\_server\_vulnerability\_assessment\_enabled | True to enable vulnerability assessment for this SQL Server. | `bool` | `false` | no | 291 | | stack | Project stack name. | `string` | n/a | yes | 292 | | 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 | 293 | | threat\_detection\_policy\_enabled | True to enable thread detection policy on the databases. | `bool` | `false` | no | 294 | | threat\_detection\_policy\_retention\_days | Specifies the number of days to keep in the Threat Detection audit logs. | `number` | `7` | no | 295 | | 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 | 296 | | use\_caf\_naming\_for\_databases | Use the Azure CAF naming provider to generate databases names. | `bool` | `false` | no | 297 | 298 | ## Outputs 299 | 300 | | Name | Description | 301 | |------|-------------| 302 | | administrator\_login | SQL Administrator login. | 303 | | administrator\_password | SQL Administrator password. | 304 | | custom\_databases\_users | Map of the custom SQL Databases users | 305 | | custom\_databases\_users\_roles | Map of the custom SQL Databases users roles | 306 | | databases\_id | Map of the SQL Databases names => IDs. | 307 | | databases\_resource | SQL Databases resource list. | 308 | | default\_administrator\_databases\_connection\_strings | Map of the SQL Databases with administrator credentials connection strings | 309 | | default\_databases\_users | Map of the SQL Databases dedicated users | 310 | | elastic\_pool\_id | ID of the SQL Elastic Pool. | 311 | | elastic\_pool\_resource | SQL Elastic Pool resource. | 312 | | identity\_principal\_id | SQL Server system identity principal ID. | 313 | | resource | SQL Server resource object. | 314 | | security\_alert\_policy\_id | ID of the MS SQL Server Security Alert Policy | 315 | | terraform\_module | Information about this Terraform module. | 316 | | vulnerability\_assessment\_id | ID of the MS SQL Server Vulnerability Assessment. | 317 | 318 | 319 | ## Related documentation 320 | 321 | Microsoft Azure root documentation: [docs.microsoft.com/en-us/azure/sql-database/](https://docs.microsoft.com/en-us/azure/sql-database/) 322 | -------------------------------------------------------------------------------- /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 | -------------------------------------------------------------------------------- /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 | -------------------------------------------------------------------------------- /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 | -------------------------------------------------------------------------------- /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 | -------------------------------------------------------------------------------- /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 | -------------------------------------------------------------------------------- /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/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 | -------------------------------------------------------------------------------- /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/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 | -------------------------------------------------------------------------------- /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 | -------------------------------------------------------------------------------- /locals-tags.tf: -------------------------------------------------------------------------------- 1 | locals { 2 | default_tags = var.default_tags_enabled ? { 3 | env = var.environment 4 | stack = var.stack 5 | } : {} 6 | } 7 | -------------------------------------------------------------------------------- /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 | -------------------------------------------------------------------------------- /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.0.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.0.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/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 | -------------------------------------------------------------------------------- /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 | -------------------------------------------------------------------------------- /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 | -------------------------------------------------------------------------------- /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 | -------------------------------------------------------------------------------- /modules/databases_users/terraform.tfvars.ci: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/claranet/terraform-azurerm-db-sql/2558b3821878002206b8ee71f4538719883cdbe8/modules/databases_users/terraform.tfvars.ci -------------------------------------------------------------------------------- /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 | -------------------------------------------------------------------------------- /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 | -------------------------------------------------------------------------------- /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 | -------------------------------------------------------------------------------- /providers.tf: -------------------------------------------------------------------------------- 1 | terraform { 2 | required_providers { 3 | azurerm = { 4 | source = "hashicorp/azurerm" 5 | version = "~> 4.0" 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 | -------------------------------------------------------------------------------- /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 | -------------------------------------------------------------------------------- /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 | -------------------------------------------------------------------------------- /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 | administrator_login = var.administrator_login 14 | administrator_login_password = var.administrator_password 15 | dynamic "azuread_administrator" { 16 | for_each = var.azuread_administrator[*] 17 | content { 18 | login_username = var.azuread_administrator.login_username 19 | object_id = var.azuread_administrator.object_id 20 | tenant_id = var.azuread_administrator.tenant_id 21 | azuread_authentication_only = var.azuread_administrator.azuread_authentication_only 22 | } 23 | } 24 | 25 | primary_user_assigned_identity_id = var.primary_user_assigned_identity_id 26 | 27 | dynamic "identity" { 28 | for_each = var.identity[*] 29 | content { 30 | type = var.identity.type 31 | identity_ids = endswith(var.identity.type, "UserAssigned") ? var.identity.identity_ids : null 32 | } 33 | } 34 | 35 | tags = merge(local.default_tags, var.extra_tags, var.server_extra_tags) 36 | } 37 | 38 | resource "azurerm_mssql_firewall_rule" "main" { 39 | for_each = can(tomap(var.allowed_cidrs)) ? tomap(var.allowed_cidrs) : { for idx, cidr in var.allowed_cidrs : "rule-${idx}" => cidr } 40 | 41 | name = each.key 42 | server_id = azurerm_mssql_server.main.id 43 | 44 | start_ip_address = cidrhost(each.value, 0) 45 | end_ip_address = cidrhost(each.value, -1) 46 | } 47 | 48 | resource "azurerm_mssql_elasticpool" "main" { 49 | count = var.elastic_pool_enabled ? 1 : 0 50 | 51 | name = local.elastic_pool_name 52 | 53 | location = var.location 54 | resource_group_name = var.resource_group_name 55 | 56 | license_type = var.elastic_pool_license_type 57 | 58 | server_name = azurerm_mssql_server.main.name 59 | 60 | per_database_settings { 61 | max_capacity = coalesce(var.elastic_pool_databases_max_capacity, var.elastic_pool_sku.capacity) 62 | min_capacity = var.elastic_pool_databases_min_capacity 63 | } 64 | 65 | max_size_gb = var.elastic_pool_max_size 66 | zone_redundant = var.elastic_pool_zone_redundant 67 | 68 | sku { 69 | capacity = local.elastic_pool_sku.capacity 70 | name = local.elastic_pool_sku.name 71 | tier = local.elastic_pool_sku.tier 72 | family = local.elastic_pool_sku.family 73 | } 74 | 75 | tags = merge(local.default_tags, var.extra_tags, var.elastic_pool_extra_tags) 76 | } 77 | 78 | resource "azurerm_mssql_virtual_network_rule" "main" { 79 | for_each = try({ for subnet in local.allowed_subnets : subnet.name => subnet }, {}) 80 | name = each.key 81 | server_id = azurerm_mssql_server.main.id 82 | subnet_id = each.value.subnet_id 83 | } 84 | 85 | 86 | moved { 87 | from = azurerm_mssql_server.sql 88 | to = azurerm_mssql_server.main 89 | } 90 | moved { 91 | from = azurerm_mssql_firewall_rule.firewall_rule 92 | to = azurerm_mssql_firewall_rule.main 93 | } 94 | moved { 95 | from = azurerm_mssql_elasticpool.elastic_pool 96 | to = azurerm_mssql_elasticpool.main 97 | } 98 | moved { 99 | from = azurerm_mssql_virtual_network_rule.vnet_rule 100 | to = azurerm_mssql_virtual_network_rule.main 101 | } 102 | -------------------------------------------------------------------------------- /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 | -------------------------------------------------------------------------------- /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 | -------------------------------------------------------------------------------- /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 | -------------------------------------------------------------------------------- /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 | -------------------------------------------------------------------------------- /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 | -------------------------------------------------------------------------------- /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 "alerting_email_addresses" { 254 | description = "List of email addresses to send reports for threat detection and vulnerability assessment." 255 | type = list(string) 256 | default = [] 257 | } 258 | 259 | variable "threat_detection_policy_enabled" { 260 | description = "True to enable thread detection policy on the databases." 261 | type = bool 262 | default = false 263 | } 264 | 265 | variable "threat_detection_policy_retention_days" { 266 | description = "Specifies the number of days to keep in the Threat Detection audit logs." 267 | type = number 268 | default = 7 269 | } 270 | 271 | variable "threat_detection_policy_disabled_alerts" { 272 | description = "Specifies a list of alerts which should be disabled. Possible values include `Access_Anomaly`, `Sql_Injection` and `Sql_Injection_Vulnerability`." 273 | type = list(string) 274 | default = [] 275 | } 276 | 277 | variable "databases_extended_auditing_enabled" { 278 | description = "True to enable extended auditing for SQL databases." 279 | type = bool 280 | default = false 281 | } 282 | 283 | variable "sql_server_extended_auditing_enabled" { 284 | description = "True to enable extended auditing for SQL Server." 285 | type = bool 286 | default = false 287 | } 288 | 289 | variable "sql_server_vulnerability_assessment_enabled" { 290 | description = "True to enable vulnerability assessment for this SQL Server." 291 | type = bool 292 | default = false 293 | } 294 | 295 | variable "sql_server_security_alerting_enabled" { 296 | description = "True to enable security alerting for this SQL Server." 297 | type = bool 298 | default = false 299 | } 300 | 301 | variable "sql_server_extended_auditing_retention_days" { 302 | description = "Server extended auditing logs retention." 303 | type = number 304 | default = 30 305 | } 306 | 307 | variable "databases_extended_auditing_retention_days" { 308 | description = "Databases extended auditing logs retention." 309 | type = number 310 | default = 30 311 | } 312 | 313 | variable "security_storage_account_blob_endpoint" { 314 | description = "Storage Account blob endpoint used to store security logs and reports." 315 | type = string 316 | default = null 317 | } 318 | 319 | variable "security_storage_account_access_key" { 320 | description = "Storage Account access key used to store security logs and reports." 321 | type = string 322 | default = null 323 | } 324 | 325 | variable "security_storage_account_container_name" { 326 | description = "Storage Account container name where to store SQL Server vulnerability assessment." 327 | type = string 328 | default = null 329 | } 330 | 331 | variable "identity" { 332 | description = "Identity block information." 333 | type = object({ 334 | type = optional(string, "SystemAssigned") 335 | identity_ids = optional(list(string)) 336 | }) 337 | default = {} 338 | nullable = false 339 | } 340 | 341 | variable "primary_user_assigned_identity_id" { 342 | 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." 343 | type = string 344 | default = null 345 | } 346 | -------------------------------------------------------------------------------- /versions.tf: -------------------------------------------------------------------------------- 1 | terraform { 2 | required_version = ">= 1.3" 3 | } 4 | -------------------------------------------------------------------------------- /versions.tofu: -------------------------------------------------------------------------------- 1 | terraform { 2 | required_version = ">= 1.8" 3 | } 4 | --------------------------------------------------------------------------------