├── .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 ├── data.tf ├── examples ├── infra │ ├── main.tf │ ├── modules.tf │ └── variables.tf ├── main │ ├── main.tf │ ├── modules.tf │ └── variables.tf └── private_cluster │ ├── main.tf │ ├── modules.tf │ └── variables.tf ├── locals-agic.tf ├── locals-naming.tf ├── locals-tags.tf ├── locals.tf ├── modules └── infra │ ├── README.md │ ├── k8s-roles.tf │ ├── k8s-storages-classes.tf │ ├── locals-aadpodidentity.tf │ ├── outputs.tf │ ├── r-aad-pod-identity.tf │ ├── terraform.tfvars.ci │ ├── variables.tf │ └── versions.tf ├── outputs.tf ├── r-acr-role.tf ├── r-aks.tf ├── r-identity.tf ├── r-infra.tf ├── r-logs.tf ├── r-naming.tf ├── r-network.tf ├── r-policy.tf ├── r-tools.tf ├── renovate.json ├── terraform.tfvars.ci ├── tools ├── agic │ ├── README.md │ ├── data.tf │ ├── helm-agic.tf │ ├── locals.tf │ ├── outputs.tf │ ├── r-application-gateway.tf │ ├── r-logs.tf │ ├── r-public-ip.tf │ ├── terraform.tfvars.ci │ ├── variables-logs.tf │ ├── variables-naming.tf │ ├── variables.tf │ └── versions.tf ├── cert-manager │ ├── README.md │ ├── locals-cert-manager.tf │ ├── outputs.tf │ ├── r-cert-manager.tf │ ├── terraform.tfvars.ci │ ├── variables.tf │ └── versions.tf ├── kured │ ├── README.md │ ├── locals-kured.tf │ ├── outputs.tf │ ├── r-kured.tf │ ├── terraform.tfvars.ci │ ├── variables.tf │ └── versions.tf └── velero │ ├── README.md │ ├── aad-bindings │ ├── .helmignore │ ├── Chart.yaml │ ├── templates │ │ ├── AzureIdentity.yaml.tpl │ │ └── AzureIdentityBinding.yaml.tpl │ └── values.yaml │ ├── locals-velero.tf │ ├── outputs.tf │ ├── r-identity.tf │ ├── r-velero.tf │ ├── terraform.tfvars.ci │ ├── variables.tf │ └── versions.tf ├── variables-logs.tf ├── variables-naming.tf ├── variables-tags.tf ├── variables.tf └── versions.tf /.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 | AzureRM version | 19 | | -------------- | ----------------- | --------------- | 20 | | >= 7.x.x | 1.3.x | >= 3.0 | 21 | | >= 6.x.x | 1.x | >= 3.0 | 22 | | >= 5.x.x | 0.15.x | >= 2.0 | 23 | | >= 4.x.x | 0.13.x / 0.14.x | >= 2.0 | 24 | | >= 3.x.x | 0.12.x | >= 2.0 | 25 | | >= 2.x.x | 0.12.x | < 2.0 | 26 | | < 2.x.x | 0.11.x | < 2.0 | 27 | 28 | ## Contributing 29 | 30 | If you want to contribute to this repository, feel free to use our [pre-commit](https://pre-commit.com/) git hook configuration 31 | which will help you automatically update and format some files for you by enforcing our Terraform code module best-practices. 32 | 33 | More details are available in the [CONTRIBUTING.md](./CONTRIBUTING.md#pull-request-process) file. 34 | 35 | ## Usage 36 | 37 | This module is optimized to work with the [Claranet terraform-wrapper](https://github.com/claranet/terraform-wrapper) tool 38 | which set some terraform variables in the environment needed by this module. 39 | More details about variables set by the `terraform-wrapper` available in the [documentation](https://github.com/claranet/terraform-wrapper#environment). 40 | 41 | ```hcl 42 | {{ include "examples/main/modules.tf" }} 43 | ``` 44 | 45 | {{ .Providers }} 46 | 47 | {{ .Modules }} 48 | 49 | {{ .Resources }} 50 | 51 | {{ .Inputs }} 52 | 53 | {{ .Outputs }} 54 | ... 55 | -------------------------------------------------------------------------------- /.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 | rule "terraform_naming_convention" { 49 | enabled = true 50 | } 51 | 52 | rule "terraform_required_version" { 53 | enabled = true 54 | } 55 | 56 | rule "terraform_required_providers" { 57 | enabled = true 58 | } 59 | 60 | rule "terraform_unused_required_providers" { 61 | enabled = true 62 | } 63 | 64 | # Disabled since we have files like "variables-xxxx.tf" instead of a single "variables.tf" 65 | rule "terraform_standard_module_structure" { 66 | enabled = false 67 | } 68 | -------------------------------------------------------------------------------- /.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: Terraform Version 25 | description: Which Terraform version are you using? 26 | placeholder: 1.0.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: 3.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: Terraform Configuration Files 49 | description: | 50 | Please provide a minimal Terraform configuration that can reproduce the issue. 51 | 52 | For large Terraform configs, please use a service like Dropbox and share a link to the ZIP file. 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 [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. `terraform 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 Terraform Configuration 40 | description: Please provide an example of what the new resource or enhancement could look like in a Terraform 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 | main.tf 3 | terraform.tfvars 4 | **/.terraform.lock.hcl 5 | !examples/**/main.tf 6 | !examples/**/terraform.tfvars 7 | -------------------------------------------------------------------------------- /.gitlab-ci.yml: -------------------------------------------------------------------------------- 1 | --- 2 | variables: 3 | TF_MIN_VERSION: "1.3" 4 | AZURERM_PROVIDER_MIN_VERSION: "3.39" 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: v4.6.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/antonbabenko/pre-commit-terraform.git 26 | rev: v1.94.1 27 | hooks: 28 | - id: terraform_fmt 29 | stages: [pre-commit] 30 | - id: terraform_docs 31 | stages: [pre-commit] 32 | args: 33 | - --args=--config=.config/terraform-docs.yml 34 | - --hook-config=--use-standard-markers=true 35 | exclude: "^modules|^example|^tools" 36 | - id: terraform_validate 37 | stages: [pre-commit] 38 | exclude: ^examples 39 | args: 40 | - --tf-init-args=-upgrade 41 | - --hook-config=--retry-once-with-cleanup=true 42 | - id: terraform_tflint 43 | stages: [pre-commit] 44 | exclude: ^examples 45 | args: 46 | - --args=--config=__GIT_WORKING_DIR__/.config/tflint.hcl 47 | - --env-vars=TFLINT_LOG="info" 48 | - id: terraform_trivy 49 | stages: [pre-commit] 50 | 51 | - repo: https://github.com/alessandrojcm/commitlint-pre-commit-hook 52 | rev: v9.17.0 53 | hooks: 54 | - id: commitlint 55 | stages: [commit-msg] 56 | additional_dependencies: ["@commitlint/config-conventional"] 57 | -------------------------------------------------------------------------------- /.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 3.8.0 2 | opentofu 1.8.1 3 | terraform-docs 0.18.0 4 | tflint 0.53.0 5 | trivy 0.55.0 6 | -------------------------------------------------------------------------------- /CHANGELOG.md: -------------------------------------------------------------------------------- 1 | ## 7.9.1 (2024-04-19) 2 | 3 | 4 | ### Documentation 5 | 6 | * **AZ-1394:** add deprecation notice in README 87767af 7 | 8 | 9 | ### Continuous Integration 10 | 11 | * **AZ-1391:** enable semantic-release [skip ci] 87cc3c8 12 | 13 | 14 | ### Miscellaneous Chores 15 | 16 | * **deps:** add renovate.json d509323 17 | * **deps:** update dependency claranet/diagnostic-settings/azurerm to v6.5.0 60e0a95 18 | * **deps:** update renovate.json 0d19178 19 | * **deps:** update terraform claranet/diagnostic-settings/azurerm to v6.5.0 8b09b70 20 | 21 | # v7.9.0 - 2023-08-18 22 | 23 | Added 24 | * [GH-13](https://github.com/claranet/terraform-azurerm-aks/pull/13): Add `scale_down_mode` on `node_pool` and `default_node_pool` config 25 | 26 | # v7.8.0 - 2023-07-21 27 | 28 | Added 29 | * AZ-1120: Add workload_runtime on node_pool config 30 | 31 | # v7.7.1 - 2023-07-13 32 | 33 | Fixed 34 | * AZ-1113: Update sub-modules READMEs (according to their example) 35 | 36 | # v7.7.0 - 2023-04-28 37 | 38 | Added 39 | * [GH-12](https://github.com/claranet/terraform-azurerm-aks/pull/12): Expose `oidc_issuer_enabled` parameter, output `oidc_issuer_url` 40 | 41 | # v7.6.1 - 2023-04-14 42 | 43 | Fixed 44 | * AZ-1059: Fix `key_vault_secrets_provider_identity` output 45 | 46 | # v7.6.0 - 2023-03-31 47 | 48 | Added 49 | * AZ-1036: Add `key_vault_secrets_provider` parameter 50 | 51 | Fixed 52 | * AZ-1035: Fix permanent drift when `enable_auto_scaling` is set to `false` 53 | 54 | # v7.5.0 - 2023-03-03 55 | 56 | Added 57 | * AZ-1000: Add an option to enable or disable UAI Private DNS Zone role assignment 58 | * AZ-1001: Add default `no_proxy_url_list` and some information about the parameter 59 | * [GH-9](https://github.com/claranet/terraform-azurerm-aks/pull/9): Add more configuration options to cluster's node pools 60 | * AZ-1011: Add AKS Kubelet identity role assignment 61 | 62 | Fixed 63 | * [GH-10](https://github.com/claranet/terraform-azurerm-aks/pull/10): Auto scaler profile fixes 64 | * AZ-1011: Fix identities outputs 65 | * [GH-11](https://github.com/claranet/terraform-azurerm-aks/pull/11): Fix node_count error when autoscaler is enabled 66 | 67 | # v7.4.0 - 2023-02-10 68 | 69 | Changed 70 | * [GH-7](https://github.com/claranet/terraform-azurerm-aks/pull/7): Fix issues with output and local variables when agic is disabled 71 | 72 | # v7.3.0 - 2023-02-08 73 | 74 | Added 75 | * [GH-8](https://github.com/claranet/terraform-azurerm-aks/pull/8): Add HTTP Application Routing option 76 | 77 | Changed 78 | * AZ-992: Prevent the gathering of `kube-audit` and `kube-audit-admin` logs by default. 79 | 80 | Fixed 81 | * AZ-992: Fix examples 82 | 83 | # v7.2.0 - 2022-12-02 84 | 85 | Added 86 | * AZ-908/AZ-515: Implement Azure CAF naming (using Microsoft provider) 87 | * AZ-914: Add AKS `http_proxy` feature 88 | 89 | Changed 90 | * AZ-908: Bump `diagnostic-settings`, uses standard variables names 91 | * AZ-908: AzureRM provider updated to `v3.22+` 92 | * AZ-901: Code security check/hardening - change variable default values 93 | * AZ-914: Update azurerm in provider version to avoid https://github.com/Azure/AKS/issues/3044 94 | 95 | Fixed 96 | * AZ-914: Update kured image tag and repository 97 | * AZ-914: Fix agic default values 98 | 99 | # v7.1.1 - 2022-11-04 100 | 101 | Fixed 102 | * AZ-883 Fix syntax to pass checks with new tflint version 103 | 104 | # v7.1.0 - 2022-10-14 105 | 106 | Added 107 | * [GH-6](https://github.com/claranet/terraform-azurerm-aks/pull/6): Allow to choose which expander to use in autoscaler profile 108 | * AZ-867: Allow to use existing Application Gateway as AGIC 109 | 110 | # v7.0.0 - 2022-09-30 111 | 112 | Breaking 113 | * AZ-840: Update to Terraform `v1.3` 114 | 115 | Fixed 116 | * AZ-856: Fix kured_chart_repository variable 117 | 118 | # v6.0.0 - 2022-08-05 119 | 120 | Breaking 121 | * AZ-717: Remove providers configurations from module/sub-modules to be compatible with terraform 1.2 122 | 123 | Added 124 | * AZ-615: Add an option to enable or disable default tags 125 | * AZ-605: Add Kubenet implementation 126 | * AZ-605: Allow aadpodidentity and Velero MSI custom naming 127 | * AZ-605: Allow to configure tags on MSIs and node pools 128 | * AZ-605: Allow to configure permissions on route table when using kubenet and UDR egress 129 | * AZ-605: Add `Kubernetes cluster containers should only use allowed capabilities` policy when using Kubenet to avoid security issue 130 | 131 | Fixed 132 | * AZ-605: Fix Velero_storage_settings variable 133 | * AZ-605: Fix aks_pod_cidr variable 134 | * AZ-605: Fix Aks Private DNS zone configuration 135 | 136 | Changed 137 | * AZ-605: Change azurerm provider minimal version 138 | * AZ-717: Bump `aad-pod-identity` helm chart to `4.1.9` 139 | * AZ-717: Bump `cert-manager` helm chart to `1.8.0` 140 | * AZ-717: Bump `velero` helm chart to `2.29.5` 141 | * AZ-717: Bump `agic` helm chart to `1.5.2` 142 | * AZ-717: Bump `helm` provider min version to `2.5.1` 143 | * AZ-717: Bump `kubernetes` provider min version to `2.11.0` 144 | * AZ-717: Add mandatory priority on AGIC Application gateway `request_routing_rule` 145 | * AZ-717: Add `installCRDs` value to true in `cert-manager` deployment 146 | 147 | # v4.5.0 - 2022-03-11 148 | 149 | Breaking 150 | * GITHUB-3: `[module_variable_optional_attrs]` requires terraform `v0.14+` 151 | 152 | Changed 153 | * [GITHUB-3](https://github.com/claranet/terraform-azurerm-aks/pull/3): Fix `velero_storage_settings` type, and make attributes optional 154 | 155 | 156 | # v4.4.0 - 2021-12-28 157 | 158 | Changed 159 | * AZ-632: Increased default disk size to 128GB for Linux nodes and 256GB for Windows nodes to comply with Microsoft recommendations 160 | * AZ-637: Add os disk type option to enable the Ephemeral disks 161 | 162 | # v4.3.2 - 2021-11-15 163 | 164 | Fixed 165 | * AZ-589: Avoid plan drift when specifying Diagnostic Settings categories 166 | 167 | # v4.3.1 - 2021-10-19 168 | 169 | Fixed 170 | * AZ-587: Fix non-working `max_pods` parameter on node pools 171 | 172 | # v4.3.0 - 2021-10-18 173 | 174 | Breaking 175 | * AZ-485: Add AKS Private Cluster Feature 176 | 177 | Added 178 | * AZ-485: Add Msi Identity for Applicationg Gateway with Agic 179 | * AZ-485: Add Private DNS Zone support 180 | * AZ-485: Add Azure Container Registry Permissions 181 | * AZ-485: Allow to configure AKS SKU 182 | 183 | Changed 184 | * AZ-532: Revamp README with latest `terraform-docs` tool 185 | * AZ-530: Cleanup module, fix linter errors 186 | 187 | # v4.2.0 - 2021-06-03 188 | 189 | Breaking 190 | * AZ-483: Remove deprecated `load_config_file` parameter from kubernetes provider declaration according to latest provider release (2.0) 191 | * AZ-483: Update minimal version required for kubernetes provider to `>= 2.1.0` 192 | 193 | Added 194 | * AZ-484: Update CI to cover Terraform 0.15 195 | 196 | # v4.1.0 - 2020-12-31 197 | 198 | Breaking 199 | * AZ-404: Rework log management by using diagnostic-settings module 200 | 201 | # v3.3.0/v4.0.0 - 2020-12-30 202 | 203 | Changed 204 | * AZ-273: Update README and CI, module compatible Terraform 0.13+ (now requires Terraform 0.12.26 minimum version) 205 | 206 | Added 207 | * AZ-335: Force lower domain name label for the public IP of the agic 208 | * AZ-377: Core tools as documented sub-module 209 | * AZ-359: Add `outbound_type` variable to be able to use user defined routing 210 | * AZ-359: Add ability to have a private ingress with `private_ingress` variable and `appgw_private_ip` 211 | 212 | Updated 213 | * AZ-381: Harmonize variables and add outputs 214 | * AZ-380: AKS module: pin velero azure image 215 | * AZ-382: Update of Kured chart version 216 | 217 | Fixed 218 | * AZ-379: Fix kured chart repository 219 | * AZ-357: Fix issue with AKS user role assignment 220 | * AZ-357: Fix velero parameter 221 | * AZ-357: Fix versions in submodules 222 | 223 | # v3.2.0 - 2020-10-20 224 | 225 | Fixed 226 | * AZ-251: Update velero helm chart to 2.12.13 227 | * AZ-251: Align velero 1.4.0 to main branch of velero-plugin-for-microsoft-azure to work with managed identities 228 | * AZ-251: Remove hack for velero pod labels since it's now supported in chart v2.12.13 229 | * AZ-252: Update AGIC helm chart to 1.2.0 final 230 | * AZ-254: Application gateway creation fail with default parameters 231 | 232 | Added 233 | * AZ-253: Update to last stable version of AKS by default 234 | 235 | # v3.1.0 - 2020-07-31 236 | 237 | Breaking 238 | * AZ-229: Replace deprecated Services Principals by Managed Identity 239 | 240 | Fixed 241 | * AZ-237: `appgw_subnet_id` variable must not be mandatory 242 | 243 | # v3.0.0 - 2020-07-03 244 | 245 | Added 246 | * AZ-123: First version of the AKS module 247 | -------------------------------------------------------------------------------- /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 | -------------------------------------------------------------------------------- /data.tf: -------------------------------------------------------------------------------- 1 | data "azurerm_subscription" "current" {} 2 | 3 | data "azurerm_virtual_network" "aks_vnet" { 4 | count = local.is_custom_dns_private_cluster ? 1 : 0 5 | 6 | name = reverse(split("/", var.vnet_id))[0] 7 | resource_group_name = split("/", var.vnet_id)[4] 8 | } 9 | -------------------------------------------------------------------------------- /examples/infra/main.tf: -------------------------------------------------------------------------------- 1 | terraform { 2 | required_version = ">= 0.13.0" 3 | required_providers { 4 | azurerm = { 5 | source = "hashicorp/azurerm" 6 | version = ">= 2.51" 7 | } 8 | helm = { 9 | source = "hashicorp/helm" 10 | version = ">= 2.3.0" 11 | } 12 | kubernetes = { 13 | source = "hashicorp/kubernetes" 14 | version = ">= 2.1.0" 15 | } 16 | tls = { 17 | source = "hashicorp/tls" 18 | version = ">= 4.0" 19 | } 20 | } 21 | } 22 | 23 | provider "azurerm" { 24 | features {} 25 | } 26 | 27 | provider "kubernetes" { 28 | alias = "aks-module" 29 | host = module.aks.aks_kube_config[0].host 30 | client_certificate = base64decode(module.aks.aks_kube_config[0].client_certificate) 31 | client_key = base64decode(module.aks.aks_kube_config[0].client_key) 32 | cluster_ca_certificate = base64decode(module.aks.aks_kube_config[0].cluster_ca_certificate) 33 | } 34 | 35 | provider "helm" { 36 | alias = "aks-module" 37 | kubernetes { 38 | host = module.aks.aks_kube_config[0].host 39 | client_certificate = base64decode(module.aks.aks_kube_config[0].client_certificate) 40 | client_key = base64decode(module.aks.aks_kube_config[0].client_key) 41 | cluster_ca_certificate = base64decode(module.aks.aks_kube_config[0].cluster_ca_certificate) 42 | } 43 | } 44 | -------------------------------------------------------------------------------- /examples/infra/modules.tf: -------------------------------------------------------------------------------- 1 | locals { 2 | allowed_cidrs = ["x.x.x.x", "y.y.y.y"] 3 | } 4 | 5 | module "azure_region" { 6 | source = "claranet/regions/azurerm" 7 | version = "x.x.x" 8 | 9 | azure_region = var.azure_region 10 | } 11 | 12 | module "rg" { 13 | source = "claranet/rg/azurerm" 14 | version = "x.x.x" 15 | 16 | location = module.azure_region.location 17 | client_name = var.client_name 18 | environment = var.environment 19 | stack = var.stack 20 | } 21 | 22 | module "azure_virtual_network" { 23 | source = "claranet/vnet/azurerm" 24 | version = "x.x.x" 25 | 26 | environment = var.environment 27 | location = module.azure_region.location 28 | location_short = module.azure_region.location_short 29 | client_name = var.client_name 30 | stack = var.stack 31 | 32 | resource_group_name = module.rg.resource_group_name 33 | 34 | vnet_cidr = ["10.0.0.0/19"] 35 | } 36 | 37 | module "node_network_subnet" { 38 | source = "claranet/subnet/azurerm" 39 | version = "x.x.x" 40 | 41 | environment = var.environment 42 | location_short = module.azure_region.location_short 43 | client_name = var.client_name 44 | stack = var.stack 45 | 46 | resource_group_name = module.rg.resource_group_name 47 | virtual_network_name = module.azure_virtual_network.virtual_network_name 48 | 49 | name_suffix = "nodes" 50 | 51 | subnet_cidr_list = ["10.0.0.0/20"] 52 | 53 | service_endpoints = ["Microsoft.Storage"] 54 | } 55 | 56 | module "appgw_network_subnet" { 57 | source = "claranet/subnet/azurerm" 58 | version = "x.x.x" 59 | 60 | environment = var.environment 61 | location_short = module.azure_region.location_short 62 | client_name = var.client_name 63 | stack = var.stack 64 | 65 | resource_group_name = module.rg.resource_group_name 66 | virtual_network_name = module.azure_virtual_network.virtual_network_name 67 | 68 | name_suffix = "appgw" 69 | 70 | subnet_cidr_list = ["10.0.20.0/24"] 71 | } 72 | 73 | module "global_run" { 74 | source = "claranet/run/azurerm" 75 | version = "x.x.x" 76 | 77 | client_name = var.client_name 78 | location = module.azure_region.location 79 | location_short = module.azure_region.location_short 80 | environment = var.environment 81 | stack = var.stack 82 | 83 | monitoring_function_splunk_token = var.monitoring_function_splunk_token 84 | 85 | resource_group_name = module.rg.resource_group_name 86 | 87 | tenant_id = var.azure_tenant_id 88 | } 89 | 90 | resource "tls_private_key" "key" { 91 | algorithm = "RSA" 92 | } 93 | 94 | module "aks" { 95 | source = "claranet/aks/azurerm" 96 | version = "x.x.x" 97 | 98 | providers = { 99 | kubernetes = kubernetes.aks-module 100 | helm = helm.aks-module 101 | } 102 | 103 | client_name = var.client_name 104 | environment = var.environment 105 | stack = var.stack 106 | 107 | resource_group_name = module.rg.resource_group_name 108 | location = module.azure_region.location 109 | location_short = module.azure_region.location_short 110 | 111 | private_cluster_enabled = true 112 | service_cidr = "10.0.16.0/22" 113 | kubernetes_version = "1.19.7" 114 | 115 | vnet_id = module.azure_virtual_network.virtual_network_id 116 | nodes_subnet_id = module.node_network_subnet.subnet_id 117 | nodes_pools = [ 118 | { 119 | name = "pool1" 120 | count = 1 121 | vm_size = "Standard_D1_v2" 122 | os_type = "Linux" 123 | os_disk_type = "Ephemeral" 124 | os_disk_size_gb = 30 125 | vnet_subnet_id = module.node_network_subnet.subnet_id 126 | }, 127 | { 128 | name = "bigpool1" 129 | count = 3 130 | vm_size = "Standard_F8s_v2" 131 | os_type = "Linux" 132 | os_disk_size_gb = 30 133 | vnet_subnet_id = module.node_network_subnet.subnet_id 134 | enable_auto_scaling = true 135 | min_count = 3 136 | max_count = 9 137 | } 138 | ] 139 | 140 | linux_profile = { 141 | username = "nodeadmin" 142 | ssh_key = tls_private_key.key.public_key_openssh 143 | } 144 | 145 | oms_log_analytics_workspace_id = module.global_run.log_analytics_workspace_id 146 | azure_policy_enabled = false 147 | 148 | logs_destinations_ids = [module.global_run.log_analytics_workspace_id] 149 | 150 | appgw_subnet_id = module.appgw_network_subnet.subnet_id 151 | 152 | appgw_ingress_controller_values = { "verbosityLevel" = 5, "appgw.shared" = true } 153 | cert_manager_settings = { "cainjector.nodeSelector.agentpool" = "default", "nodeSelector.agentpool" = "default", "webhook.nodeSelector.agentpool" = "default" } 154 | velero_storage_settings = { allowed_cidrs = local.allowed_cidrs } 155 | 156 | container_registries_id = [module.acr.acr_id] 157 | 158 | key_vault_secrets_provider = { 159 | secret_rotation_enabled = true 160 | secret_rotation_interval = "2m" 161 | } 162 | } 163 | 164 | module "acr" { 165 | source = "claranet/acr/azurerm" 166 | version = "x.x.x" 167 | 168 | location = module.azure_region.location 169 | location_short = module.azure_region.location_short 170 | resource_group_name = module.rg.resource_group_name 171 | sku = "Standard" 172 | 173 | client_name = var.client_name 174 | environment = var.environment 175 | stack = var.stack 176 | 177 | logs_destinations_ids = [module.global_run.log_analytics_workspace_id] 178 | } 179 | -------------------------------------------------------------------------------- /examples/infra/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 | 21 | variable "monitoring_function_splunk_token" { 22 | description = "Access Token to send metrics to Splunk Observability" 23 | type = string 24 | } 25 | 26 | variable "azure_tenant_id" { 27 | description = "Azure Tenant Id" 28 | type = string 29 | } 30 | -------------------------------------------------------------------------------- /examples/main/main.tf: -------------------------------------------------------------------------------- 1 | terraform { 2 | required_version = ">= 0.13.0" 3 | required_providers { 4 | azurerm = { 5 | source = "hashicorp/azurerm" 6 | version = ">= 2.51" 7 | } 8 | helm = { 9 | source = "hashicorp/helm" 10 | version = ">= 2.3.0" 11 | } 12 | kubernetes = { 13 | source = "hashicorp/kubernetes" 14 | version = ">= 2.1.0" 15 | } 16 | tls = { 17 | source = "hashicorp/tls" 18 | version = ">= 4.0" 19 | } 20 | } 21 | } 22 | 23 | provider "azurerm" { 24 | features {} 25 | } 26 | 27 | provider "kubernetes" { 28 | alias = "aks-module" 29 | host = module.aks.aks_kube_config[0].host 30 | client_certificate = base64decode(module.aks.aks_kube_config[0].client_certificate) 31 | client_key = base64decode(module.aks.aks_kube_config[0].client_key) 32 | cluster_ca_certificate = base64decode(module.aks.aks_kube_config[0].cluster_ca_certificate) 33 | } 34 | 35 | provider "helm" { 36 | alias = "aks-module" 37 | kubernetes { 38 | host = module.aks.aks_kube_config[0].host 39 | client_certificate = base64decode(module.aks.aks_kube_config[0].client_certificate) 40 | client_key = base64decode(module.aks.aks_kube_config[0].client_key) 41 | cluster_ca_certificate = base64decode(module.aks.aks_kube_config[0].cluster_ca_certificate) 42 | } 43 | } 44 | -------------------------------------------------------------------------------- /examples/main/modules.tf: -------------------------------------------------------------------------------- 1 | locals { 2 | allowed_cidrs = ["x.x.x.x", "y.y.y.y"] 3 | } 4 | 5 | module "azure_region" { 6 | source = "claranet/regions/azurerm" 7 | version = "x.x.x" 8 | 9 | azure_region = var.azure_region 10 | } 11 | 12 | module "rg" { 13 | source = "claranet/rg/azurerm" 14 | version = "x.x.x" 15 | 16 | location = module.azure_region.location 17 | client_name = var.client_name 18 | environment = var.environment 19 | stack = var.stack 20 | } 21 | 22 | module "azure_virtual_network" { 23 | source = "claranet/vnet/azurerm" 24 | version = "x.x.x" 25 | 26 | environment = var.environment 27 | location = module.azure_region.location 28 | location_short = module.azure_region.location_short 29 | client_name = var.client_name 30 | stack = var.stack 31 | 32 | resource_group_name = module.rg.resource_group_name 33 | 34 | vnet_cidr = ["10.0.0.0/19"] 35 | } 36 | 37 | module "node_network_subnet" { 38 | source = "claranet/subnet/azurerm" 39 | version = "x.x.x" 40 | 41 | environment = var.environment 42 | location_short = module.azure_region.location_short 43 | client_name = var.client_name 44 | stack = var.stack 45 | 46 | resource_group_name = module.rg.resource_group_name 47 | virtual_network_name = module.azure_virtual_network.virtual_network_name 48 | 49 | name_suffix = "nodes" 50 | 51 | subnet_cidr_list = ["10.0.0.0/20"] 52 | 53 | service_endpoints = ["Microsoft.Storage"] 54 | } 55 | 56 | module "appgw_network_subnet" { 57 | source = "claranet/subnet/azurerm" 58 | version = "x.x.x" 59 | 60 | environment = var.environment 61 | location_short = module.azure_region.location_short 62 | client_name = var.client_name 63 | stack = var.stack 64 | 65 | resource_group_name = module.rg.resource_group_name 66 | virtual_network_name = module.azure_virtual_network.virtual_network_name 67 | 68 | name_suffix = "appgw" 69 | 70 | subnet_cidr_list = ["10.0.20.0/24"] 71 | } 72 | 73 | module "global_run" { 74 | source = "claranet/run/azurerm" 75 | version = "x.x.x" 76 | 77 | client_name = var.client_name 78 | location = module.azure_region.location 79 | location_short = module.azure_region.location_short 80 | environment = var.environment 81 | stack = var.stack 82 | 83 | monitoring_function_splunk_token = var.monitoring_function_splunk_token 84 | 85 | resource_group_name = module.rg.resource_group_name 86 | 87 | tenant_id = var.azure_tenant_id 88 | } 89 | 90 | resource "tls_private_key" "key" { 91 | algorithm = "RSA" 92 | } 93 | 94 | module "aks" { 95 | source = "claranet/aks/azurerm" 96 | version = "x.x.x" 97 | 98 | providers = { 99 | kubernetes = kubernetes.aks-module 100 | helm = helm.aks-module 101 | } 102 | 103 | client_name = var.client_name 104 | environment = var.environment 105 | stack = var.stack 106 | 107 | resource_group_name = module.rg.resource_group_name 108 | location = module.azure_region.location 109 | location_short = module.azure_region.location_short 110 | 111 | private_cluster_enabled = false 112 | service_cidr = "10.0.16.0/22" 113 | kubernetes_version = "1.19.7" 114 | 115 | vnet_id = module.azure_virtual_network.virtual_network_id 116 | nodes_subnet_id = module.node_network_subnet.subnet_id 117 | nodes_pools = [ 118 | { 119 | name = "pool1" 120 | count = 1 121 | vm_size = "Standard_D1_v2" 122 | os_type = "Linux" 123 | os_disk_type = "Ephemeral" 124 | os_disk_size_gb = 30 125 | vnet_subnet_id = module.node_network_subnet.subnet_id 126 | }, 127 | { 128 | name = "bigpool1" 129 | count = 3 130 | vm_size = "Standard_F8s_v2" 131 | os_type = "Linux" 132 | os_disk_size_gb = 30 133 | vnet_subnet_id = module.node_network_subnet.subnet_id 134 | enable_auto_scaling = true 135 | min_count = 3 136 | max_count = 9 137 | } 138 | ] 139 | 140 | linux_profile = { 141 | username = "nodeadmin" 142 | ssh_key = tls_private_key.key.public_key_openssh 143 | } 144 | 145 | oms_log_analytics_workspace_id = module.global_run.log_analytics_workspace_id 146 | azure_policy_enabled = false 147 | 148 | logs_destinations_ids = [module.global_run.log_analytics_workspace_id] 149 | 150 | appgw_subnet_id = module.appgw_network_subnet.subnet_id 151 | 152 | appgw_ingress_controller_values = { "verbosityLevel" = 5, "appgw.shared" = true } 153 | cert_manager_settings = { "cainjector.nodeSelector.agentpool" = "default", "nodeSelector.agentpool" = "default", "webhook.nodeSelector.agentpool" = "default" } 154 | velero_storage_settings = { allowed_cidrs = local.allowed_cidrs } 155 | 156 | container_registries_id = [module.acr.acr_id] 157 | 158 | key_vault_secrets_provider = { 159 | secret_rotation_enabled = true 160 | secret_rotation_interval = "2m" 161 | } 162 | } 163 | 164 | module "acr" { 165 | source = "claranet/acr/azurerm" 166 | version = "x.x.x" 167 | 168 | location = module.azure_region.location 169 | location_short = module.azure_region.location_short 170 | resource_group_name = module.rg.resource_group_name 171 | sku = "Standard" 172 | 173 | client_name = var.client_name 174 | environment = var.environment 175 | stack = var.stack 176 | 177 | logs_destinations_ids = [module.global_run.log_analytics_workspace_id] 178 | } 179 | -------------------------------------------------------------------------------- /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 | 21 | variable "monitoring_function_splunk_token" { 22 | description = "Access Token to send metrics to Splunk Observability" 23 | type = string 24 | } 25 | 26 | variable "azure_tenant_id" { 27 | description = "Azure Tenant Id" 28 | type = string 29 | } 30 | -------------------------------------------------------------------------------- /examples/private_cluster/main.tf: -------------------------------------------------------------------------------- 1 | terraform { 2 | required_version = ">= 0.13.0" 3 | required_providers { 4 | azurerm = { 5 | source = "hashicorp/azurerm" 6 | version = ">= 2.51" 7 | } 8 | helm = { 9 | source = "hashicorp/helm" 10 | version = ">= 2.3.0" 11 | } 12 | kubernetes = { 13 | source = "hashicorp/kubernetes" 14 | version = ">= 2.1.0" 15 | } 16 | tls = { 17 | source = "hashicorp/tls" 18 | version = ">= 4.0" 19 | } 20 | } 21 | } 22 | 23 | provider "azurerm" { 24 | features {} 25 | } 26 | 27 | provider "kubernetes" { 28 | alias = "aks-module" 29 | host = module.aks.aks_kube_config[0].host 30 | client_certificate = base64decode(module.aks.aks_kube_config[0].client_certificate) 31 | client_key = base64decode(module.aks.aks_kube_config[0].client_key) 32 | cluster_ca_certificate = base64decode(module.aks.aks_kube_config[0].cluster_ca_certificate) 33 | } 34 | 35 | provider "helm" { 36 | alias = "aks-module" 37 | kubernetes { 38 | host = module.aks.aks_kube_config[0].host 39 | client_certificate = base64decode(module.aks.aks_kube_config[0].client_certificate) 40 | client_key = base64decode(module.aks.aks_kube_config[0].client_key) 41 | cluster_ca_certificate = base64decode(module.aks.aks_kube_config[0].cluster_ca_certificate) 42 | } 43 | } 44 | -------------------------------------------------------------------------------- /examples/private_cluster/modules.tf: -------------------------------------------------------------------------------- 1 | locals { 2 | allowed_cidrs = ["x.x.x.x", "y.y.y.y"] 3 | } 4 | 5 | module "azure_region" { 6 | source = "claranet/regions/azurerm" 7 | version = "x.x.x" 8 | 9 | azure_region = var.azure_region 10 | } 11 | 12 | module "rg" { 13 | source = "claranet/rg/azurerm" 14 | version = "x.x.x" 15 | 16 | location = module.azure_region.location 17 | client_name = var.client_name 18 | environment = var.environment 19 | stack = var.stack 20 | } 21 | 22 | module "azure_virtual_network" { 23 | source = "claranet/vnet/azurerm" 24 | version = "x.x.x" 25 | 26 | environment = var.environment 27 | location = module.azure_region.location 28 | location_short = module.azure_region.location_short 29 | client_name = var.client_name 30 | stack = var.stack 31 | 32 | resource_group_name = module.rg.resource_group_name 33 | 34 | vnet_cidr = ["10.0.0.0/19"] 35 | } 36 | 37 | resource "azurerm_private_dns_zone" "private_dns_zone" { 38 | name = "privatelink.francecentral.azmk8s.io" 39 | resource_group_name = module.rg.resource_group_name 40 | 41 | } 42 | 43 | module "node_network_subnet" { 44 | source = "claranet/subnet/azurerm" 45 | version = "x.x.x" 46 | 47 | environment = var.environment 48 | location_short = module.azure_region.location_short 49 | client_name = var.client_name 50 | stack = var.stack 51 | 52 | resource_group_name = module.rg.resource_group_name 53 | virtual_network_name = module.azure_virtual_network.virtual_network_name 54 | 55 | name_suffix = "nodes" 56 | 57 | subnet_cidr_list = ["10.0.0.0/20"] 58 | 59 | service_endpoints = ["Microsoft.Storage"] 60 | } 61 | 62 | module "appgw_network_subnet" { 63 | source = "claranet/subnet/azurerm" 64 | version = "x.x.x" 65 | 66 | environment = var.environment 67 | location_short = module.azure_region.location_short 68 | client_name = var.client_name 69 | stack = var.stack 70 | 71 | resource_group_name = module.rg.resource_group_name 72 | virtual_network_name = module.azure_virtual_network.virtual_network_name 73 | 74 | name_suffix = "appgw" 75 | 76 | subnet_cidr_list = ["10.0.20.0/24"] 77 | } 78 | 79 | module "global_run" { 80 | source = "claranet/run/azurerm" 81 | version = "x.x.x" 82 | 83 | client_name = var.client_name 84 | location = module.azure_region.location 85 | location_short = module.azure_region.location_short 86 | environment = var.environment 87 | stack = var.stack 88 | 89 | monitoring_function_splunk_token = var.monitoring_function_splunk_token 90 | 91 | resource_group_name = module.rg.resource_group_name 92 | 93 | tenant_id = var.azure_tenant_id 94 | } 95 | 96 | resource "tls_private_key" "key" { 97 | algorithm = "RSA" 98 | } 99 | 100 | module "aks" { 101 | source = "claranet/aks/azurerm" 102 | version = "x.x.x" 103 | 104 | client_name = var.client_name 105 | environment = var.environment 106 | stack = var.stack 107 | 108 | resource_group_name = module.rg.resource_group_name 109 | location = module.azure_region.location 110 | location_short = module.azure_region.location_short 111 | 112 | service_cidr = "10.0.16.0/22" 113 | kubernetes_version = "1.19.7" 114 | 115 | vnet_id = module.azure_virtual_network.virtual_network_id 116 | nodes_subnet_id = module.node_network_subnet.subnet_id 117 | 118 | private_cluster_enabled = true 119 | private_dns_zone_type = "Custom" 120 | private_dns_zone_id = azurerm_private_dns_zone.private_dns_zone.id 121 | 122 | agic_enabled = true 123 | appgw_subnet_id = module.appgw_network_subnet.subnet_id 124 | appgw_identity_enabled = true 125 | 126 | default_node_pool = { 127 | max_pods = 110 128 | os_disk_size_gb = 64 129 | vm_size = "Standard_B4ms" 130 | } 131 | 132 | nodes_pools = [ 133 | { 134 | name = "nodepool1" 135 | vm_size = "Standard_B4ms" 136 | os_type = "Linux" 137 | os_disk_type = "Ephemeral" 138 | os_disk_size_gb = 100 139 | vnet_subnet_id = module.node_network_subnet.subnet_id 140 | max_pods = 110 141 | enable_auto_scaling = true 142 | count = 1 143 | min_count = 1 144 | max_count = 10 145 | }, 146 | ] 147 | 148 | linux_profile = { 149 | username = "nodeadmin" 150 | ssh_key = tls_private_key.key.public_key_openssh 151 | } 152 | 153 | oms_log_analytics_workspace_id = module.global_run.log_analytics_workspace_id 154 | azure_policy_enabled = false 155 | 156 | logs_destinations_ids = [module.global_run.log_analytics_workspace_id] 157 | 158 | appgw_ingress_controller_values = { "verbosityLevel" = 5, "appgw.shared" = true } 159 | cert_manager_settings = { "cainjector.nodeSelector.agentpool" = "default", "nodeSelector.agentpool" = "default", "webhook.nodeSelector.agentpool" = "default" } 160 | velero_storage_settings = { allowed_cidrs = local.allowed_cidrs } 161 | 162 | container_registries_id = [module.acr.acr_id] 163 | } 164 | 165 | module "acr" { 166 | source = "claranet/acr/azurerm" 167 | version = "x.x.x" 168 | 169 | location = module.azure_region.location 170 | location_short = module.azure_region.location_short 171 | resource_group_name = module.rg.resource_group_name 172 | sku = "Standard" 173 | 174 | client_name = var.client_name 175 | environment = var.environment 176 | stack = var.stack 177 | 178 | logs_destinations_ids = [module.global_run.log_analytics_workspace_id] 179 | } 180 | -------------------------------------------------------------------------------- /examples/private_cluster/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 | 21 | variable "monitoring_function_splunk_token" { 22 | description = "Access Token to send metrics to Splunk Observability" 23 | type = string 24 | } 25 | 26 | variable "azure_tenant_id" { 27 | description = "Azure Tenant Id" 28 | type = string 29 | } 30 | -------------------------------------------------------------------------------- /locals-agic.tf: -------------------------------------------------------------------------------- 1 | locals { 2 | appgw_default_settings = { 3 | ip_name = "${local.appgw_name}-pip" 4 | ip_sku = "Standard" 5 | ip_allocation_method = "Static" 6 | frontend_ip_configuration_name = "${local.appgw_name}-frontipconfig" 7 | frontend_priv_ip_configuration_name = "${local.appgw_name}-frontipconfig-priv" 8 | gateway_ip_configuration_name = "${local.appgw_name}-ipconfig" 9 | sku_name = "Standard_v2" 10 | sku_tier = "Standard_v2" 11 | sku_capacity = 2 12 | zones = ["1", "2", "3"] 13 | policy_name = "AppGwSslPolicy20170401S" 14 | enabled_waf = false 15 | file_upload_limit_mb = "100" 16 | max_request_body_size_kb = "128" 17 | request_body_check = true 18 | rule_set_type = "OWASP" 19 | rule_set_version = "3.0" 20 | firewall_mode = "Detection" 21 | 22 | app_gateway_tags = local.default_tags 23 | ip_tags = local.default_tags 24 | appgw_backend_http_settings = [{ 25 | name = "dummy" 26 | cookie_based_affinity = "Disabled" 27 | path = "/" 28 | port = 80 29 | protocol = "Http" 30 | request_timeout = 1 31 | probe_name = "dummy" 32 | }] 33 | appgw_backend_pools = [{ 34 | name = "dummy" 35 | fqdns = ["dummy"] 36 | }] 37 | appgw_probes = [{ 38 | host = "dummy" 39 | interval = 30 40 | minimum_servers = 0 41 | name = "dummy" 42 | path = "/" 43 | pick_host_name_from_backend_http_settings = false 44 | protocol = "Http" 45 | timeout = 30 46 | unhealthy_threshold = 3 47 | match_status_code = ["200"] 48 | }] 49 | appgw_routings = [{ 50 | name = "dummy" 51 | rule_type = "Basic" 52 | http_listener_name = "dummy" 53 | backend_address_pool_name = "dummy" 54 | backend_http_settings_name = "dummy" 55 | 56 | }] 57 | appgw_http_listeners = [{ 58 | name = "dummy" 59 | frontend_ip_configuration_name = local.frontend_ip_configuration_name 60 | frontend_port_name = "dummy" 61 | protocol = "Http" 62 | host_name = "dummy" 63 | }] 64 | appgw_rewrite_rule_set = [] 65 | frontend_port_settings = [{ 66 | name = "dummy" 67 | port = 80 68 | }] 69 | ssl_certificates_configs = [] 70 | identity = var.appgw_identity_enabled ? azurerm_user_assigned_identity.appgw_assigned_identity[0].id : null 71 | } 72 | 73 | appgw_settings = merge(local.appgw_default_settings, var.appgw_settings) 74 | frontend_ip_configuration_name = var.private_ingress ? "${local.appgw_name}-frontipconfig-priv" : "${local.appgw_name}-frontipconfig" 75 | } 76 | -------------------------------------------------------------------------------- /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 | aks_name = coalesce(var.custom_aks_name, data.azurecaf_name.aks.result) 7 | aks_identity_name = coalesce(var.aks_user_assigned_identity_custom_name, data.azurecaf_name.aks_identity.result) 8 | appgw_identity_name = coalesce(var.appgw_user_assigned_identity_custom_name, data.azurecaf_name.appgw_identity.result) 9 | 10 | appgw_name = coalesce(var.custom_appgw_name, data.azurecaf_name.appgw.result) 11 | } 12 | -------------------------------------------------------------------------------- /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 | default_agent_profile = { 3 | name = var.default_node_pool.name 4 | node_count = var.default_node_pool.node_count 5 | vm_size = var.default_node_pool.vm_size 6 | os_type = var.default_node_pool.os_type 7 | workload_runtime = var.default_node_pool.workload_runtime 8 | zones = var.default_node_pool.zones 9 | enable_auto_scaling = var.default_node_pool.enable_auto_scaling 10 | min_count = var.default_node_pool.min_count 11 | max_count = var.default_node_pool.max_count 12 | type = var.default_node_pool.type 13 | node_taints = var.default_node_pool.node_taints 14 | node_labels = var.default_node_pool.node_labels 15 | orchestrator_version = var.default_node_pool.orchestrator_version 16 | priority = var.default_node_pool.priority 17 | enable_host_encryption = var.default_node_pool.enable_host_encryption 18 | eviction_policy = var.default_node_pool.eviction_policy 19 | vnet_subnet_id = var.nodes_subnet_id 20 | max_pods = var.default_node_pool.max_pods 21 | os_disk_type = var.default_node_pool.os_disk_type 22 | os_disk_size_gb = var.default_node_pool.os_disk_size_gb 23 | enable_node_public_ip = var.default_node_pool.enable_node_public_ip 24 | scale_down_mode = var.default_node_pool.scale_down_mode 25 | } 26 | 27 | # Defaults for Linux profile 28 | # Generally smaller images so can run more pods and require smaller HD 29 | default_linux_node_profile = { 30 | max_pods = 30 31 | os_disk_size_gb = 128 32 | } 33 | 34 | # Defaults for Windows profile 35 | # Do not want to run same number of pods and some images can be quite large 36 | default_windows_node_profile = { 37 | max_pods = 20 38 | os_disk_size_gb = 256 39 | } 40 | 41 | default_node_pool = merge(local.default_agent_profile, var.default_node_pool) 42 | 43 | nodes_pools_with_defaults = [for ap in var.nodes_pools : merge(local.default_agent_profile, ap)] 44 | nodes_pools = [for ap in local.nodes_pools_with_defaults : ap.os_type == "Linux" ? merge(local.default_linux_node_profile, ap) : merge(local.default_windows_node_profile, ap)] 45 | 46 | private_dns_zone = var.private_dns_zone_type == "Custom" ? var.private_dns_zone_id : var.private_dns_zone_type 47 | is_custom_dns_private_cluster = var.private_dns_zone_type == "Custom" && var.private_cluster_enabled 48 | 49 | default_no_proxy_url_list = [ 50 | data.azurerm_virtual_network.aks_vnet[*].address_space, 51 | var.aks_pod_cidr, 52 | var.docker_bridge_cidr, 53 | var.service_cidr, 54 | "localhost", 55 | "konnectivity", 56 | "127.0.0.1", # Localhost 57 | "168.63.129.16", # Azure platform global VIP (https://learn.microsoft.com/en-us/azure/virtual-network/what-is-ip-address-168-63-129-16) 58 | "169.254.169.254", # Azure Instance Metadata Service (IMDS) 59 | ] 60 | } 61 | -------------------------------------------------------------------------------- /modules/infra/README.md: -------------------------------------------------------------------------------- 1 | # Azure Kubernetes Service - Core Azure tools 2 | [![Changelog](https://img.shields.io/badge/changelog-release-green.svg)](CHANGELOG.md) [![Notice](https://img.shields.io/badge/notice-copyright-yellow.svg)](NOTICE) [![Apache V2 License](https://img.shields.io/badge/license-Apache%20V2-orange.svg)](LICENSE) [![TF Registry](https://img.shields.io/badge/terraform-registry-blue.svg)](https://registry.terraform.io/modules/claranet/aks/azurerm/latest/submodules/infra) 3 | 4 | This module deploys the [Azure Active Directory Pod Identity](https://github.com/Azure/aad-pod-identity) and creates some 5 | [Storage Classes](https://kubernetes.io/docs/concepts/storage/storage-classes/) with different types of Azure managed disks (Standard HDD retain and delete, Premium SSD retain and delete). 6 | 7 | 8 | ## Global versioning rule for Claranet Azure modules 9 | 10 | | Module version | Terraform version | AzureRM version | 11 | | -------------- | ----------------- | --------------- | 12 | | >= 7.x.x | 1.3.x | >= 3.0 | 13 | | >= 6.x.x | 1.x | >= 3.0 | 14 | | >= 5.x.x | 0.15.x | >= 2.0 | 15 | | >= 4.x.x | 0.13.x / 0.14.x | >= 2.0 | 16 | | >= 3.x.x | 0.12.x | >= 2.0 | 17 | | >= 2.x.x | 0.12.x | < 2.0 | 18 | | < 2.x.x | 0.11.x | < 2.0 | 19 | 20 | ## Contributing 21 | 22 | If you want to contribute to this repository, feel free to use our [pre-commit](https://pre-commit.com/) git hook configuration 23 | which will help you automatically update and format some files for you by enforcing our Terraform code module best-practices. 24 | 25 | More details are available in the [CONTRIBUTING.md](../../CONTRIBUTING.md#pull-request-process) file. 26 | 27 | ## Usage 28 | 29 | This module is optimized to work with the [Claranet terraform-wrapper](https://github.com/claranet/terraform-wrapper) tool 30 | which set some terraform variables in the environment needed by this module. 31 | More details about variables set by the `terraform-wrapper` available in the [documentation](https://github.com/claranet/terraform-wrapper#environment). 32 | 33 | ```hcl 34 | locals { 35 | allowed_cidrs = ["x.x.x.x", "y.y.y.y"] 36 | } 37 | 38 | module "azure_region" { 39 | source = "claranet/regions/azurerm" 40 | version = "x.x.x" 41 | 42 | azure_region = var.azure_region 43 | } 44 | 45 | module "rg" { 46 | source = "claranet/rg/azurerm" 47 | version = "x.x.x" 48 | 49 | location = module.azure_region.location 50 | client_name = var.client_name 51 | environment = var.environment 52 | stack = var.stack 53 | } 54 | 55 | module "azure_virtual_network" { 56 | source = "claranet/vnet/azurerm" 57 | version = "x.x.x" 58 | 59 | environment = var.environment 60 | location = module.azure_region.location 61 | location_short = module.azure_region.location_short 62 | client_name = var.client_name 63 | stack = var.stack 64 | 65 | resource_group_name = module.rg.resource_group_name 66 | 67 | vnet_cidr = ["10.0.0.0/19"] 68 | } 69 | 70 | module "node_network_subnet" { 71 | source = "claranet/subnet/azurerm" 72 | version = "x.x.x" 73 | 74 | environment = var.environment 75 | location_short = module.azure_region.location_short 76 | client_name = var.client_name 77 | stack = var.stack 78 | 79 | resource_group_name = module.rg.resource_group_name 80 | virtual_network_name = module.azure_virtual_network.virtual_network_name 81 | 82 | name_suffix = "nodes" 83 | 84 | subnet_cidr_list = ["10.0.0.0/20"] 85 | 86 | service_endpoints = ["Microsoft.Storage"] 87 | } 88 | 89 | module "appgw_network_subnet" { 90 | source = "claranet/subnet/azurerm" 91 | version = "x.x.x" 92 | 93 | environment = var.environment 94 | location_short = module.azure_region.location_short 95 | client_name = var.client_name 96 | stack = var.stack 97 | 98 | resource_group_name = module.rg.resource_group_name 99 | virtual_network_name = module.azure_virtual_network.virtual_network_name 100 | 101 | name_suffix = "appgw" 102 | 103 | subnet_cidr_list = ["10.0.20.0/24"] 104 | } 105 | 106 | module "global_run" { 107 | source = "claranet/run/azurerm" 108 | version = "x.x.x" 109 | 110 | client_name = var.client_name 111 | location = module.azure_region.location 112 | location_short = module.azure_region.location_short 113 | environment = var.environment 114 | stack = var.stack 115 | 116 | monitoring_function_splunk_token = var.monitoring_function_splunk_token 117 | 118 | resource_group_name = module.rg.resource_group_name 119 | 120 | tenant_id = var.azure_tenant_id 121 | } 122 | 123 | resource "tls_private_key" "key" { 124 | algorithm = "RSA" 125 | } 126 | 127 | module "aks" { 128 | source = "claranet/aks/azurerm" 129 | version = "x.x.x" 130 | 131 | providers = { 132 | kubernetes = kubernetes.aks-module 133 | helm = helm.aks-module 134 | } 135 | 136 | client_name = var.client_name 137 | environment = var.environment 138 | stack = var.stack 139 | 140 | resource_group_name = module.rg.resource_group_name 141 | location = module.azure_region.location 142 | location_short = module.azure_region.location_short 143 | 144 | private_cluster_enabled = true 145 | service_cidr = "10.0.16.0/22" 146 | kubernetes_version = "1.19.7" 147 | 148 | vnet_id = module.azure_virtual_network.virtual_network_id 149 | nodes_subnet_id = module.node_network_subnet.subnet_id 150 | nodes_pools = [ 151 | { 152 | name = "pool1" 153 | count = 1 154 | vm_size = "Standard_D1_v2" 155 | os_type = "Linux" 156 | os_disk_type = "Ephemeral" 157 | os_disk_size_gb = 30 158 | vnet_subnet_id = module.node_network_subnet.subnet_id 159 | }, 160 | { 161 | name = "bigpool1" 162 | count = 3 163 | vm_size = "Standard_F8s_v2" 164 | os_type = "Linux" 165 | os_disk_size_gb = 30 166 | vnet_subnet_id = module.node_network_subnet.subnet_id 167 | enable_auto_scaling = true 168 | min_count = 3 169 | max_count = 9 170 | } 171 | ] 172 | 173 | linux_profile = { 174 | username = "nodeadmin" 175 | ssh_key = tls_private_key.key.public_key_openssh 176 | } 177 | 178 | oms_log_analytics_workspace_id = module.global_run.log_analytics_workspace_id 179 | azure_policy_enabled = false 180 | 181 | logs_destinations_ids = [module.global_run.log_analytics_workspace_id] 182 | 183 | appgw_subnet_id = module.appgw_network_subnet.subnet_id 184 | 185 | appgw_ingress_controller_values = { "verbosityLevel" = 5, "appgw.shared" = true } 186 | cert_manager_settings = { "cainjector.nodeSelector.agentpool" = "default", "nodeSelector.agentpool" = "default", "webhook.nodeSelector.agentpool" = "default" } 187 | velero_storage_settings = { allowed_cidrs = local.allowed_cidrs } 188 | 189 | container_registries_id = [module.acr.acr_id] 190 | 191 | key_vault_secrets_provider = { 192 | secret_rotation_enabled = true 193 | secret_rotation_interval = "2m" 194 | } 195 | } 196 | 197 | module "acr" { 198 | source = "claranet/acr/azurerm" 199 | version = "x.x.x" 200 | 201 | location = module.azure_region.location 202 | location_short = module.azure_region.location_short 203 | resource_group_name = module.rg.resource_group_name 204 | sku = "Standard" 205 | 206 | client_name = var.client_name 207 | environment = var.environment 208 | stack = var.stack 209 | 210 | logs_destinations_ids = [module.global_run.log_analytics_workspace_id] 211 | } 212 | ``` 213 | 214 | ## Providers 215 | 216 | | Name | Version | 217 | |------|---------| 218 | | azurerm | >= 2.51 | 219 | | helm | >= 2.5.1 | 220 | | kubernetes | >= 2.11.0 | 221 | 222 | ## Modules 223 | 224 | No modules. 225 | 226 | ## Resources 227 | 228 | | Name | Type | 229 | |------|------| 230 | | [azurerm_role_assignment.aad_pod_identity_msi](https://registry.terraform.io/providers/hashicorp/azurerm/latest/docs/resources/role_assignment) | resource | 231 | | [azurerm_user_assigned_identity.aad_pod_identity](https://registry.terraform.io/providers/hashicorp/azurerm/latest/docs/resources/user_assigned_identity) | resource | 232 | | [helm_release.aad_pod_identity](https://registry.terraform.io/providers/hashicorp/helm/latest/docs/resources/release) | resource | 233 | | [kubernetes_cluster_role.containerlogs](https://registry.terraform.io/providers/hashicorp/kubernetes/latest/docs/resources/cluster_role) | resource | 234 | | [kubernetes_cluster_role_binding.containerlogs](https://registry.terraform.io/providers/hashicorp/kubernetes/latest/docs/resources/cluster_role_binding) | resource | 235 | | [kubernetes_namespace.add_pod_identity](https://registry.terraform.io/providers/hashicorp/kubernetes/latest/docs/resources/namespace) | resource | 236 | | [kubernetes_storage_class.managed_premium_delete](https://registry.terraform.io/providers/hashicorp/kubernetes/latest/docs/resources/storage_class) | resource | 237 | | [kubernetes_storage_class.managed_premium_retain](https://registry.terraform.io/providers/hashicorp/kubernetes/latest/docs/resources/storage_class) | resource | 238 | | [kubernetes_storage_class.managed_standard_delete](https://registry.terraform.io/providers/hashicorp/kubernetes/latest/docs/resources/storage_class) | resource | 239 | | [kubernetes_storage_class.managed_standard_retain](https://registry.terraform.io/providers/hashicorp/kubernetes/latest/docs/resources/storage_class) | resource | 240 | | [azurerm_subscription.current](https://registry.terraform.io/providers/hashicorp/azurerm/latest/docs/data-sources/subscription) | data source | 241 | 242 | ## Inputs 243 | 244 | | Name | Description | Type | Default | Required | 245 | |------|-------------|------|---------|:--------:| 246 | | aadpodidentity\_chart\_repository | URL of the Helm chart repository | `string` | `"https://raw.githubusercontent.com/Azure/aad-pod-identity/master/charts"` | no | 247 | | aadpodidentity\_chart\_version | Azure Active Directory Pod Identity Chart version | `string` | `"4.1.9"` | no | 248 | | aadpodidentity\_custom\_name | Custom name for aad pod identity MSI | `string` | `"aad-pod-identity"` | no | 249 | | aadpodidentity\_extra\_tags | Extra tags to add to aad pod identity MSI | `map(string)` | `{}` | no | 250 | | aadpodidentity\_namespace | Kubernetes namespace in which to deploy AAD Pod Identity | `string` | `"system-aadpodid"` | no | 251 | | aadpodidentity\_values | Settings for AAD Pod identity helm Chart

map(object({ 

nmi.nodeSelector.agentpool = string

mic.nodeSelector.agentpool = string

azureIdentity.enabled = bool

azureIdentity.type = string

azureIdentity.resourceID = string

azureIdentity.clientID = string

nmi.micNamespace = string

}))

| `map(string)` | `{}` | no | 252 | | aks\_network\_plugin | AKS network plugin to use. Possible values are `azure` and `kubenet`.
Changing this forces a new resource to be created. | `string` | `"azure"` | no | 253 | | aks\_resource\_group\_name | Name of the AKS Managed resource group. Eg MC\_xxxx | `string` | n/a | yes | 254 | | location | AKS Cluster location | `string` | n/a | yes | 255 | 256 | ## Outputs 257 | 258 | | Name | Description | 259 | |------|-------------| 260 | | aad\_pod\_identity\_azure\_identity | Identity object for AAD Pod Identity | 261 | | aad\_pod\_identity\_client\_id | Client ID of the User MSI used for AAD Pod Identity | 262 | | aad\_pod\_identity\_id | ID of the User MSI used for AAD Pod Identity | 263 | | aad\_pod\_identity\_namespace | Namespace used for AAD Pod Identity | 264 | | aad\_pod\_identity\_principal\_id | Principal ID of the User MSI used for AAD Pod Identity | 265 | 266 | ## Related documentation 267 | 268 | - AAD Pod Identity : [github.com/Azure/aad-pod-identity](https://github.com/Azure/aad-pod-identity) 269 | -------------------------------------------------------------------------------- /modules/infra/k8s-roles.tf: -------------------------------------------------------------------------------- 1 | resource "kubernetes_cluster_role" "containerlogs" { 2 | metadata { 3 | name = "containerhealth-log-reader" 4 | } 5 | rule { 6 | api_groups = [""] 7 | resources = ["pods/log"] 8 | verbs = ["get"] 9 | } 10 | } 11 | 12 | resource "kubernetes_cluster_role_binding" "containerlogs" { 13 | metadata { 14 | name = "containerhealth-read-logs-global" 15 | } 16 | role_ref { 17 | api_group = "rbac.authorization.k8s.io" 18 | kind = "ClusterRole" 19 | name = kubernetes_cluster_role.containerlogs.metadata[0].name 20 | } 21 | subject { 22 | api_group = "rbac.authorization.k8s.io" 23 | kind = "User" 24 | name = "clusterUser" 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /modules/infra/k8s-storages-classes.tf: -------------------------------------------------------------------------------- 1 | resource "kubernetes_storage_class" "managed_standard_retain" { 2 | storage_provisioner = "kubernetes.io/azure-disk" 3 | allow_volume_expansion = true 4 | metadata { 5 | name = "standard-hdd-retain" 6 | } 7 | reclaim_policy = "Retain" 8 | parameters = { 9 | storageaccounttype = "Standard_LRS" 10 | kind = "Managed" 11 | } 12 | } 13 | 14 | resource "kubernetes_storage_class" "managed_standard_delete" { 15 | storage_provisioner = "kubernetes.io/azure-disk" 16 | allow_volume_expansion = true 17 | metadata { 18 | name = "standard-hdd-delete" 19 | } 20 | reclaim_policy = "Delete" 21 | parameters = { 22 | storageaccounttype = "Standard_LRS" 23 | kind = "Managed" 24 | } 25 | } 26 | 27 | resource "kubernetes_storage_class" "managed_premium_retain" { 28 | storage_provisioner = "kubernetes.io/azure-disk" 29 | allow_volume_expansion = true 30 | metadata { 31 | name = "managed-premium-retain" 32 | } 33 | reclaim_policy = "Retain" 34 | parameters = { 35 | storageaccounttype = "Premium_LRS" 36 | kind = "Managed" 37 | } 38 | } 39 | 40 | resource "kubernetes_storage_class" "managed_premium_delete" { 41 | storage_provisioner = "kubernetes.io/azure-disk" 42 | metadata { 43 | name = "managed-premium-delete" 44 | } 45 | reclaim_policy = "Delete" 46 | parameters = { 47 | storageaccounttype = "Premium_LRS" 48 | kind = "Managed" 49 | } 50 | } 51 | -------------------------------------------------------------------------------- /modules/infra/locals-aadpodidentity.tf: -------------------------------------------------------------------------------- 1 | locals { 2 | aadpodidentity_default_values = { 3 | "azureIdentity.enabled" = "true" 4 | "azureIdentity.type" = "0" 5 | "azureIdentity.resourceID" = azurerm_user_assigned_identity.aad_pod_identity.id 6 | "azureIdentity.clientID" = azurerm_user_assigned_identity.aad_pod_identity.client_id 7 | "nmi.micNamespace" = kubernetes_namespace.add_pod_identity.metadata[0].name 8 | "rbac.allowAccessToSecrets" = "false" 9 | } 10 | 11 | aadpodidentity_values = merge(local.aadpodidentity_default_values, var.aadpodidentity_values) 12 | } 13 | -------------------------------------------------------------------------------- /modules/infra/outputs.tf: -------------------------------------------------------------------------------- 1 | output "aad_pod_identity_namespace" { 2 | description = "Namespace used for AAD Pod Identity" 3 | value = kubernetes_namespace.add_pod_identity.metadata[0].name 4 | } 5 | 6 | output "aad_pod_identity_azure_identity" { 7 | description = "Identity object for AAD Pod Identity" 8 | value = azurerm_user_assigned_identity.aad_pod_identity 9 | } 10 | 11 | output "aad_pod_identity_id" { 12 | description = "ID of the User MSI used for AAD Pod Identity" 13 | value = azurerm_user_assigned_identity.aad_pod_identity.id 14 | } 15 | 16 | output "aad_pod_identity_client_id" { 17 | description = "Client ID of the User MSI used for AAD Pod Identity" 18 | value = azurerm_user_assigned_identity.aad_pod_identity.client_id 19 | } 20 | 21 | output "aad_pod_identity_principal_id" { 22 | description = "Principal ID of the User MSI used for AAD Pod Identity" 23 | value = azurerm_user_assigned_identity.aad_pod_identity.principal_id 24 | } 25 | -------------------------------------------------------------------------------- /modules/infra/r-aad-pod-identity.tf: -------------------------------------------------------------------------------- 1 | data "azurerm_subscription" "current" {} 2 | 3 | resource "kubernetes_namespace" "add_pod_identity" { 4 | metadata { 5 | name = var.aadpodidentity_namespace 6 | labels = { 7 | deployed-by = "Terraform" 8 | } 9 | } 10 | } 11 | 12 | resource "helm_release" "aad_pod_identity" { 13 | name = "aad-pod-identity" 14 | repository = var.aadpodidentity_chart_repository 15 | chart = "aad-pod-identity" 16 | version = var.aadpodidentity_chart_version 17 | namespace = kubernetes_namespace.add_pod_identity.metadata[0].name 18 | 19 | dynamic "set" { 20 | for_each = local.aadpodidentity_values 21 | iterator = setting 22 | content { 23 | name = setting.key 24 | value = setting.value 25 | } 26 | } 27 | 28 | # If `Aadpodidentity` is used within an Aks Cluster with Kubenet network Plugin, 29 | # `nmi.allowNetworkPluginKubenet` parameter is set to `true`. 30 | # https://github.com/Azure/aad-pod-identity/issues/949 31 | set { 32 | name = "nmi.allowNetworkPluginKubenet" 33 | value = var.aks_network_plugin == "kubenet" ? "true" : "false" 34 | } 35 | } 36 | 37 | resource "azurerm_user_assigned_identity" "aad_pod_identity" { 38 | location = var.location 39 | name = var.aadpodidentity_custom_name 40 | resource_group_name = var.aks_resource_group_name 41 | 42 | tags = var.aadpodidentity_extra_tags 43 | } 44 | 45 | resource "azurerm_role_assignment" "aad_pod_identity_msi" { 46 | scope = format("/subscriptions/%s/resourceGroups/%s", data.azurerm_subscription.current.subscription_id, var.aks_resource_group_name) 47 | principal_id = azurerm_user_assigned_identity.aad_pod_identity.principal_id 48 | role_definition_name = "Managed Identity Operator" 49 | } 50 | -------------------------------------------------------------------------------- /modules/infra/terraform.tfvars.ci: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/claranet/terraform-azurerm-aks/ee813b08d5bb87d7d7e1443363b46c87b3b6a69b/modules/infra/terraform.tfvars.ci -------------------------------------------------------------------------------- /modules/infra/variables.tf: -------------------------------------------------------------------------------- 1 | variable "aks_resource_group_name" { 2 | description = "Name of the AKS Managed resource group. Eg MC_xxxx" 3 | type = string 4 | } 5 | 6 | variable "aks_network_plugin" { 7 | description = < 58 |
map(object({ 
59 | nmi.nodeSelector.agentpool = string
60 | mic.nodeSelector.agentpool = string
61 | azureIdentity.enabled = bool
62 | azureIdentity.type = string
63 | azureIdentity.resourceID = string
64 | azureIdentity.clientID = string
65 | nmi.micNamespace = string
66 | }))
67 |
68 | EOD 69 | type = map(string) 70 | default = {} 71 | } 72 | -------------------------------------------------------------------------------- /modules/infra/versions.tf: -------------------------------------------------------------------------------- 1 | terraform { 2 | required_version = ">= 1.3" 3 | required_providers { 4 | azurerm = { 5 | source = "hashicorp/azurerm" 6 | version = ">= 2.51" 7 | } 8 | # tflint-ignore: terraform_unused_required_providers 9 | helm = { 10 | source = "hashicorp/helm" 11 | version = ">= 2.5.1" 12 | } 13 | # tflint-ignore: terraform_unused_required_providers 14 | kubernetes = { 15 | source = "hashicorp/kubernetes" 16 | version = ">= 2.11.0" 17 | } 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /outputs.tf: -------------------------------------------------------------------------------- 1 | output "aks_id" { 2 | description = "AKS resource id" 3 | value = azurerm_kubernetes_cluster.aks.id 4 | } 5 | 6 | output "aks_name" { 7 | description = "Name of the AKS cluster" 8 | value = split("/", azurerm_kubernetes_cluster.aks.id)[8] 9 | } 10 | 11 | output "aks_nodes_rg" { 12 | description = "Name of the resource group in which AKS nodes are deployed" 13 | value = azurerm_kubernetes_cluster.aks.node_resource_group 14 | } 15 | 16 | output "aks_nodes_pools_ids" { 17 | description = "Ids of AKS nodes pools" 18 | value = azurerm_kubernetes_cluster_node_pool.node_pools[*].id 19 | } 20 | 21 | output "aks_nodes_pools_names" { 22 | description = "Names of AKS nodes pools" 23 | value = azurerm_kubernetes_cluster_node_pool.node_pools[*].name 24 | } 25 | 26 | output "aks_kube_config_raw" { 27 | description = "Raw kube config to be used by kubectl command" 28 | value = azurerm_kubernetes_cluster.aks.kube_config_raw 29 | sensitive = true 30 | } 31 | 32 | output "aks_kube_config" { 33 | description = "Kube configuration of AKS Cluster" 34 | value = azurerm_kubernetes_cluster.aks.kube_config 35 | sensitive = true 36 | } 37 | 38 | output "aks_user_managed_identity" { 39 | description = "The User Managed Identity used by the AKS cluster." 40 | value = azurerm_user_assigned_identity.aks_user_assigned_identity 41 | } 42 | 43 | output "aks_kubelet_user_managed_identity" { 44 | description = "The Kubelet User Managed Identity used by the AKS cluster." 45 | value = azurerm_kubernetes_cluster.aks.kubelet_identity[0] 46 | } 47 | 48 | output "key_vault_secrets_provider_identity" { 49 | description = "The User Managed Identity used by the Key Vault secrets provider." 50 | value = try(azurerm_kubernetes_cluster.aks.key_vault_secrets_provider[0].secret_identity[0], null) 51 | } 52 | 53 | ########################## 54 | # AGIC outputs 55 | ########################## 56 | output "agic_namespace" { 57 | description = "Namespace used for AGIC" 58 | value = module.appgw.namespace 59 | } 60 | 61 | output "application_gateway_id" { 62 | description = "Id of the application gateway used by AKS" 63 | value = module.appgw.application_gateway_id 64 | } 65 | 66 | output "application_gateway_identity_principal_id" { 67 | description = "Id of the managed service identity of the application gateway used by AKS" 68 | value = var.appgw_identity_enabled ? azurerm_user_assigned_identity.appgw_assigned_identity[0].principal_id : null 69 | } 70 | 71 | output "application_gateway_name" { 72 | description = "Name of the application gateway used by AKS" 73 | value = module.appgw.application_gateway_name 74 | } 75 | 76 | output "public_ip_id" { 77 | description = "Id of the public ip used by AKS application gateway" 78 | value = module.appgw.public_ip_id 79 | } 80 | 81 | output "public_ip_name" { 82 | value = module.appgw.public_ip_name 83 | description = "Name of the public ip used by AKS application gateway" 84 | } 85 | 86 | ########################## 87 | # AAD Pod Identity outputs 88 | ########################## 89 | output "aad_pod_identity_namespace" { 90 | description = "Namespace used for AAD Pod Identity" 91 | value = module.infra.aad_pod_identity_namespace 92 | } 93 | 94 | output "aad_pod_identity_azure_identity" { 95 | description = "Identity object for AAD Pod Identity" 96 | value = module.infra.aad_pod_identity_azure_identity 97 | } 98 | 99 | ########################## 100 | # Cert Manager outputs 101 | ########################## 102 | output "cert_manager_namespace" { 103 | description = "Namespace used for Cert Manager" 104 | value = module.certmanager.namespace 105 | } 106 | 107 | ########################## 108 | # Velero outputs 109 | ########################## 110 | output "kured_namespace" { 111 | description = "Namespace used for Kured" 112 | value = module.kured.namespace 113 | } 114 | 115 | ########################## 116 | # Velero outputs 117 | ########################## 118 | output "velero_namespace" { 119 | description = "Namespace used for Velero" 120 | value = module.velero.namespace 121 | } 122 | 123 | output "velero_storage_account" { 124 | description = "Storage Account on which Velero data is stored." 125 | value = module.velero.storage_account 126 | sensitive = true 127 | } 128 | 129 | output "velero_storage_account_container" { 130 | description = "Container in Storage Account on which Velero data is stored." 131 | value = module.velero.storage_account_container 132 | } 133 | 134 | output "velero_identity" { 135 | description = "Azure Identity used for Velero pods" 136 | value = module.velero.velero_identity 137 | } 138 | 139 | output "oidc_issuer_url" { 140 | description = "The URL of the OpenID Connect issuer." 141 | value = azurerm_kubernetes_cluster.aks.oidc_issuer_url 142 | } 143 | -------------------------------------------------------------------------------- /r-acr-role.tf: -------------------------------------------------------------------------------- 1 | resource "azurerm_role_assignment" "aks_acr_pull_allowed" { 2 | for_each = toset(var.container_registries_id) 3 | 4 | principal_id = azurerm_user_assigned_identity.aks_user_assigned_identity.principal_id 5 | scope = each.value 6 | role_definition_name = "AcrPull" 7 | } 8 | -------------------------------------------------------------------------------- /r-aks.tf: -------------------------------------------------------------------------------- 1 | #tfsec:ignore:azure-container-use-rbac-permissions 2 | resource "azurerm_kubernetes_cluster" "aks" { 3 | name = local.aks_name 4 | location = var.location 5 | resource_group_name = var.resource_group_name 6 | dns_prefix = replace(local.aks_name, "/[\\W_]/", "-") 7 | kubernetes_version = var.kubernetes_version 8 | sku_tier = var.aks_sku_tier 9 | api_server_authorized_ip_ranges = var.private_cluster_enabled ? null : var.api_server_authorized_ip_ranges 10 | node_resource_group = var.node_resource_group 11 | enable_pod_security_policy = var.enable_pod_security_policy 12 | oidc_issuer_enabled = var.oidc_issuer_enabled 13 | http_application_routing_enabled = var.http_application_routing_enabled 14 | 15 | private_cluster_enabled = var.private_cluster_enabled 16 | private_dns_zone_id = var.private_cluster_enabled ? local.private_dns_zone : null 17 | 18 | dynamic "aci_connector_linux" { 19 | for_each = var.aci_subnet_id != null && var.aks_network_plugin != "kubenet" ? [true] : [] 20 | content { 21 | subnet_name = element(split("/", var.aci_subnet_id), length(split("/", var.aci_subnet_id)) - 1) 22 | } 23 | } 24 | 25 | default_node_pool { 26 | name = local.default_node_pool.name 27 | vm_size = local.default_node_pool.vm_size 28 | zones = local.default_node_pool.zones 29 | enable_auto_scaling = local.default_node_pool.enable_auto_scaling 30 | node_count = local.default_node_pool.enable_auto_scaling ? null : local.default_node_pool.node_count 31 | min_count = local.default_node_pool.enable_auto_scaling ? local.default_node_pool.min_count : null 32 | max_count = local.default_node_pool.enable_auto_scaling ? local.default_node_pool.max_count : null 33 | max_pods = local.default_node_pool.max_pods 34 | os_disk_type = local.default_node_pool.os_disk_type 35 | os_disk_size_gb = local.default_node_pool.os_disk_size_gb 36 | type = local.default_node_pool.type 37 | vnet_subnet_id = local.default_node_pool.vnet_subnet_id 38 | node_taints = local.default_node_pool.node_taints 39 | node_labels = local.default_node_pool.node_labels 40 | scale_down_mode = local.default_node_pool.scale_down_mode 41 | tags = merge(local.default_tags, var.default_node_pool_tags) 42 | } 43 | 44 | identity { 45 | type = "UserAssigned" 46 | identity_ids = [azurerm_user_assigned_identity.aks_user_assigned_identity.id] 47 | } 48 | 49 | dynamic "auto_scaler_profile" { 50 | for_each = var.auto_scaler_profile != null ? [var.auto_scaler_profile] : [] 51 | content { 52 | balance_similar_node_groups = try(auto_scaler_profile.value.balance_similar_node_groups, null) 53 | expander = try(auto_scaler_profile.value.expander, null) 54 | max_graceful_termination_sec = try(auto_scaler_profile.value.max_graceful_termination_sec, null) 55 | max_node_provisioning_time = try(auto_scaler_profile.value.max_node_provisioning_time, null) 56 | max_unready_nodes = try(auto_scaler_profile.value.max_unready_nodes, null) 57 | max_unready_percentage = try(auto_scaler_profile.value.max_unready_percentage, null) 58 | new_pod_scale_up_delay = try(auto_scaler_profile.value.new_pod_scale_up_delay, null) 59 | scale_down_delay_after_add = try(auto_scaler_profile.value.scale_down_delay_after_add, null) 60 | scale_down_delay_after_delete = try(auto_scaler_profile.value.scale_down_delay_after_delete, null) 61 | scale_down_delay_after_failure = try(auto_scaler_profile.value.scale_down_delay_after_failure, null) 62 | scan_interval = try(auto_scaler_profile.value.scan_interval, null) 63 | scale_down_unneeded = try(auto_scaler_profile.value.scale_down_unneeded, null) 64 | scale_down_unready = try(auto_scaler_profile.value.scale_down_unready, null) 65 | scale_down_utilization_threshold = try(auto_scaler_profile.value.scale_down_utilization_threshold, null) 66 | empty_bulk_delete_max = try(auto_scaler_profile.value.empty_bulk_delete_max, null) 67 | skip_nodes_with_local_storage = try(auto_scaler_profile.value.skip_nodes_with_local_storage, null) 68 | skip_nodes_with_system_pods = try(auto_scaler_profile.value.skip_nodes_with_system_pods, null) 69 | } 70 | } 71 | 72 | oms_agent { 73 | log_analytics_workspace_id = var.oms_log_analytics_workspace_id 74 | } 75 | 76 | azure_policy_enabled = var.azure_policy_enabled 77 | 78 | dynamic "linux_profile" { 79 | for_each = var.linux_profile != null ? [true] : [] 80 | iterator = lp 81 | content { 82 | admin_username = var.linux_profile.username 83 | 84 | ssh_key { 85 | key_data = var.linux_profile.ssh_key 86 | } 87 | } 88 | } 89 | 90 | dynamic "http_proxy_config" { 91 | for_each = var.aks_http_proxy_settings != null ? ["enabled"] : [] 92 | content { 93 | http_proxy = var.aks_http_proxy_settings.http_proxy_url 94 | https_proxy = var.aks_http_proxy_settings.https_proxy_url 95 | no_proxy = distinct(flatten(concat(local.default_no_proxy_url_list, var.aks_http_proxy_settings.no_proxy_url_list))) 96 | trusted_ca = var.aks_http_proxy_settings.trusted_ca 97 | } 98 | } 99 | 100 | network_profile { 101 | network_plugin = var.aks_network_plugin 102 | network_policy = var.aks_network_plugin == "azure" ? "azure" : var.aks_network_policy 103 | network_mode = var.aks_network_plugin == "azure" ? "transparent" : null 104 | dns_service_ip = cidrhost(var.service_cidr, 10) 105 | docker_bridge_cidr = var.docker_bridge_cidr 106 | service_cidr = var.service_cidr 107 | load_balancer_sku = "standard" 108 | outbound_type = var.outbound_type 109 | pod_cidr = var.aks_network_plugin == "kubenet" ? var.aks_pod_cidr : null 110 | } 111 | 112 | dynamic "key_vault_secrets_provider" { 113 | for_each = var.key_vault_secrets_provider[*] 114 | content { 115 | secret_rotation_enabled = key_vault_secrets_provider.value.secret_rotation_enabled 116 | secret_rotation_interval = key_vault_secrets_provider.value.secret_rotation_interval 117 | } 118 | } 119 | 120 | depends_on = [ 121 | azurerm_role_assignment.aks_uai_private_dns_zone_contributor, 122 | azurerm_role_assignment.aks_uai_route_table_contributor, 123 | ] 124 | 125 | tags = merge(local.default_tags, var.extra_tags) 126 | } 127 | 128 | resource "azurerm_kubernetes_cluster_node_pool" "node_pools" { 129 | count = length(local.nodes_pools) 130 | kubernetes_cluster_id = azurerm_kubernetes_cluster.aks.id 131 | name = local.nodes_pools[count.index].name 132 | vm_size = local.nodes_pools[count.index].vm_size 133 | os_type = local.nodes_pools[count.index].os_type 134 | orchestrator_version = local.nodes_pools[count.index].orchestrator_version 135 | os_disk_type = local.nodes_pools[count.index].os_disk_type 136 | os_disk_size_gb = local.nodes_pools[count.index].os_disk_size_gb 137 | priority = local.nodes_pools[count.index].priority 138 | vnet_subnet_id = local.nodes_pools[count.index].vnet_subnet_id 139 | enable_host_encryption = local.nodes_pools[count.index].enable_host_encryption 140 | eviction_policy = local.nodes_pools[count.index].eviction_policy 141 | enable_auto_scaling = local.nodes_pools[count.index].enable_auto_scaling 142 | node_count = local.nodes_pools[count.index].enable_auto_scaling ? null : local.nodes_pools[count.index].node_count 143 | min_count = local.nodes_pools[count.index].enable_auto_scaling ? local.nodes_pools[count.index].min_count : null 144 | max_count = local.nodes_pools[count.index].enable_auto_scaling ? local.nodes_pools[count.index].max_count : null 145 | max_pods = local.nodes_pools[count.index].max_pods 146 | node_labels = local.nodes_pools[count.index].node_labels 147 | node_taints = local.nodes_pools[count.index].node_taints 148 | enable_node_public_ip = local.nodes_pools[count.index].enable_node_public_ip 149 | workload_runtime = local.nodes_pools[count.index].workload_runtime 150 | zones = local.nodes_pools[count.index].zones 151 | scale_down_mode = local.nodes_pools[count.index].scale_down_mode 152 | tags = merge(local.default_tags, var.node_pool_tags) 153 | } 154 | 155 | # Allow user assigned identity to manage AKS items in MC_xxx RG 156 | resource "azurerm_role_assignment" "aks_user_assigned" { 157 | principal_id = azurerm_kubernetes_cluster.aks.kubelet_identity[0].object_id 158 | scope = format("/subscriptions/%s/resourceGroups/%s", data.azurerm_subscription.current.subscription_id, azurerm_kubernetes_cluster.aks.node_resource_group) 159 | role_definition_name = "Contributor" 160 | } 161 | -------------------------------------------------------------------------------- /r-identity.tf: -------------------------------------------------------------------------------- 1 | resource "azurerm_user_assigned_identity" "aks_user_assigned_identity" { 2 | name = local.aks_identity_name 3 | resource_group_name = coalesce(var.aks_user_assigned_identity_resource_group_name, var.resource_group_name) 4 | location = var.location 5 | 6 | tags = merge(local.default_tags, var.aks_user_assigned_identity_tags) 7 | } 8 | 9 | resource "azurerm_role_assignment" "aks_uai_private_dns_zone_contributor" { 10 | count = local.is_custom_dns_private_cluster && var.private_dns_zone_role_assignment_enabled ? 1 : 0 11 | 12 | scope = var.private_dns_zone_id 13 | role_definition_name = "Private DNS Zone Contributor" 14 | principal_id = azurerm_user_assigned_identity.aks_user_assigned_identity.principal_id 15 | } 16 | 17 | resource "azurerm_role_assignment" "aks_uai_vnet_network_contributor" { 18 | count = local.is_custom_dns_private_cluster ? 1 : 0 19 | 20 | scope = var.vnet_id 21 | role_definition_name = "Network Contributor" 22 | principal_id = azurerm_user_assigned_identity.aks_user_assigned_identity.principal_id 23 | } 24 | 25 | resource "azurerm_role_assignment" "aks_kubelet_uai_vnet_network_contributor" { 26 | count = local.is_custom_dns_private_cluster ? 1 : 0 27 | 28 | scope = var.vnet_id 29 | role_definition_name = "Network Contributor" 30 | principal_id = azurerm_kubernetes_cluster.aks.kubelet_identity[0].object_id 31 | } 32 | 33 | # Application gateway identity stuff, used to gather ssl certificate from keyvault 34 | # https://github.com/Azure/application-gateway-kubernetes-ingress/issues/999 35 | # https://github.com/Azure/application-gateway-kubernetes-ingress/blob/master/docs/features/appgw-ssl-certificate.md#configure-certificate-from-key-vault-to-appgw 36 | resource "azurerm_user_assigned_identity" "appgw_assigned_identity" { 37 | count = var.appgw_identity_enabled ? 1 : 0 38 | 39 | name = local.appgw_identity_name 40 | resource_group_name = coalesce(var.appgw_user_assigned_identity_resource_group_name, var.resource_group_name) 41 | location = var.location 42 | } 43 | 44 | resource "azurerm_role_assignment" "aad_pod_identity_mio_appgw_identity" { 45 | count = var.appgw_identity_enabled ? 1 : 0 46 | 47 | scope = azurerm_user_assigned_identity.appgw_assigned_identity[0].id 48 | role_definition_name = "Managed Identity Operator" 49 | principal_id = module.infra.aad_pod_identity_principal_id 50 | } 51 | 52 | # Role assignment for ACI, if ACI is enabled 53 | data "azuread_service_principal" "aci_identity" { 54 | count = var.aci_subnet_id != null ? 1 : 0 55 | display_name = "aciconnectorlinux-${coalesce(var.custom_aks_name, local.aks_name)}" 56 | depends_on = [azurerm_kubernetes_cluster.aks] 57 | } 58 | 59 | resource "azurerm_role_assignment" "aci_assignment" { 60 | count = var.aci_subnet_id != null ? 1 : 0 61 | scope = var.aci_subnet_id 62 | role_definition_name = "Network Contributor" 63 | principal_id = data.azuread_service_principal.aci_identity[0].id 64 | } 65 | -------------------------------------------------------------------------------- /r-infra.tf: -------------------------------------------------------------------------------- 1 | module "infra" { 2 | source = "./modules/infra" 3 | 4 | aks_resource_group_name = azurerm_kubernetes_cluster.aks.node_resource_group 5 | aks_network_plugin = var.aks_network_plugin 6 | 7 | location = var.location 8 | 9 | aadpodidentity_chart_version = var.aadpodidentity_chart_version 10 | aadpodidentity_chart_repository = var.aadpodidentity_chart_repository 11 | aadpodidentity_namespace = var.aadpodidentity_namespace 12 | aadpodidentity_values = var.aadpodidentity_values 13 | aadpodidentity_custom_name = var.aadpodidentity_custom_name 14 | 15 | aadpodidentity_extra_tags = var.aadpodidentity_extra_tags 16 | } 17 | -------------------------------------------------------------------------------- /r-logs.tf: -------------------------------------------------------------------------------- 1 | module "diagnostic_settings" { 2 | source = "claranet/diagnostic-settings/azurerm" 3 | version = "~> 6.5.0" 4 | 5 | resource_id = azurerm_kubernetes_cluster.aks.id 6 | 7 | logs_destinations_ids = var.logs_destinations_ids 8 | log_categories = var.logs_categories 9 | metric_categories = var.logs_metrics_categories 10 | 11 | use_caf_naming = var.use_caf_naming 12 | custom_name = var.custom_diagnostic_settings_name 13 | name_prefix = var.name_prefix 14 | name_suffix = var.name_suffix 15 | 16 | excluded_log_categories = var.logs_kube_audit_enabled ? [] : ["kube-audit", "kube-audit-admin"] 17 | } 18 | -------------------------------------------------------------------------------- /r-naming.tf: -------------------------------------------------------------------------------- 1 | data "azurecaf_name" "aks" { 2 | name = var.stack 3 | resource_type = "azurerm_kubernetes_cluster" 4 | prefixes = var.name_prefix == "" ? null : [local.name_prefix] 5 | suffixes = compact([var.client_name, var.location_short, var.environment, local.name_suffix, var.use_caf_naming ? "" : "aks"]) 6 | use_slug = var.use_caf_naming 7 | clean_input = true 8 | separator = "-" 9 | } 10 | 11 | data "azurecaf_name" "aks_identity" { 12 | name = var.stack 13 | resource_type = "azurerm_user_assigned_identity" 14 | prefixes = compact(["aks", local.name_prefix]) 15 | suffixes = compact([var.client_name, var.location_short, var.environment, local.name_suffix, var.use_caf_naming ? "" : "identity"]) 16 | use_slug = var.use_caf_naming 17 | clean_input = true 18 | separator = "-" 19 | } 20 | 21 | data "azurecaf_name" "appgw_identity" { 22 | name = var.stack 23 | resource_type = "azurerm_user_assigned_identity" 24 | prefixes = compact(["appgw", local.name_prefix]) 25 | suffixes = compact([var.client_name, var.location_short, var.environment, local.name_suffix, var.use_caf_naming ? "" : "identity"]) 26 | use_slug = var.use_caf_naming 27 | clean_input = true 28 | separator = "-" 29 | } 30 | 31 | data "azurecaf_name" "appgw" { 32 | name = var.stack 33 | resource_type = "azurerm_application_gateway" 34 | prefixes = compact(["aks", local.name_prefix]) 35 | suffixes = compact([var.client_name, var.location_short, var.environment, local.name_suffix, var.use_caf_naming ? "" : "appgw"]) 36 | use_slug = var.use_caf_naming 37 | clean_input = true 38 | separator = "-" 39 | } 40 | -------------------------------------------------------------------------------- /r-network.tf: -------------------------------------------------------------------------------- 1 | resource "azurerm_role_assignment" "aks_uai_route_table_contributor" { 2 | count = var.aks_network_plugin == "kubenet" && var.outbound_type == "userDefinedRouting" ? 1 : 0 3 | 4 | scope = var.aks_route_table_id 5 | role_definition_name = "Contributor" 6 | principal_id = azurerm_user_assigned_identity.aks_user_assigned_identity.principal_id 7 | } 8 | -------------------------------------------------------------------------------- /r-policy.tf: -------------------------------------------------------------------------------- 1 | # https://docs.microsoft.com/en-us/azure/aks/use-azure-ad-pod-identity#using-kubenet-network-plugin-with-azure-active-directory-pod-managed-identities 2 | # https://azure.github.io/aad-pod-identity/docs/configure/aad_pod_identity_on_kubenet/ 3 | data "azurerm_policy_definition" "aks_policy_kubenet_aadpodidentity_definition" { 4 | for_each = toset(var.aadpodidentity_kubenet_policy_enabled ? ["enabled"] : []) 5 | 6 | name = "c26596ff-4d70-4e6a-9a30-c2506bd2f80c" 7 | } 8 | 9 | # https://github.com/hashicorp/terraform-provider-azurerm/issues/8527 10 | resource "azurerm_resource_policy_assignment" "aks_policy_kubenet_aadpodidentity_assignment" { 11 | for_each = toset(var.aadpodidentity_kubenet_policy_enabled ? ["enabled"] : []) 12 | 13 | name = "aks_policy_kubenet_aadpodidentity_assignment" 14 | resource_id = azurerm_kubernetes_cluster.aks.id 15 | policy_definition_id = data.azurerm_policy_definition.aks_policy_kubenet_aadpodidentity_definition["enabled"].id 16 | enforce = true 17 | 18 | parameters = <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 = "test-rg" 7 | 8 | extra_tags = { 9 | foo = "bar" 10 | } 11 | service_cidr = "192.168.1.0/24" 12 | nodes_pools = [ 13 | { 14 | name = "nodepool1" 15 | vm_size = "Standard_B4ms" 16 | os_type = "Linux" 17 | os_disk_size_gb = 100 18 | vnet_subnet_id = "subnet_id" 19 | max_pods = 110 20 | enable_auto_scaling = true 21 | count = 1 22 | min_count = 1 23 | max_count = 10 24 | }, 25 | { 26 | name = "nodepool2" 27 | vm_size = "Standard_B4ms" 28 | os_type = "Linux" 29 | os_disk_size_gb = 100 30 | vnet_subnet_id = "subnet_id" 31 | max_pods = 110 32 | enable_auto_scaling = true 33 | count = 1 34 | max_count = 10 35 | min_count = 1 36 | } 37 | ] 38 | -------------------------------------------------------------------------------- /tools/agic/README.md: -------------------------------------------------------------------------------- 1 | # Azure Kubernetes Service - Application Gateway Ingress Controller tool submodule 2 | [![Changelog](https://img.shields.io/badge/changelog-release-green.svg)](CHANGELOG.md) [![Notice](https://img.shields.io/badge/notice-copyright-yellow.svg)](NOTICE) [![Apache V2 License](https://img.shields.io/badge/license-Apache%20V2-orange.svg)](LICENSE) [![TF Registry](https://img.shields.io/badge/terraform-registry-blue.svg)](https://registry.terraform.io/modules/claranet/aks/azurerm/latest/submodules/agic) 3 | 4 | This module allows you to create an application gateway ingress controller with its associated Application Gateway v2 on an existing AKS cluster. 5 | 6 | ## Version compatibility 7 | 8 | | Module version | Terraform version | AzureRM version | Helm version | Kubernetes version | 9 | |-------------------|-------------------|-----------------|--------------|--------------------| 10 | | >= 4.x.x | >= 0.13.x | >= 2.0 | = 1.1.1 | ~> 1.11.1 | 11 | | >= 3.x.x | 0.12.x | >= 2.0 | = 1.1.1 | ~> 1.11.1 | 12 | | >= 2.x.x, < 3.x.x | 0.12.x | < 2.0 | N/A | N/A | 13 | | < 2.x.x | 0.11.x | < 2.0 | N/A | N/A | 14 | 15 | ## Usage 16 | 17 | This module is optimized to work with the [Claranet terraform-wrapper](https://github.com/claranet/terraform-wrapper) tool 18 | which set some terraform variables in the environment needed by this module. 19 | More details about variables set by the `terraform-wrapper` available in the [documentation](https://github.com/claranet/terraform-wrapper#environment). 20 | 21 | ```hcl 22 | module "rg" { 23 | source = "claranet/rg/azurerm" 24 | version = "x.x.x" 25 | 26 | location = module.azure-region.location 27 | client_name = var.client_name 28 | environment = var.environment 29 | stack = var.stack 30 | 31 | custom_rg_name = local.support_bastion_rg_name 32 | } 33 | 34 | module "azure-region" { 35 | source = "claranet/regions/azurerm" 36 | version = "x.x.x" 37 | 38 | azure_region = var.azure_region 39 | } 40 | 41 | module "agic" { 42 | source = "claranet/aks/azurerm//modules/tools/agic" 43 | version = "x.x.x" 44 | 45 | client_name = var.client_name 46 | environment = var.environment 47 | stack = var.stack 48 | 49 | resource_group_name = module.rg.resource_group_name 50 | location = module.azure-region.location 51 | location_short = module.azure-region.location_short 52 | 53 | appgw_subnet_id = "/subscriptions/xxxxxxx/xxxxx/xxxxxxx" 54 | appgw_ingress_contoller_values = { "verbosityLevel" = "5" } 55 | app_gateway_tags = {"tag1" = "value1"} 56 | 57 | aks_aad_pod_identity_id = "/subscription/xxx/xxx/xxx" 58 | aks_aad_pod_identity_client_id = "xxx-xxxxx-xxxx-xxxx" 59 | aks_aad_pod_identity_principal_id = "xxxx-xxxx-xxxx-xxxx" 60 | aks_name = "MyClusterName" 61 | 62 | diagnostics = { 63 | enabled = true 64 | destination = "/subscription/xxx/xxx/workspace/id" 65 | eventhub_name = null 66 | logs = ["all"] 67 | metrics = ["all"] 68 | } 69 | } 70 | ``` 71 | 72 | 73 | ## Providers 74 | 75 | | Name | Version | 76 | |------|---------| 77 | | azurerm | ~> 3.22 | 78 | | helm | >= 2.5.1 | 79 | | kubernetes | >= 2.11.0 | 80 | 81 | ## Modules 82 | 83 | | Name | Source | Version | 84 | |------|--------|---------| 85 | | diagnostic\_settings\_appgw | claranet/diagnostic-settings/azurerm | 6.5.0 | 86 | 87 | ## Resources 88 | 89 | | Name | Type | 90 | |------|------| 91 | | [azurerm_application_gateway.app_gateway](https://registry.terraform.io/providers/hashicorp/azurerm/latest/docs/resources/application_gateway) | resource | 92 | | [azurerm_public_ip.ip](https://registry.terraform.io/providers/hashicorp/azurerm/latest/docs/resources/public_ip) | resource | 93 | | [azurerm_role_assignment.agic](https://registry.terraform.io/providers/hashicorp/azurerm/latest/docs/resources/role_assignment) | resource | 94 | | [azurerm_role_assignment.agic_rg](https://registry.terraform.io/providers/hashicorp/azurerm/latest/docs/resources/role_assignment) | resource | 95 | | [helm_release.agic](https://registry.terraform.io/providers/hashicorp/helm/latest/docs/resources/release) | resource | 96 | | [kubernetes_namespace.agic](https://registry.terraform.io/providers/hashicorp/kubernetes/latest/docs/resources/namespace) | resource | 97 | | [azurerm_resource_group.resource_group](https://registry.terraform.io/providers/hashicorp/azurerm/latest/docs/data-sources/resource_group) | data source | 98 | | [azurerm_subscription.current](https://registry.terraform.io/providers/hashicorp/azurerm/latest/docs/data-sources/subscription) | data source | 99 | 100 | ## Inputs 101 | 102 | | Name | Description | Type | Default | Required | 103 | |------|-------------|------|---------|:--------:| 104 | | agic\_chart\_repository | Helm chart repository URL. | `string` | `"https://appgwingress.blob.core.windows.net/ingress-azure-helm-package/"` | no | 105 | | agic\_chart\_version | Version of the Helm chart. | `string` | `"1.5.2"` | no | 106 | | agic\_enabled | Enable application gateway ingress controller. | `bool` | `true` | no | 107 | | agic\_helm\_version | [DEPRECATED] Version of Helm chart to deploy. | `string` | `null` | no | 108 | | aks\_aad\_pod\_identity\_client\_id | AAD Identity client\_id used by AKS. | `string` | n/a | yes | 109 | | aks\_aad\_pod\_identity\_id | AAD Identity id used by AKS. | `string` | n/a | yes | 110 | | aks\_aad\_pod\_identity\_principal\_id | AAD Identity principal\_id used by AKS. | `string` | n/a | yes | 111 | | app\_gateway\_subnet\_id | ID of the subnet to use with the application gateway. | `string` | n/a | yes | 112 | | app\_gateway\_tags | Tags to apply on the Application gateway. | `map(string)` | n/a | yes | 113 | | appgw\_backend\_http\_settings | List of maps including backend http settings configurations. | `any` |
[
{
"fake": "fake"
}
]
| no | 114 | | appgw\_backend\_pools | List of maps including backend pool configurations. | `any` |
[
{
"fake": "fake"
}
]
| no | 115 | | appgw\_http\_listeners | List of maps including http listeners configurations. | `list(map(string))` |
[
{
"fake": "fake"
}
]
| no | 116 | | appgw\_ingress\_values | Application Gateway Ingress Controller settings. | `map(string)` | `{}` | no | 117 | | appgw\_private\_ip | Private IP for Application Gateway. Used when variable `private_ingress` is set to `true`. | `string` | `null` | no | 118 | | appgw\_probes | List of maps including request probes configurations. | `any` |
[
{
"fake": "fake"
}
]
| no | 119 | | appgw\_redirect\_configuration | List of maps including redirect configurations. | `list(map(string))` | `[]` | no | 120 | | appgw\_rewrite\_rule\_set | Application gateway's rewrite rules | `any` | `[]` | no | 121 | | appgw\_routings | List of maps including request routing rules configurations. | `list(map(string))` |
[
{
"fake": "fake"
}
]
| no | 122 | | appgw\_url\_path\_map | List of maps including url path map configurations. | `any` | `[]` | no | 123 | | application\_gateway\_id | ID of an existing Application Gateway to use as an AGIC. `use_existing_application_gateway` must be set to `true`. | `string` | `null` | no | 124 | | authentication\_certificate\_configs | List of maps including authentication certificate configurations. | `list(map(string))` | `[]` | no | 125 | | client\_name | Client name/account used in naming | `string` | n/a | yes | 126 | | custom\_diagnostic\_settings\_name | Custom name of the diagnostics settings, name will be 'default' if not set. | `string` | `"default"` | no | 127 | | disabled\_rule\_group\_settings | Appgw WAF rules group to disable. |
list(object({
rule_group_name = string
rules = list(string)
}))
| `[]` | no | 128 | | enabled\_waf | Enable WAF or not. | `bool` | `false` | no | 129 | | environment | Project's environment. | `string` | n/a | yes | 130 | | file\_upload\_limit\_mb | WAF configuration of the file upload limit in MB. | `number` | `100` | no | 131 | | firewall\_mode | Appgw WAF mode. | `string` | `"Detection"` | no | 132 | | frontend\_ip\_configuration\_name | Name of the appgw frontend ip configuration. | `string` | n/a | yes | 133 | | frontend\_port\_settings | Appgw frontent port settings. | `list(map(string))` |
[
{
"fake": "fake"
}
]
| no | 134 | | frontend\_priv\_ip\_configuration\_name | Name of the appgw frontend private ip configuration. | `string` | `null` | no | 135 | | gateway\_identity\_id | Id of the application gateway MSI. | `string` | `null` | no | 136 | | gateway\_ip\_configuration\_name | Name of the appgw gateway ip configuration. | `string` | n/a | yes | 137 | | ip\_allocation\_method | Allocation method of the IP address. | `string` | `"Static"` | no | 138 | | ip\_name | Name of the applications gateway's public ip address | `string` | n/a | yes | 139 | | ip\_sku | SKU of the public ip address. | `string` | `"Standard"` | no | 140 | | ip\_tags | Specific tags for the public ip address. | `map(string)` | n/a | yes | 141 | | location | Location of application gateway. | `string` | n/a | yes | 142 | | location\_short | Short name of Azure regions to use. | `string` | n/a | yes | 143 | | logs\_categories | Log categories to send to destinations. | `list(string)` | `null` | no | 144 | | 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 specify an Azure EventHub to send logs and metrics to, you need to provide a formated string with 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 | 145 | | logs\_metrics\_categories | Metrics categories to send to destinations. | `list(string)` | `null` | no | 146 | | logs\_retention\_days | Number of days to keep logs on storage account. | `number` | `30` | no | 147 | | max\_request\_body\_size\_kb | WAF configuration of the max request body size in KB. | `number` | `128` | no | 148 | | name | Name of the application gateway. | `string` | n/a | yes | 149 | | name\_prefix | Optional prefix for the generated name | `string` | `""` | no | 150 | | name\_suffix | Optional suffix for the generated name | `string` | `""` | no | 151 | | policy\_name | Name of the SSLPolicy to use with Appgw. | `string` | `"AppGwSslPolicy20170401S"` | no | 152 | | private\_ingress | Private ingress boolean variable. When `true`, the default http listener will listen on private IP instead of the public IP. | `bool` | `false` | no | 153 | | request\_body\_check | WAF should check the request body. | `bool` | `true` | no | 154 | | resource\_group\_name | Name of the resource group in which to deploy the application gateway. | `string` | n/a | yes | 155 | | rule\_set\_type | WAF rules set type. | `string` | `"OWASP"` | no | 156 | | rule\_set\_version | WAF rules set version. | `string` | `"3.0"` | no | 157 | | sku\_capacity | Application gateway's SKU capacity. | `string` | `2` | no | 158 | | sku\_name | Application gateway's SKU name. | `string` | `"Standard_v2"` | no | 159 | | sku\_tier | Application gateway's SKU tier. | `string` | `"Standard_v2"` | no | 160 | | ssl\_certificates\_configs | List of maps including ssl certificates configurations. | `list(map(string))` | `[]` | no | 161 | | stack | Project's stack. | `string` | n/a | yes | 162 | | trusted\_root\_certificate\_configs | Trusted root certificate configurations. | `list(map(string))` | `[]` | no | 163 | | use\_caf\_naming | Use the Azure CAF naming provider to generate default resource name. `custom_aks_name` override this if set. Legacy default name is used if this is set to `false`. | `bool` | `true` | no | 164 | | use\_existing\_application\_gateway | True to use an existing Application Gateway instead of creating a new one.
If true you may use appgw\_ingress\_controller\_values = { appgw.shared = true } to tell AGIC to not erase the whole Application Gateway configuration with its own configuration.
You also have to deploy AzureIngressProhibitedTarget CRD.
https://github.com/Azure/application-gateway-kubernetes-ingress/blob/072626cb4e37f7b7a1b0c4578c38d1eadc3e8701/docs/setup/install-existing.md#multi-cluster--shared-app-gateway | `bool` | `false` | no | 165 | | waf\_exclusion\_settings | Appgw WAF exclusion settings. | `list(map(string))` | `[]` | no | 166 | | zones | Application gateway's Zones to use. | `list(string)` |
[
"1",
"2",
"3"
]
| no | 167 | 168 | ## Outputs 169 | 170 | | Name | Description | 171 | |------|-------------| 172 | | application\_gateway\_id | Application gateway Id | 173 | | application\_gateway\_name | Application gateway name | 174 | | namespace | Namespace used for AGIC | 175 | | public\_ip\_id | Application gateway public ip Id | 176 | | public\_ip\_name | Application gateway public ip name | 177 | 178 | 179 | ## Related documentation 180 | 181 | - Terraform Azure Application gateway documentation: [terraform.io/docs/providers/azurerm/r/application_gateway.html](https://www.terraform.io/docs/providers/azurerm/r/application_gateway.html) 182 | - Azure application gateway documentation : [docs.microsoft.com/en-us/azure/application-gateway/overview](https://docs.microsoft.com/en-us/azure/application-gateway/overview) 183 | - Helm AGIC documentation : [azure.github.io/application-gateway-kubernetes-ingress/](https://azure.github.io/application-gateway-kubernetes-ingress/) 184 | -------------------------------------------------------------------------------- /tools/agic/data.tf: -------------------------------------------------------------------------------- 1 | data "azurerm_subscription" "current" { 2 | count = var.agic_enabled ? 1 : 0 3 | } 4 | 5 | data "azurerm_resource_group" "resource_group" { 6 | count = var.agic_enabled ? 1 : 0 7 | name = var.resource_group_name 8 | } 9 | -------------------------------------------------------------------------------- /tools/agic/helm-agic.tf: -------------------------------------------------------------------------------- 1 | resource "kubernetes_namespace" "agic" { 2 | count = var.agic_enabled ? 1 : 0 3 | metadata { 4 | name = "system-agic" 5 | labels = { 6 | deployed-by = "Terraform" 7 | } 8 | } 9 | } 10 | 11 | resource "azurerm_role_assignment" "agic" { 12 | count = var.agic_enabled ? 1 : 0 13 | principal_id = var.aks_aad_pod_identity_principal_id 14 | scope = try(azurerm_application_gateway.app_gateway[0].id, var.application_gateway_id) 15 | role_definition_name = "Contributor" 16 | } 17 | 18 | resource "azurerm_role_assignment" "agic_rg" { 19 | count = var.agic_enabled ? 1 : 0 20 | principal_id = var.aks_aad_pod_identity_principal_id 21 | scope = data.azurerm_resource_group.resource_group[0].id 22 | role_definition_name = "Reader" 23 | } 24 | 25 | 26 | resource "helm_release" "agic" { 27 | count = var.agic_enabled ? 1 : 0 28 | depends_on = [ 29 | azurerm_role_assignment.agic, 30 | azurerm_role_assignment.agic_rg, 31 | azurerm_application_gateway.app_gateway 32 | ] 33 | name = "ingress-azure" 34 | repository = var.agic_chart_repository 35 | chart = "ingress-azure" 36 | namespace = kubernetes_namespace.agic[0].metadata[0].name 37 | version = coalesce(var.agic_helm_version, var.agic_chart_version) 38 | 39 | 40 | dynamic "set" { 41 | for_each = local.appgw_ingress_settings 42 | iterator = setting 43 | content { 44 | name = setting.key 45 | value = setting.value 46 | } 47 | } 48 | } 49 | -------------------------------------------------------------------------------- /tools/agic/locals.tf: -------------------------------------------------------------------------------- 1 | locals { 2 | name_prefix = var.name_prefix != "" ? replace(var.name_prefix, "/[a-z0-9]/", "$0-") : "" 3 | default_name = "${local.name_prefix}${var.stack}-${var.client_name}-${var.location_short}-${var.environment}-aks-appgw" 4 | name = coalesce(var.name, local.default_name) 5 | 6 | ip_name = coalesce(var.ip_name, "${local.name}-pip") 7 | ip_label = coalesce(var.ip_name, "${local.name}-pip") 8 | frontend_ip_configuration_name = coalesce(var.frontend_ip_configuration_name, "${local.name}-frontipconfig") 9 | frontend_priv_ip_configuration_name = coalesce(var.frontend_priv_ip_configuration_name, "${local.name}-frontipconfig-priv") 10 | gateway_ip_configuration_name = coalesce(var.gateway_ip_configuration_name, "${local.name}-ipconfig") 11 | 12 | appgw_ingress_default_values = { 13 | "appgw.name" = try(azurerm_application_gateway.app_gateway[0].name, split("/", var.application_gateway_id)[8], "") 14 | "appgw.subscriptionId" = try(data.azurerm_subscription.current[0].subscription_id, split("/", var.application_gateway_id)[2], "") 15 | "appgw.resourceGroup" = try(azurerm_application_gateway.app_gateway[0].resource_group_name, split("/", var.application_gateway_id)[4], "") 16 | "appgw.subnetID" = try(var.app_gateway_subnet_id, "") 17 | "appgw.usePrivateIP" = "false" 18 | "armAuth.type" = "aadPodIdentity" 19 | "armAuth.identityResourceID" = try(var.aks_aad_pod_identity_id, "") 20 | "armAuth.identityClientID" = try(var.aks_aad_pod_identity_client_id, "") 21 | "rbac.enabled" = "true" 22 | "verbosityLevel" = "1" 23 | } 24 | 25 | appgw_ingress_settings = merge(local.appgw_ingress_default_values, var.appgw_ingress_values) 26 | } 27 | -------------------------------------------------------------------------------- /tools/agic/outputs.tf: -------------------------------------------------------------------------------- 1 | output "namespace" { 2 | description = "Namespace used for AGIC" 3 | value = try(kubernetes_namespace.agic[0].metadata[0].name, "") 4 | } 5 | 6 | output "application_gateway_id" { 7 | description = "Application gateway Id" 8 | value = try(azurerm_application_gateway.app_gateway[0].id, "") 9 | } 10 | 11 | output "application_gateway_name" { 12 | description = "Application gateway name" 13 | value = try(azurerm_application_gateway.app_gateway[0].name, "") 14 | } 15 | 16 | output "public_ip_id" { 17 | description = "Application gateway public ip Id" 18 | value = try(azurerm_public_ip.ip[0].id, "") 19 | } 20 | 21 | output "public_ip_name" { 22 | description = "Application gateway public ip name" 23 | value = try(azurerm_public_ip.ip[0].name, "") 24 | } 25 | -------------------------------------------------------------------------------- /tools/agic/r-application-gateway.tf: -------------------------------------------------------------------------------- 1 | resource "azurerm_application_gateway" "app_gateway" { 2 | count = var.agic_enabled && !var.use_existing_application_gateway ? 1 : 0 3 | location = var.location 4 | name = var.name 5 | resource_group_name = var.resource_group_name 6 | 7 | # 8 | # Common 9 | # 10 | 11 | sku { 12 | capacity = var.sku_capacity 13 | name = var.sku_name 14 | tier = var.sku_tier 15 | } 16 | 17 | zones = var.zones 18 | 19 | frontend_ip_configuration { 20 | name = local.frontend_ip_configuration_name 21 | public_ip_address_id = azurerm_public_ip.ip[0].id 22 | } 23 | 24 | dynamic "frontend_ip_configuration" { 25 | for_each = var.private_ingress ? ["fake"] : [] 26 | content { 27 | name = local.frontend_priv_ip_configuration_name 28 | private_ip_address_allocation = var.private_ingress ? "Static" : null 29 | private_ip_address = var.private_ingress ? var.appgw_private_ip : null 30 | subnet_id = var.private_ingress ? var.app_gateway_subnet_id : null 31 | } 32 | } 33 | 34 | dynamic "frontend_port" { 35 | for_each = var.frontend_port_settings 36 | content { 37 | name = lookup(frontend_port.value, "name", "dummy") 38 | port = lookup(frontend_port.value, "port", 80) 39 | } 40 | } 41 | 42 | dynamic "identity" { 43 | for_each = var.gateway_identity_id != null ? ["fake"] : [] 44 | content { 45 | type = "UserAssigned" 46 | identity_ids = [var.gateway_identity_id] 47 | } 48 | } 49 | 50 | 51 | 52 | gateway_ip_configuration { 53 | name = local.gateway_ip_configuration_name 54 | subnet_id = var.app_gateway_subnet_id 55 | } 56 | 57 | /* 58 | Azure seems to don't take care of enabled = false and throw an error 59 | about wrong SKU to use with WAF. So we dynamically disable it 60 | */ 61 | dynamic "waf_configuration" { 62 | for_each = var.enabled_waf ? ["fake"] : [] 63 | content { 64 | enabled = var.enabled_waf 65 | file_upload_limit_mb = var.file_upload_limit_mb 66 | firewall_mode = var.firewall_mode 67 | max_request_body_size_kb = var.max_request_body_size_kb 68 | request_body_check = var.request_body_check 69 | rule_set_type = var.rule_set_type 70 | rule_set_version = var.rule_set_version 71 | 72 | dynamic "disabled_rule_group" { 73 | for_each = var.disabled_rule_group_settings 74 | content { 75 | rule_group_name = lookup(disabled_rule_group.value, "rule_group_name") 76 | rules = lookup(disabled_rule_group.value, "rules") 77 | } 78 | } 79 | 80 | dynamic "exclusion" { 81 | for_each = var.waf_exclusion_settings 82 | content { 83 | match_variable = lookup(exclusion.value, "match_variable") 84 | selector = lookup(exclusion.value, "selector") 85 | selector_match_operator = lookup(exclusion.value, "selector_match_operator") 86 | } 87 | } 88 | } 89 | } 90 | 91 | 92 | ssl_policy { 93 | policy_type = "Predefined" 94 | policy_name = var.policy_name 95 | } 96 | 97 | # 98 | # Backend HTTP settings 99 | # 100 | 101 | dynamic "backend_http_settings" { 102 | for_each = var.appgw_backend_http_settings 103 | content { 104 | name = lookup(backend_http_settings.value, "name", "dummy") 105 | path = lookup(backend_http_settings.value, "path", "/") 106 | probe_name = lookup(backend_http_settings.value, "probe_name", "dummy") 107 | 108 | affinity_cookie_name = "ApplicationGatewayAffinity" 109 | cookie_based_affinity = lookup(backend_http_settings.value, "cookie_based_affinity", "Disabled") 110 | pick_host_name_from_backend_address = lookup(backend_http_settings.value, "pick_host_name_from_backend_address", false) 111 | host_name = lookup(backend_http_settings.value, "host_name", "dummy") 112 | port = lookup(backend_http_settings.value, "port", 80) 113 | protocol = lookup(backend_http_settings.value, "protocol", "Http") 114 | request_timeout = lookup(backend_http_settings.value, "request_timeout", 1) 115 | trusted_root_certificate_names = lookup(backend_http_settings.value, "trusted_root_certificate_names", []) 116 | } 117 | } 118 | 119 | # 120 | # HTTP listener 121 | # 122 | 123 | dynamic "http_listener" { 124 | for_each = var.appgw_http_listeners 125 | content { 126 | name = lookup(http_listener.value, "name", "dummy") 127 | frontend_ip_configuration_name = lookup(http_listener.value, "frontend_ip_configuration_name", local.frontend_ip_configuration_name) 128 | frontend_port_name = lookup(http_listener.value, "frontend_port_name", "dummy") 129 | protocol = lookup(http_listener.value, "protocol", "Http") 130 | ssl_certificate_name = lookup(http_listener.value, "ssl_certificate_name", null) 131 | host_name = lookup(http_listener.value, "host_name", "dummy") 132 | require_sni = lookup(http_listener.value, "require_sni", null) 133 | } 134 | } 135 | 136 | # 137 | # Backend address pool 138 | # 139 | 140 | dynamic "backend_address_pool" { 141 | for_each = var.appgw_backend_pools 142 | content { 143 | name = lookup(backend_address_pool.value, "name", "dummy") 144 | fqdns = lookup(backend_address_pool.value, "fqdns", ["dummy"]) 145 | } 146 | } 147 | 148 | # 149 | # SSL certificate 150 | # 151 | 152 | dynamic "ssl_certificate" { 153 | for_each = toset(var.ssl_certificates_configs) 154 | content { 155 | name = lookup(ssl_certificate.value, "name") 156 | data = lookup(ssl_certificate.value, "key_vault_secret_id") == "" ? base64((lookup(ssl_certificate.value, "data"))) : null 157 | password = lookup(ssl_certificate.value, "key_vault_secret_id") == "" ? lookup(ssl_certificate.value, "password") : null 158 | key_vault_secret_id = lookup(ssl_certificate.value, "data") == "" ? lookup(ssl_certificate.value, "key_vault_secret_id") : null 159 | } 160 | } 161 | 162 | # 163 | # Authentication certificate 164 | # 165 | 166 | dynamic "authentication_certificate" { 167 | for_each = var.authentication_certificate_configs 168 | content { 169 | name = lookup(authentication_certificate.value, "name") 170 | data = filebase64(lookup(authentication_certificate.value, "data")) 171 | } 172 | } 173 | 174 | # 175 | # Trusted root certificate 176 | # 177 | 178 | dynamic "trusted_root_certificate" { 179 | for_each = var.trusted_root_certificate_configs 180 | content { 181 | name = lookup(trusted_root_certificate.value, "name") 182 | data = filebase64(lookup(trusted_root_certificate.value, "data")) 183 | } 184 | } 185 | 186 | # 187 | # Request routing rule 188 | # 189 | 190 | dynamic "request_routing_rule" { 191 | for_each = var.appgw_routings 192 | content { 193 | name = lookup(request_routing_rule.value, "name", "dummy") 194 | rule_type = lookup(request_routing_rule.value, "rule_type", "Basic") 195 | 196 | http_listener_name = lookup(request_routing_rule.value, "http_listener_name", lookup(request_routing_rule.value, "name", "dummy")) 197 | backend_address_pool_name = lookup(request_routing_rule.value, "backend_address_pool_name", lookup(request_routing_rule.value, "name", "dummy")) 198 | backend_http_settings_name = lookup(request_routing_rule.value, "backend_http_settings_name", lookup(request_routing_rule.value, "name", "dummy")) 199 | url_path_map_name = lookup(request_routing_rule.value, "url_path_map_name", null) 200 | redirect_configuration_name = lookup(request_routing_rule.value, "redirect_configuration_name", null) 201 | rewrite_rule_set_name = lookup(request_routing_rule.value, "rewrite_rule_set_name", null) 202 | priority = lookup(request_routing_rule.value, "priority", 1) 203 | } 204 | } 205 | 206 | # 207 | # Rewrite rule set 208 | # 209 | 210 | dynamic "rewrite_rule_set" { 211 | for_each = var.appgw_rewrite_rule_set 212 | content { 213 | name = lookup(rewrite_rule_set.value, "name", null) 214 | dynamic "rewrite_rule" { 215 | for_each = lookup(rewrite_rule_set.value, "rewrite_rule", {}) 216 | content { 217 | name = lookup(rewrite_rule.value, "name") 218 | rule_sequence = lookup(rewrite_rule.value, "rule_sequence") 219 | 220 | dynamic "request_header_configuration" { 221 | for_each = lookup(rewrite_rule.value, "request_header_configurations", {}) 222 | content { 223 | header_name = lookup(request_header_configuration.value, "header_name", null) 224 | header_value = lookup(request_header_configuration.value, "header_value", null) 225 | } 226 | } 227 | 228 | dynamic "response_header_configuration" { 229 | for_each = lookup(rewrite_rule.value, "response_header_configurations", {}) 230 | content { 231 | header_name = lookup(response_header_configuration.value, "header_name", null) 232 | header_value = lookup(response_header_configuration.value, "header_value", null) 233 | } 234 | } 235 | 236 | dynamic "condition" { 237 | for_each = lookup(rewrite_rule.value, "conditions", {}) 238 | content { 239 | ignore_case = lookup(condition.value, "condition_ignore_case", null) 240 | negate = lookup(condition.value, "condition_negate", null) 241 | pattern = lookup(condition.value, "condition_pattern", null) 242 | variable = lookup(condition.value, "condition_variable", null) 243 | } 244 | } 245 | } 246 | } 247 | } 248 | } 249 | 250 | # 251 | # Probe 252 | # 253 | 254 | dynamic "probe" { 255 | for_each = var.appgw_probes 256 | content { 257 | host = lookup(probe.value, "host", "dummy") 258 | interval = lookup(probe.value, "interval", 30) 259 | name = lookup(probe.value, "name", "dummy") 260 | path = lookup(probe.value, "path", "/") 261 | protocol = lookup(probe.value, "protocol", "Http") 262 | timeout = lookup(probe.value, "timeout", 30) 263 | unhealthy_threshold = lookup(probe.value, "unhealthy_threshold", 3) 264 | match { 265 | body = lookup(probe.value, "match_body", "") 266 | status_code = lookup(probe.value, "match_status_code", ["200"]) 267 | } 268 | } 269 | } 270 | 271 | # 272 | # URL path map 273 | # 274 | 275 | dynamic "url_path_map" { 276 | for_each = var.appgw_url_path_map 277 | content { 278 | name = lookup(url_path_map.value, "name") 279 | default_backend_address_pool_name = lookup(url_path_map.value, "default_backend_address_pool_name") 280 | default_backend_http_settings_name = lookup(url_path_map.value, "default_backend_http_settings_name", lookup(url_path_map.value, "default_backend_address_pool_name")) 281 | 282 | dynamic "path_rule" { 283 | for_each = lookup(url_path_map.value, "path_rule") 284 | content { 285 | name = lookup(path_rule.value, "path_rule_name") 286 | backend_address_pool_name = lookup(path_rule.value, "backend_address_pool_name", lookup(path_rule.value, "path_rule_name")) 287 | backend_http_settings_name = lookup(path_rule.value, "backend_http_settings_name", lookup(path_rule.value, "path_rule_name")) 288 | paths = [lookup(path_rule.value, "paths")] 289 | } 290 | } 291 | } 292 | } 293 | 294 | # 295 | # Redirect configuration 296 | # 297 | 298 | dynamic "redirect_configuration" { 299 | for_each = var.appgw_redirect_configuration 300 | content { 301 | name = lookup(redirect_configuration.value, "name") 302 | redirect_type = lookup(redirect_configuration.value, "redirect_type", "Permanent") 303 | target_listener_name = lookup(redirect_configuration.value, "target_listener_name") 304 | include_path = lookup(redirect_configuration.value, "include_path", "true") 305 | include_query_string = lookup(redirect_configuration.value, "include_query_string", "true") 306 | } 307 | } 308 | 309 | tags = var.app_gateway_tags 310 | 311 | # Ignore most changes as they should be managed by AKS ingress controller 312 | lifecycle { 313 | ignore_changes = [ 314 | backend_address_pool, 315 | backend_http_settings, 316 | frontend_port, 317 | http_listener, 318 | probe, 319 | request_routing_rule, 320 | url_path_map, 321 | ssl_certificate, 322 | redirect_configuration, 323 | autoscale_configuration, 324 | tags 325 | ] 326 | } 327 | 328 | } 329 | -------------------------------------------------------------------------------- /tools/agic/r-logs.tf: -------------------------------------------------------------------------------- 1 | module "diagnostic_settings_appgw" { 2 | count = var.agic_enabled && !var.use_existing_application_gateway ? 1 : 0 3 | 4 | source = "claranet/diagnostic-settings/azurerm" 5 | version = "6.5.0" 6 | 7 | resource_id = azurerm_application_gateway.app_gateway[0].id 8 | 9 | logs_destinations_ids = var.logs_destinations_ids 10 | log_categories = var.logs_categories 11 | metric_categories = var.logs_metrics_categories 12 | 13 | use_caf_naming = var.use_caf_naming 14 | custom_name = var.custom_diagnostic_settings_name 15 | name_prefix = var.name_prefix 16 | name_suffix = var.name_suffix 17 | } 18 | -------------------------------------------------------------------------------- /tools/agic/r-public-ip.tf: -------------------------------------------------------------------------------- 1 | resource "azurerm_public_ip" "ip" { 2 | count = var.agic_enabled && !var.use_existing_application_gateway ? 1 : 0 3 | location = var.location 4 | name = local.ip_name 5 | allocation_method = var.ip_allocation_method 6 | resource_group_name = var.resource_group_name 7 | sku = var.ip_sku 8 | 9 | domain_name_label = lower(replace(local.ip_label, "/[\\W_]/", "-")) 10 | zones = var.zones 11 | 12 | tags = var.ip_tags 13 | } 14 | -------------------------------------------------------------------------------- /tools/agic/terraform.tfvars.ci: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/claranet/terraform-azurerm-aks/ee813b08d5bb87d7d7e1443363b46c87b3b6a69b/tools/agic/terraform.tfvars.ci -------------------------------------------------------------------------------- /tools/agic/variables-logs.tf: -------------------------------------------------------------------------------- 1 | # Diag settings / logs parameters 2 | 3 | variable "logs_destinations_ids" { 4 | type = list(string) 5 | description = <= 3.x.x | 0.12.x | = 1.1.1 | ~> 1.11.1 | 11 | | >= 2.x.x, < 3.x.x | 0.12.x | N/A | N/A | 12 | | < 2.x.x | 0.11.x | N/A | N/A | 13 | 14 | ## Usage 15 | 16 | ```hcl 17 | module "certmanager" { 18 | source = "claranet/aks/azurerm//modules/tools/cert-manager" 19 | 20 | cert_manager_namespace = var.cert_manager_namespace 21 | cert_manager_chart_version = var.cert_manager_chart_version 22 | cert_manager_settings = var.cert_manager_settings 23 | } 24 | 25 | ``` 26 | 27 | 28 | ## Providers 29 | 30 | | Name | Version | 31 | |------|---------| 32 | | helm | >= 2.5.1 | 33 | | kubernetes | >= 2.11.0 | 34 | 35 | ## Modules 36 | 37 | No modules. 38 | 39 | ## Resources 40 | 41 | | Name | Type | 42 | |------|------| 43 | | [helm_release.cert_manager](https://registry.terraform.io/providers/hashicorp/helm/latest/docs/resources/release) | resource | 44 | | [kubernetes_namespace.cert_manager](https://registry.terraform.io/providers/hashicorp/kubernetes/latest/docs/resources/namespace) | resource | 45 | 46 | ## Inputs 47 | 48 | | Name | Description | Type | Default | Required | 49 | |------|-------------|------|---------|:--------:| 50 | | cert\_manager\_chart\_repository | Helm chart repository URL | `string` | `"https://charts.jetstack.io"` | no | 51 | | cert\_manager\_chart\_version | Cert Manager helm chart version to use | `string` | `"v1.8.0"` | no | 52 | | cert\_manager\_namespace | Kubernetes namespace in which to deploy Cert Manager | `string` | `"system-cert-manager"` | no | 53 | | cert\_manager\_settings | Settings for cert-manager helm chart | `map(string)` | `{}` | no | 54 | | enable\_cert\_manager | Enable cert-manager on AKS cluster | `bool` | `true` | no | 55 | 56 | ## Outputs 57 | 58 | | Name | Description | 59 | |------|-------------| 60 | | namespace | Namespace used for Cert Manager | 61 | 62 | 63 | ## Related documentation 64 | 65 | - cert-manager documentation : [github.com/jetstack/cert-manager](https://github.com/jetstack/cert-manager) 66 | -------------------------------------------------------------------------------- /tools/cert-manager/locals-cert-manager.tf: -------------------------------------------------------------------------------- 1 | locals { 2 | cert_manager_default_values = { 3 | "installCRDs" = "true" 4 | } 5 | 6 | cert_manager_values = merge(local.cert_manager_default_values, var.cert_manager_settings) 7 | } 8 | -------------------------------------------------------------------------------- /tools/cert-manager/outputs.tf: -------------------------------------------------------------------------------- 1 | output "namespace" { 2 | description = "Namespace used for Cert Manager" 3 | value = try(kubernetes_namespace.cert_manager[0].metadata[0].name, "") 4 | } 5 | -------------------------------------------------------------------------------- /tools/cert-manager/r-cert-manager.tf: -------------------------------------------------------------------------------- 1 | resource "kubernetes_namespace" "cert_manager" { 2 | count = var.enable_cert_manager ? 1 : 0 3 | metadata { 4 | name = var.cert_manager_namespace 5 | labels = { 6 | deployed-by = "Terraform" 7 | } 8 | } 9 | } 10 | 11 | resource "helm_release" "cert_manager" { 12 | count = var.enable_cert_manager ? 1 : 0 13 | name = "cert-manager" 14 | chart = "cert-manager" 15 | repository = var.cert_manager_chart_repository 16 | namespace = kubernetes_namespace.cert_manager[0].metadata[0].name 17 | version = var.cert_manager_chart_version 18 | dynamic "set" { 19 | for_each = local.cert_manager_values 20 | iterator = setting 21 | content { 22 | name = setting.key 23 | value = setting.value 24 | } 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /tools/cert-manager/terraform.tfvars.ci: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/claranet/terraform-azurerm-aks/ee813b08d5bb87d7d7e1443363b46c87b3b6a69b/tools/cert-manager/terraform.tfvars.ci -------------------------------------------------------------------------------- /tools/cert-manager/variables.tf: -------------------------------------------------------------------------------- 1 | variable "enable_cert_manager" { 2 | description = "Enable cert-manager on AKS cluster" 3 | type = bool 4 | default = true 5 | } 6 | 7 | variable "cert_manager_settings" { 8 | description = "Settings for cert-manager helm chart" 9 | type = map(string) 10 | default = {} 11 | } 12 | 13 | variable "cert_manager_namespace" { 14 | description = "Kubernetes namespace in which to deploy Cert Manager" 15 | type = string 16 | default = "system-cert-manager" 17 | } 18 | 19 | variable "cert_manager_chart_repository" { 20 | description = "Helm chart repository URL" 21 | type = string 22 | default = "https://charts.jetstack.io" 23 | } 24 | 25 | variable "cert_manager_chart_version" { 26 | description = "Cert Manager helm chart version to use" 27 | type = string 28 | default = "v1.8.0" 29 | } 30 | -------------------------------------------------------------------------------- /tools/cert-manager/versions.tf: -------------------------------------------------------------------------------- 1 | terraform { 2 | required_version = ">= 1.1" 3 | required_providers { 4 | # tflint-ignore: terraform_unused_required_providers 5 | helm = { 6 | source = "hashicorp/helm" 7 | version = ">= 2.5.1" 8 | } 9 | # tflint-ignore: terraform_unused_required_providers 10 | kubernetes = { 11 | source = "hashicorp/kubernetes" 12 | version = ">= 2.11.0" 13 | } 14 | } 15 | } 16 | -------------------------------------------------------------------------------- /tools/kured/README.md: -------------------------------------------------------------------------------- 1 | # Azure Kubernetes Service - Kured tool submodule 2 | [![Changelog](https://img.shields.io/badge/changelog-release-green.svg)](CHANGELOG.md) [![Notice](https://img.shields.io/badge/notice-copyright-yellow.svg)](NOTICE) [![Apache V2 License](https://img.shields.io/badge/license-Apache%20V2-orange.svg)](LICENSE) [![TF Registry](https://img.shields.io/badge/terraform-registry-blue.svg)](https://registry.terraform.io/modules/claranet/aks/azurerm/latest/submodules/kured) 3 | 4 | This module deploys [Kured](https://github.com/weaveworks/kured) on an existing K8S cluster with Helm 3. 5 | 6 | ## Version compatibility 7 | 8 | | Module version | Terraform version | Helm version | Kubernetes version | 9 | |-------------------|-------------------|--------------|--------------------| 10 | | >= 3.x.x | 0.12.x | = 1.1.1 | ~> 1.11.1 | 11 | | >= 2.x.x, < 3.x.x | 0.12.x | N/A | N/A | 12 | | < 2.x.x | 0.11.x | N/A | N/A | 13 | 14 | ## Usage 15 | 16 | ```hcl 17 | module "kured" { 18 | source = "claranet/aks/azurerm//modules/tools/kured" 19 | version = "x.x.x" 20 | 21 | cert_manager_namespace = var.cert_manager_namespace 22 | cert_manager_chart_version = var.cert_manager_chart_version 23 | cert_manager_settings = var.cert_manager_settings 24 | } 25 | 26 | ``` 27 | 28 | 29 | ## Providers 30 | 31 | | Name | Version | 32 | |------|---------| 33 | | helm | >= 2.3.0 | 34 | 35 | ## Modules 36 | 37 | No modules. 38 | 39 | ## Resources 40 | 41 | | Name | Type | 42 | |------|------| 43 | | [helm_release.kured](https://registry.terraform.io/providers/hashicorp/helm/latest/docs/resources/release) | resource | 44 | 45 | ## Inputs 46 | 47 | | Name | Description | Type | Default | Required | 48 | |------|-------------|------|---------|:--------:| 49 | | enable\_kured | Enable kured daemon on AKS cluster | `bool` | `true` | no | 50 | | kured\_chart\_repository | Helm chart repository URL | `string` | `"https://kubereboot.github.io/charts"` | no | 51 | | kured\_chart\_version | Version of the Helm chart | `string` | `"2.2.0"` | no | 52 | | kured\_settings | Settings for kured helm chart


map(object({

image.repository = string

image.tag = string

image.pullPolicy = string

extraArgs.reboot-days = string

extraArgs.start-time = string

extraArgs.end-time = string

extraArgs.time-zone = string

rbac.create = string

podSecurityPolicy.create = string

serviceAccount.create = string

autolock.enabled = string

}))

| `map(string)` | `{}` | no | 53 | 54 | ## Outputs 55 | 56 | | Name | Description | 57 | |------|-------------| 58 | | namespace | Namespace used for Kured | 59 | 60 | 61 | ## Related documentation 62 | 63 | - Kured documentation : [github.com/weaveworks/kured](https://github.com/weaveworks/kured) 64 | -------------------------------------------------------------------------------- /tools/kured/locals-kured.tf: -------------------------------------------------------------------------------- 1 | locals { 2 | # Forced to kube-system due to Chart specificity 3 | namespace = "kube-system" 4 | kured_default_values = { 5 | "image.repository" = "ghcr.io/kubereboot/kured" 6 | "image.tag" = "1.11.0" 7 | "image.pullPolicy" = "IfNotPresent" 8 | "extraArgs.reboot-days" = "mon" 9 | "extraArgs.start-time" = "3am" 10 | "extraArgs.end-time" = "6am" 11 | "extraArgs.time-zone" = "Europe/Paris" 12 | "rbac.create" = "true" 13 | "podSecurityPolicy.create" = "false" 14 | "serviceAccount.create" = "true" 15 | } 16 | 17 | kured_values = merge(local.kured_default_values, var.kured_settings) 18 | } 19 | -------------------------------------------------------------------------------- /tools/kured/outputs.tf: -------------------------------------------------------------------------------- 1 | output "namespace" { 2 | description = "Namespace used for Kured" 3 | value = local.namespace 4 | } 5 | -------------------------------------------------------------------------------- /tools/kured/r-kured.tf: -------------------------------------------------------------------------------- 1 | resource "helm_release" "kured" { 2 | count = var.enable_kured ? 1 : 0 3 | name = "kured" 4 | chart = "kured" 5 | repository = var.kured_chart_repository 6 | version = var.kured_chart_version 7 | namespace = local.namespace 8 | 9 | dynamic "set" { 10 | for_each = local.kured_values 11 | iterator = setting 12 | content { 13 | name = setting.key 14 | value = setting.value 15 | } 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /tools/kured/terraform.tfvars.ci: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/claranet/terraform-azurerm-aks/ee813b08d5bb87d7d7e1443363b46c87b3b6a69b/tools/kured/terraform.tfvars.ci -------------------------------------------------------------------------------- /tools/kured/variables.tf: -------------------------------------------------------------------------------- 1 | variable "enable_kured" { 2 | description = "Enable kured daemon on AKS cluster" 3 | type = bool 4 | default = true 5 | } 6 | 7 | variable "kured_chart_repository" { 8 | description = "Helm chart repository URL" 9 | type = string 10 | default = "https://kubereboot.github.io/charts" 11 | } 12 | 13 | variable "kured_chart_version" { 14 | description = "Version of the Helm chart" 15 | type = string 16 | default = "2.2.0" 17 | } 18 | 19 | variable "kured_settings" { 20 | description = < 22 |
23 | map(object({ 
24 | image.repository = string
25 | image.tag = string
26 | image.pullPolicy = string
27 | extraArgs.reboot-days = string
28 | extraArgs.start-time = string
29 | extraArgs.end-time = string
30 | extraArgs.time-zone = string
31 | rbac.create = string
32 | podSecurityPolicy.create = string
33 | serviceAccount.create = string
34 | autolock.enabled = string
35 | }))
36 |
37 | EODK 38 | type = map(string) 39 | default = {} 40 | } 41 | -------------------------------------------------------------------------------- /tools/kured/versions.tf: -------------------------------------------------------------------------------- 1 | terraform { 2 | required_version = ">= 1.1" 3 | required_providers { 4 | # tflint-ignore: terraform_unused_required_providers 5 | helm = { 6 | source = "hashicorp/helm" 7 | version = ">= 2.5.1" 8 | } 9 | } 10 | } 11 | -------------------------------------------------------------------------------- /tools/velero/README.md: -------------------------------------------------------------------------------- 1 | # Azure Kubernetes Service - Velero tool submodule 2 | [![Changelog](https://img.shields.io/badge/changelog-release-green.svg)](CHANGELOG.md) [![Notice](https://img.shields.io/badge/notice-copyright-yellow.svg)](NOTICE) [![Apache V2 License](https://img.shields.io/badge/license-Apache%20V2-orange.svg)](LICENSE) [![TF Registry](https://img.shields.io/badge/terraform-registry-blue.svg)](https://registry.terraform.io/modules/claranet/aks/azurerm/latest/submodules/velero) 3 | 4 | This module deploys [Velero](https://velero.io/) on an existing K8S cluster with Helm 3 and its associated Block blob storage account. 5 | 6 | ## Version compatibility 7 | 8 | | Module version | Terraform version | Helm version | Kubernetes version | 9 | |-------------------|-------------------|--------------|--------------------| 10 | | >= 3.x.x | 0.12.x | = 1.1.1 | ~> 1.11.1 | 11 | | >= 2.x.x, < 3.x.x | 0.12.x | N/A | N/A | 12 | | < 2.x.x | 0.11.x | N/A | N/A | 13 | 14 | ## Usage 15 | 16 | ```hcl 17 | module "rg" { 18 | source = "claranet/rg/azurerm" 19 | version = "x.x.x" 20 | 21 | location = module.azure-region.location 22 | client_name = var.client_name 23 | environment = var.environment 24 | stack = var.stack 25 | 26 | custom_rg_name = local.support_bastion_rg_name 27 | } 28 | 29 | module "azure-region" { 30 | source = "claranet/regions/azurerm" 31 | version = "x.x.x" 32 | 33 | azure_region = var.azure_region 34 | } 35 | 36 | module "velero" { 37 | source = "claranet/aks/azurerm//modules/tools/velero" 38 | version = "x.x.x" 39 | 40 | enable_velero = var.enable_velero 41 | 42 | client_name = var.client_name 43 | stack = var.stack 44 | environment = var.environment 45 | location = module.azure-region.location 46 | location_short = module.azure-region.location_short 47 | name_prefix = var.name_prefix 48 | 49 | resource_group_name = module.rg.resource_group_name 50 | aks_cluster_name = var.aks_cluster_name 51 | aks_nodes_resource_group_name = var.aks_nodes_resource_group_name 52 | nodes_subnet_id = var.nodes_subnet_id 53 | 54 | velero_namespace = var.velero_namespace 55 | velero_chart_version = var.velero_chart_version 56 | velero_values = var.velero_values 57 | velero_storage_settings = var.velero_storage_settings 58 | } 59 | 60 | ``` 61 | 62 | 63 | ## Providers 64 | 65 | | Name | Version | 66 | |------|---------| 67 | | azurerm | >= 2.51 | 68 | | helm | >= 2.5.1 | 69 | | kubernetes | >= 2.11.0 | 70 | 71 | ## Modules 72 | 73 | No modules. 74 | 75 | ## Resources 76 | 77 | | Name | Type | 78 | |------|------| 79 | | [azurerm_role_assignment.velero_identity_role_aks](https://registry.terraform.io/providers/hashicorp/azurerm/latest/docs/resources/role_assignment) | resource | 80 | | [azurerm_role_assignment.velero_identity_role_storage](https://registry.terraform.io/providers/hashicorp/azurerm/latest/docs/resources/role_assignment) | resource | 81 | | [azurerm_storage_account.velero](https://registry.terraform.io/providers/hashicorp/azurerm/latest/docs/resources/storage_account) | resource | 82 | | [azurerm_storage_account_network_rules.velero](https://registry.terraform.io/providers/hashicorp/azurerm/latest/docs/resources/storage_account_network_rules) | resource | 83 | | [azurerm_storage_container.velero](https://registry.terraform.io/providers/hashicorp/azurerm/latest/docs/resources/storage_container) | resource | 84 | | [azurerm_user_assigned_identity.velero_identity](https://registry.terraform.io/providers/hashicorp/azurerm/latest/docs/resources/user_assigned_identity) | resource | 85 | | [helm_release.velero](https://registry.terraform.io/providers/hashicorp/helm/latest/docs/resources/release) | resource | 86 | | [helm_release.velero_identity](https://registry.terraform.io/providers/hashicorp/helm/latest/docs/resources/release) | resource | 87 | | [kubernetes_namespace.velero](https://registry.terraform.io/providers/hashicorp/kubernetes/latest/docs/resources/namespace) | resource | 88 | | [kubernetes_secret.velero](https://registry.terraform.io/providers/hashicorp/kubernetes/latest/docs/resources/secret) | resource | 89 | | [azurerm_resource_group.aks_nodes_rg](https://registry.terraform.io/providers/hashicorp/azurerm/latest/docs/data-sources/resource_group) | data source | 90 | | [azurerm_subscription.current](https://registry.terraform.io/providers/hashicorp/azurerm/latest/docs/data-sources/subscription) | data source | 91 | 92 | ## Inputs 93 | 94 | | Name | Description | Type | Default | Required | 95 | |------|-------------|------|---------|:--------:| 96 | | aks\_nodes\_resource\_group\_name | Name of AKS nodes resource group | `string` | n/a | yes | 97 | | client\_name | Client name/account used in naming | `string` | n/a | yes | 98 | | enable\_velero | Enable velero on AKS cluster | `bool` | `true` | no | 99 | | environment | Project environment | `string` | n/a | yes | 100 | | location | Azure region to use | `string` | n/a | yes | 101 | | location\_short | Short name of Azure regions to use | `string` | n/a | yes | 102 | | name\_prefix | Prefix used in naming | `string` | `""` | no | 103 | | nodes\_subnet\_id | Id of the subnet used for nodes | `string` | n/a | yes | 104 | | resource\_group\_name | Name of the resource group for Velero's Storage Account | `string` | n/a | yes | 105 | | stack | Project stack name | `string` | n/a | yes | 106 | | velero\_chart\_repository | Helm chart repository URL | `string` | `"https://vmware-tanzu.github.io/helm-charts"` | no | 107 | | velero\_chart\_version | Velero helm chart version to use | `string` | `"2.29.5"` | no | 108 | | velero\_identity\_custom\_name | Name of the Velero MSI | `string` | `""` | no | 109 | | velero\_identity\_tags | Tags to add to velero MSI | `map(string)` | `{}` | no | 110 | | velero\_namespace | Kubernetes namespace in which to deploy Velero | `string` | `"system-velero"` | no | 111 | | velero\_storage\_settings | Settings for Storage account and blob container for Velero |
object({
name = optional(string)
resource_group_name = optional(string)
location = optional(string)
account_tier = optional(string)
account_replication_type = optional(string)
tags = optional(map(any))
allowed_cidrs = optional(list(string))
allowed_subnet_ids = optional(list(string))
container_name = optional(string)
})
| `{}` | no | 112 | | velero\_values | Settings for Velero helm chart

map(object({
configuration.backupStorageLocation.bucket = string
configuration.backupStorageLocation.config.resourceGroup = string
configuration.backupStorageLocation.config.storageAccount = string
configuration.backupStorageLocation.name = string
configuration.provider = string
configuration.volumeSnapshotLocation.config.resourceGroup = string
configuration.volumeSnapshotLocation.name = string
credential.exstingSecret = string
credentials.useSecret = string
deployRestic = string
env.AZURE\_CREDENTIALS\_FILE = string
metrics.enabled = string
rbac.create = string
schedules.daily.schedule = string
schedules.daily.template.includedNamespaces = string
schedules.daily.template.snapshotVolumes = string
schedules.daily.template.ttl = string
serviceAccount.server.create = string
snapshotsEnabled = string
initContainers[0].name = string
initContainers[0].image = string
initContainers[0].volumeMounts[0].mountPath = string
initContainers[0].volumeMounts[0].name = string
image.repository = string
image.tag = string
image.pullPolicy = string
podAnnotations.aadpodidbinding = string
podLabels.aadpodidbinding = string

})) | `map(string)` | `{}` | no | 113 | 114 | ## Outputs 115 | 116 | | Name | Description | 117 | |------|-------------| 118 | | namespace | Namespace used for Velero | 119 | | storage\_account | Storage Account on which Velero data is stored. | 120 | | storage\_account\_container | Container in Storage Account on which Velero data is stored. | 121 | | velero\_identity | Azure Identity used for Velero pods | 122 | 123 | 124 | ## Related documentation 125 | 126 | - Velero documentation : [velero.io/docs/v1.3.2/](https://velero.io/docs/v1.3.2/) 127 | - Velero Azure plugin documentation : [github.com/vmware-tanzu/velero-plugin-for-microsoft-azure](https://github.com/vmware-tanzu/velero-plugin-for-microsoft-azure) 128 | - BlockBlob storage account documentation : [docs.microsoft.com/en-us/azure/storage/blobs/storage-blob-create-account-block-blob?tabs=azure-portal](https://docs.microsoft.com/en-us/azure/storage/blobs/storage-blob-create-account-block-blob?tabs=azure-portal) 129 | -------------------------------------------------------------------------------- /tools/velero/aad-bindings/.helmignore: -------------------------------------------------------------------------------- 1 | # Patterns to ignore when building packages. 2 | # This supports shell glob matching, relative path matching, and 3 | # negation (prefixed with !). Only one pattern per line. 4 | .DS_Store 5 | # Common VCS dirs 6 | .git/ 7 | .gitignore 8 | .bzr/ 9 | .bzrignore 10 | .hg/ 11 | .hgignore 12 | .svn/ 13 | # Common backup files 14 | *.swp 15 | *.bak 16 | *.tmp 17 | *.orig 18 | *~ 19 | # Various IDEs 20 | .project 21 | .idea/ 22 | *.tmproj 23 | .vscode/ 24 | -------------------------------------------------------------------------------- /tools/velero/aad-bindings/Chart.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: v2 2 | name: aad-bindings 3 | description: A workaround to deploy Aad binding. 4 | 5 | # A chart can be either an 'application' or a 'library' chart. 6 | # 7 | # Application charts are a collection of templates that can be packaged into versioned archives 8 | # to be deployed. 9 | # 10 | # Library charts provide useful utilities or functions for the chart developer. They're included as 11 | # a dependency of application charts to inject those utilities and functions into the rendering 12 | # pipeline. Library charts do not define any templates and therefore cannot be deployed. 13 | type: application 14 | 15 | # This is the chart version. This version number should be incremented each time you make changes 16 | # to the chart and its templates, including the app version. 17 | version: 0.1.0 18 | 19 | # This is the version number of the application being deployed. This version number should be 20 | # incremented each time you make changes to the application. 21 | appVersion: 1.16.0 22 | -------------------------------------------------------------------------------- /tools/velero/aad-bindings/templates/AzureIdentity.yaml.tpl: -------------------------------------------------------------------------------- 1 | apiVersion: "aadpodidentity.k8s.io/v1" 2 | kind: AzureIdentity 3 | metadata: 4 | name: {{ .Values.IdentityName }} 5 | spec: 6 | type: 0 7 | resourceID: {{ .Values.IdentityID }} 8 | clientID: {{ .Values.IdentityClientID }} 9 | -------------------------------------------------------------------------------- /tools/velero/aad-bindings/templates/AzureIdentityBinding.yaml.tpl: -------------------------------------------------------------------------------- 1 | apiVersion: "aadpodidentity.k8s.io/v1" 2 | kind: AzureIdentityBinding 3 | metadata: 4 | name: {{ .Values.IdentityName }}-binding 5 | spec: 6 | azureIdentity: {{ .Values.IdentityName }} 7 | selector: {{ .Values.IdentityName }} 8 | -------------------------------------------------------------------------------- /tools/velero/aad-bindings/values.yaml: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/claranet/terraform-azurerm-aks/ee813b08d5bb87d7d7e1443363b46c87b3b6a69b/tools/velero/aad-bindings/values.yaml -------------------------------------------------------------------------------- /tools/velero/locals-velero.tf: -------------------------------------------------------------------------------- 1 | locals { 2 | credentials = < v if v != null }) : null 59 | velero_values = var.enable_velero ? merge(local.velero_default_values, var.velero_values) : null 60 | } 61 | -------------------------------------------------------------------------------- /tools/velero/outputs.tf: -------------------------------------------------------------------------------- 1 | output "namespace" { 2 | description = "Namespace used for Velero" 3 | value = try(kubernetes_namespace.velero[0].metadata[0].name, "") 4 | } 5 | 6 | output "storage_account" { 7 | description = "Storage Account on which Velero data is stored." 8 | value = azurerm_storage_account.velero 9 | } 10 | 11 | output "storage_account_container" { 12 | description = "Container in Storage Account on which Velero data is stored." 13 | value = azurerm_storage_container.velero 14 | } 15 | 16 | output "velero_identity" { 17 | description = "Azure Identity used for Velero pods" 18 | value = azurerm_user_assigned_identity.velero_identity 19 | } 20 | -------------------------------------------------------------------------------- /tools/velero/r-identity.tf: -------------------------------------------------------------------------------- 1 | data "azurerm_resource_group" "aks_nodes_rg" { 2 | count = var.enable_velero ? 1 : 0 3 | name = var.aks_nodes_resource_group_name 4 | } 5 | 6 | resource "azurerm_user_assigned_identity" "velero_identity" { 7 | count = var.enable_velero ? 1 : 0 8 | location = var.location 9 | name = local.velero_identity_name 10 | resource_group_name = var.aks_nodes_resource_group_name 11 | 12 | tags = var.velero_identity_tags 13 | } 14 | 15 | resource "azurerm_role_assignment" "velero_identity_role_aks" { 16 | count = var.enable_velero ? 1 : 0 17 | principal_id = azurerm_user_assigned_identity.velero_identity[0].principal_id 18 | scope = try(data.azurerm_resource_group.aks_nodes_rg[0].id, "") 19 | role_definition_name = "Contributor" 20 | } 21 | 22 | resource "azurerm_role_assignment" "velero_identity_role_storage" { 23 | count = var.enable_velero ? 1 : 0 24 | principal_id = azurerm_user_assigned_identity.velero_identity[0].principal_id 25 | scope = azurerm_storage_account.velero[0].id 26 | role_definition_name = "Contributor" 27 | } 28 | 29 | resource "helm_release" "velero_identity" { 30 | depends_on = [helm_release.velero] 31 | count = var.enable_velero ? 1 : 0 32 | chart = "${path.module}/aad-bindings" 33 | name = "velero-aad-bindings" 34 | namespace = kubernetes_namespace.velero[0].metadata[0].name 35 | 36 | set { 37 | name = "IdentityName" 38 | value = azurerm_user_assigned_identity.velero_identity[0].name 39 | } 40 | 41 | set { 42 | name = "IdentityID" 43 | value = azurerm_user_assigned_identity.velero_identity[0].id 44 | } 45 | 46 | set { 47 | name = "IdentityClientID" 48 | value = azurerm_user_assigned_identity.velero_identity[0].client_id 49 | } 50 | } 51 | -------------------------------------------------------------------------------- /tools/velero/r-velero.tf: -------------------------------------------------------------------------------- 1 | data "azurerm_subscription" "current" { 2 | count = var.enable_velero ? 1 : 0 3 | } 4 | 5 | resource "kubernetes_namespace" "velero" { 6 | count = var.enable_velero ? 1 : 0 7 | metadata { 8 | name = var.velero_namespace 9 | labels = { 10 | deployed-by = "Terraform" 11 | } 12 | } 13 | } 14 | 15 | resource "kubernetes_secret" "velero" { 16 | count = var.enable_velero ? 1 : 0 17 | metadata { 18 | name = "cloud-credentials" 19 | namespace = kubernetes_namespace.velero[0].metadata[0].name 20 | } 21 | data = { 22 | cloud = local.velero_credentials 23 | } 24 | } 25 | 26 | resource "azurerm_storage_account" "velero" { 27 | count = var.enable_velero ? 1 : 0 28 | name = local.velero_storage.name 29 | resource_group_name = local.velero_storage.resource_group_name 30 | location = local.velero_storage.location 31 | account_tier = local.velero_storage.account_tier 32 | account_replication_type = local.velero_storage.account_replication_type 33 | account_kind = "BlockBlobStorage" 34 | min_tls_version = "TLS1_2" 35 | tags = local.velero_storage.tags 36 | 37 | lifecycle { 38 | ignore_changes = [network_rules] 39 | } 40 | } 41 | 42 | resource "azurerm_storage_account_network_rules" "velero" { 43 | count = var.enable_velero ? 1 : 0 44 | 45 | storage_account_id = azurerm_storage_account.velero[0].id 46 | 47 | default_action = "Deny" 48 | bypass = local.velero_storage.bypass 49 | virtual_network_subnet_ids = concat(local.velero_storage.allowed_subnet_ids, [var.nodes_subnet_id]) 50 | ip_rules = local.velero_storage.allowed_cidrs 51 | } 52 | 53 | resource "azurerm_storage_container" "velero" { 54 | count = var.enable_velero ? 1 : 0 55 | name = local.velero_storage.container_name 56 | storage_account_name = azurerm_storage_account.velero[0].name 57 | container_access_type = "private" 58 | } 59 | 60 | resource "helm_release" "velero" { 61 | count = var.enable_velero ? 1 : 0 62 | depends_on = [ 63 | kubernetes_secret.velero, 64 | kubernetes_namespace.velero, 65 | azurerm_storage_account.velero, 66 | azurerm_storage_container.velero] 67 | name = "velero" 68 | chart = "velero" 69 | repository = var.velero_chart_repository 70 | namespace = kubernetes_namespace.velero[0].metadata[0].name 71 | version = var.velero_chart_version 72 | 73 | dynamic "set" { 74 | for_each = local.velero_values 75 | iterator = setting 76 | content { 77 | name = setting.key 78 | value = setting.value 79 | } 80 | } 81 | 82 | } 83 | -------------------------------------------------------------------------------- /tools/velero/terraform.tfvars.ci: -------------------------------------------------------------------------------- 1 | velero_storage_settings = { allowed_cidrs = ["1.1.1.1", "2.2.2.2"] } 2 | -------------------------------------------------------------------------------- /tools/velero/variables.tf: -------------------------------------------------------------------------------- 1 | variable "resource_group_name" { 2 | description = "Name of the resource group for Velero's Storage Account" 3 | type = string 4 | } 5 | 6 | variable "aks_nodes_resource_group_name" { 7 | description = "Name of AKS nodes resource group" 8 | type = string 9 | } 10 | 11 | variable "nodes_subnet_id" { 12 | description = "Id of the subnet used for nodes" 13 | type = string 14 | } 15 | 16 | variable "enable_velero" { 17 | description = "Enable velero on AKS cluster" 18 | type = bool 19 | default = true 20 | } 21 | 22 | variable "velero_chart_repository" { 23 | description = "Helm chart repository URL" 24 | type = string 25 | default = "https://vmware-tanzu.github.io/helm-charts" 26 | } 27 | 28 | variable "velero_identity_custom_name" { 29 | description = "Name of the Velero MSI" 30 | type = string 31 | default = "" 32 | } 33 | 34 | variable "velero_identity_tags" { 35 | description = "Tags to add to velero MSI" 36 | type = map(string) 37 | default = {} 38 | } 39 | 40 | variable "velero_storage_settings" { 41 | description = "Settings for Storage account and blob container for Velero" 42 | default = {} 43 | type = object({ 44 | name = optional(string) 45 | resource_group_name = optional(string) 46 | location = optional(string) 47 | account_tier = optional(string) 48 | account_replication_type = optional(string) 49 | tags = optional(map(any)) 50 | allowed_cidrs = optional(list(string)) 51 | allowed_subnet_ids = optional(list(string)) 52 | container_name = optional(string) 53 | }) 54 | } 55 | 56 | variable "velero_values" { 57 | description = <