diff --git a/.github/ISSUE_TEMPLATE/config.yml b/.github/ISSUE_TEMPLATE/config.yml index 3ba13e0c..bd9dfe4e 100644 --- a/.github/ISSUE_TEMPLATE/config.yml +++ b/.github/ISSUE_TEMPLATE/config.yml @@ -1 +1,2 @@ +--- blank_issues_enabled: false diff --git a/.github/linters/.yaml-lint.yml b/.github/linters/.yaml-lint.yml new file mode 100644 index 00000000..01c763da --- /dev/null +++ b/.github/linters/.yaml-lint.yml @@ -0,0 +1,11 @@ +--- +extends: default + +rules: + # 200 chars should be enough, but don't fail if a line is longer + line-length: + max: 200 + level: warning + truthy: + check-keys: false + level: warning diff --git a/.github/workflows/docs-fmt-test.yml b/.github/workflows/docs-fmt-test.yml new file mode 100644 index 00000000..99e23243 --- /dev/null +++ b/.github/workflows/docs-fmt-test.yml @@ -0,0 +1,42 @@ +--- +name: Docs & fmt test + +on: + pull_request: + types: ['opened', 'reopened', 'synchronize'] + merge_group: + workflow_dispatch: + +concurrency: + group: docsfmttest-${{ github.event.pull_request.head.repo.full_name }}/${{ github.head_ref || github.run_id }} + cancel-in-progress: true + +jobs: + docsfmttest: + name: Docs & fmt test + runs-on: ubuntu-latest + steps: + - name: Checkout repository + uses: actions/checkout@v4 + + - name: Setup go + uses: actions/setup-go@v4 + with: + go-version: '1.20.x' + cache-dependency-path: tests/go.sum + + - name: Install tools + run: make tools + + - name: Check fmt and docs + run: | + echo "==> Running make fmt & make docs" + make fmt + make docs + echo "==> Testing for changes to tracked files" + CHANGES=$(git status -suno) + if [ "$CHANGES" ]; then + echo "Repository formatting or documentation is not correct." + echo "Run 'make fmt && make docs' locally and commit the changes to fix." + exit 1 + fi diff --git a/.github/workflows/super-linter.yml b/.github/workflows/super-linter.yml new file mode 100644 index 00000000..97862d73 --- /dev/null +++ b/.github/workflows/super-linter.yml @@ -0,0 +1,49 @@ +--- +name: Linting +on: + pull_request: + types: ['opened', 'synchronize'] + merge_group: + workflow_dispatch: + +concurrency: + group: linting-${{ github.event.pull_request.head.repo.full_name }}/${{ github.head_ref || github.run_id }} + cancel-in-progress: true + +jobs: + superlinter: + name: super linter + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v3 + - name: Setup Terraform + uses: hashicorp/setup-terraform@v2 + with: + terraform_version: latest + terraform_wrapper: false + - name: Run github/super-linter/slim + uses: github/super-linter/slim@v5 + env: + # Lint all code + VALIDATE_ALL_CODEBASE: true + FILTER_REGEX_EXCLUDE: '.*tests/vendor/.*' + # Need to define main branch as default + # is set to master in super-linter + DEFAULT_BRANCH: main + # Enable setting the status of each individual linter + # run in the Checks section of a pull request + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} + # The following linter types will be enabled: + VALIDATE_BASH: true + VALIDATE_BASH_EXEC: true + VALIDATE_GITHUB_ACTIONS: true + VALIDATE_JSON: true + VALIDATE_MARKDOWN: true + # VALIDATE_TERRAFORM_TERRASCAN: true # disabled for now as does not support TF 1.3 optional(type, default) + VALIDATE_TERRAFORM_TFLINT: true + VALIDATE_YAML: true + # VALIDATE_GO: true # Disabled because it down not work :( + # Additional settings: + # If a shell script is not executable, the bash-exec + # linter will report an error when set to true + ERROR_ON_MISSING_EXEC_BIT: true diff --git a/.github/workflows/wiki-sync.yml b/.github/workflows/wiki-sync.yml index a6da8b5f..e00012f6 100644 --- a/.github/workflows/wiki-sync.yml +++ b/.github/workflows/wiki-sync.yml @@ -1,62 +1,62 @@ ---- - name: Docs/Wiki Sync - - # yamllint disable-line rule:truthy - on: - release: - types: [published] - workflow_dispatch: {} - - env: - wiki_source_repo: "${{ github.repository }}" - wiki_source_repo_dir: "${{ github.repository }}/docs/wiki" - wiki_target_repo: "${{ github.repository }}.wiki" - github_user_name: "github-actions" - github_email: "github-actions@github.com" - github_commit_message: "GitHub Action syncing wiki from docs/wiki" - - jobs: - sync-wiki: - name: Sync Wiki - if: github.repository == 'Azure/alz-terraform-accelerator' || github.event_name == 'workflow_dispatch' - runs-on: ubuntu-latest - steps: - - name: Checkout Source Repo - uses: actions/checkout@v3 - with: - repository: ${{ env.wiki_source_repo }} - path: ${{ env.wiki_source_repo }} - - - name: Checkout Wiki Repo - uses: actions/checkout@v3 - with: - repository: ${{ env.wiki_target_repo }} - path: ${{ env.wiki_target_repo }} - - - name: Configure Local Git - run: | - git config --global user.name "$github_user_name" - git config --global user.email "$github_email" - working-directory: ${{ env.GITHUB_WORKSPACE }} - - - name: Sync docs/wiki Into Wiki Repo - run: | - rsync -avzr --delete --exclude='.git/' "$wiki_source_repo_dir/" "$wiki_target_repo" - working-directory: ${{ env.GITHUB_WORKSPACE }} - - - name: Check for changes - id: git_status - run: | - mapfile -t "CHECK_GIT_STATUS" < <(git status -s) - printf "%s\n" "${CHECK_GIT_STATUS[@]}" - echo "changes=${#CHECK_GIT_STATUS[@]}" >> "$GITHUB_OUTPUT" - working-directory: ${{ env.wiki_target_repo }} - - - name: Add files, commit and push into Wiki - if: steps.git_status.outputs.changes > 0 - run: | - echo "Pushing changes to origin..." - git add . - git commit -m "$github_commit_message [$GITHUB_ACTOR/${GITHUB_SHA::8}]" - git push --set-upstream "https://$GITHUB_TOKEN@github.com/$wiki_target_repo.git" master - working-directory: ${{ env.wiki_target_repo }} \ No newline at end of file +--- +name: Docs/Wiki Sync + +# yamllint disable-line rule:truthy +on: + release: + types: [published] + workflow_dispatch: + +env: + wiki_source_repo: "${{ github.repository }}" + wiki_source_repo_dir: "${{ github.repository }}/docs/wiki" + wiki_target_repo: "${{ github.repository }}.wiki" + github_user_name: "github-actions" + github_email: "github-actions@github.com" + github_commit_message: "GitHub Action syncing wiki from docs/wiki" + +jobs: + sync-wiki: + name: Sync Wiki + if: github.repository == 'Azure/alz-terraform-accelerator' || github.event_name == 'workflow_dispatch' + runs-on: ubuntu-latest + steps: + - name: Checkout Source Repo + uses: actions/checkout@v3 + with: + repository: ${{ env.wiki_source_repo }} + path: ${{ env.wiki_source_repo }} + + - name: Checkout Wiki Repo + uses: actions/checkout@v3 + with: + repository: ${{ env.wiki_target_repo }} + path: ${{ env.wiki_target_repo }} + + - name: Configure Local Git + run: | + git config --global user.name "$github_user_name" + git config --global user.email "$github_email" + working-directory: ${{ env.GITHUB_WORKSPACE }} + + - name: Sync docs/wiki Into Wiki Repo + run: | + rsync -avzr --delete --exclude='.git/' "$wiki_source_repo_dir/" "$wiki_target_repo" + working-directory: ${{ env.GITHUB_WORKSPACE }} + + - name: Check for changes + id: git_status + run: | + mapfile -t "CHECK_GIT_STATUS" < <(git status -s) + printf "%s\n" "${CHECK_GIT_STATUS[@]}" + echo "changes=${#CHECK_GIT_STATUS[@]}" >> "$GITHUB_OUTPUT" + working-directory: ${{ env.wiki_target_repo }} + + - name: Add files, commit and push into Wiki + if: steps.git_status.outputs.changes > 0 + run: | + echo "Pushing changes to origin..." + git add . + git commit -m "$github_commit_message [$GITHUB_ACTOR/${GITHUB_SHA::8}]" + git push --set-upstream "https://$GITHUB_TOKEN@github.com/$wiki_target_repo.git" master + working-directory: ${{ env.wiki_target_repo }} diff --git a/Makefile b/Makefile new file mode 100644 index 00000000..09aecee3 --- /dev/null +++ b/Makefile @@ -0,0 +1,35 @@ +default: + @echo "==> Type make to run tasks" + @echo + @echo "Thing is one of:" + @echo "docs fmt fmtcheck tfclean tools" + +docs: + @echo "==> Updating documentation..." + find . | egrep "\.md" | grep -v README.md | sort | while read f; do terrafmt fmt $$f; done + +fmt: + @echo "==> Fixing Terraform code with terraform fmt..." + terraform fmt -recursive + @echo "==> Fixing embedded Terraform with terrafmt..." + find . | egrep "\.md|\.tf" | grep -v README.md | sort | while read f; do terrafmt fmt $$f; done + +fmtcheck: + @echo "==> Checking source code with gofmt..." + @sh "$(CURDIR)/scripts/gofmtcheck.sh" + @echo "==> Checking source code with terraform fmt..." + terraform fmt -check -recursive + +tfclean: + @echo "==> Cleaning terraform files..." + find . -type d -name '.terraform' | xargs rm -vrf + find . -type f -name 'tfplan' | xargs rm -vf + find . -type f -name 'terraform.tfstate*' | xargs rm -vf + find . -type f -name '.terraform.lock.hcl' | xargs rm -vf + +tools: + go install github.com/katbyte/terrafmt@latest + +# Makefile targets are files, but we aren't using it like this, +# so have to declare PHONY targets +.PHONY: docs fmt fmtcheck tfclean tools diff --git a/README.md b/README.md index 858d43fa..cc3c8f55 100644 --- a/README.md +++ b/README.md @@ -33,7 +33,7 @@ Please refer to our [wiki](https://github.com/Azure/alz-terraform-accelerator/wi This project welcomes contributions and suggestions. Most contributions require you to agree to a Contributor License Agreement (CLA) declaring that you have the right to, and actually do, grant us -the rights to use your contribution. For details, visit https://cla.opensource.microsoft.com. +the rights to use your contribution. For details, visit [https://cla.opensource.microsoft.com](https://cla.opensource.microsoft.com). When you submit a pull request, a CLA bot will automatically determine whether you need to provide a CLA and decorate the PR appropriately (e.g., status check, comment). Simply follow the instructions diff --git a/SECURITY.md b/SECURITY.md index f7b89984..4fa5946a 100644 --- a/SECURITY.md +++ b/SECURITY.md @@ -14,17 +14,17 @@ Instead, please report them to the Microsoft Security Response Center (MSRC) at If you prefer to submit without logging in, send email to [secure@microsoft.com](mailto:secure@microsoft.com). If possible, encrypt your message with our PGP key; please download it from the [Microsoft Security Response Center PGP Key page](https://www.microsoft.com/en-us/msrc/pgp-key-msrc). -You should receive a response within 24 hours. If for some reason you do not, please follow up via email to ensure we received your original message. Additional information can be found at [microsoft.com/msrc](https://www.microsoft.com/msrc). +You should receive a response within 24 hours. If for some reason you do not, please follow up via email to ensure we received your original message. Additional information can be found at [microsoft.com/msrc](https://www.microsoft.com/msrc). Please include the requested information listed below (as much as you can provide) to help us better understand the nature and scope of the possible issue: - * Type of issue (e.g. buffer overflow, SQL injection, cross-site scripting, etc.) - * Full paths of source file(s) related to the manifestation of the issue - * The location of the affected source code (tag/branch/commit or direct URL) - * Any special configuration required to reproduce the issue - * Step-by-step instructions to reproduce the issue - * Proof-of-concept or exploit code (if possible) - * Impact of the issue, including how an attacker might exploit the issue +* Type of issue (e.g. buffer overflow, SQL injection, cross-site scripting, etc.) +* Full paths of source file(s) related to the manifestation of the issue +* The location of the affected source code (tag/branch/commit or direct URL) +* Any special configuration required to reproduce the issue +* Step-by-step instructions to reproduce the issue +* Proof-of-concept or exploit code (if possible) +* Impact of the issue, including how an attacker might exploit the issue This information will help us triage your report more quickly. @@ -38,4 +38,4 @@ We prefer all communications to be in English. Microsoft follows the principle of [Coordinated Vulnerability Disclosure](https://www.microsoft.com/en-us/msrc/cvd). - \ No newline at end of file + diff --git a/SUPPORT.md b/SUPPORT.md index dc72f0e5..885c43c2 100644 --- a/SUPPORT.md +++ b/SUPPORT.md @@ -1,25 +1,11 @@ -# TODO: The maintainer of this repo has not yet edited this file - -**REPO OWNER**: Do you want Customer Service & Support (CSS) support for this product/project? - -- **No CSS support:** Fill out this template with information about how to file issues and get help. -- **Yes CSS support:** Fill out an intake form at [aka.ms/spot](https://aka.ms/spot). CSS will work with/help you to determine next steps. More details also available at [aka.ms/onboardsupport](https://aka.ms/onboardsupport). -- **Not sure?** Fill out a SPOT intake as though the answer were "Yes". CSS will help you decide. - -*Then remove this first heading from this SUPPORT.MD file before publishing your repo.* - -# Support - -## How to file issues and get help - -This project uses GitHub Issues to track bugs and feature requests. Please search the existing -issues before filing new issues to avoid duplicates. For new issues, file your bug or -feature request as a new Issue. - -For help and questions about using this project, please **REPO MAINTAINER: INSERT INSTRUCTIONS HERE -FOR HOW TO ENGAGE REPO OWNERS OR COMMUNITY FOR HELP. COULD BE A STACK OVERFLOW TAG OR OTHER -CHANNEL. WHERE WILL YOU HELP PEOPLE?**. - -## Microsoft Support Policy - -Support for this **PROJECT or PRODUCT** is limited to the resources listed above. +# Support + +## How to file issues and get help + +This project uses GitHub Issues to track bugs and feature requests. Please search the existing issues before filing new issues to avoid duplicates. For new issues, file your bug or feature request as a new Issue. + +For help and questions about using this project, please raise an Issue. + +## Microsoft Support Policy + +Support for this project is limited to the resources listed above. diff --git a/bootstrap/.config/ALZ-Powershell.config.json b/bootstrap/.config/ALZ-Powershell.config.json index 6bfc5915..723b0d22 100644 --- a/bootstrap/.config/ALZ-Powershell.config.json +++ b/bootstrap/.config/ALZ-Powershell.config.json @@ -90,7 +90,7 @@ "azure_name" : { "Type": "Valid", "Description": "A valid Azure name e.g. 'my-azure-name'", - "Valid": "^[a-zA-Z0-9]{2,10}(-[a-zA-Z0-9]{2,10})?$" + "Valid": "^[a-zA-Z0-9]{2,10}(-[a-zA-Z0-9]{2,10}){0,1}(-[a-zA-Z0-9]{2,10})?$" }, "azure_name_section" : { "Type": "Valid", @@ -132,7 +132,7 @@ "cidr_range" : { "Type": "Valid", "Description": "A valid CIDR range e.g '10.0.0.0/16'", - "Valid": "^(([0-9]|[1-9][0-9]|1[0-9]{2}|2[0-4][0-9]|25[0-5])\\.){3}([0-9]|[1-9][0-9]|1[0-9]{2}|2[0-4][0-9]|25[0-5])(\/(3[0-2]|[1-2][0-9]|[0-9]))$" + "Valid": "^(([0-9]|[1-9][0-9]|1[0-9]{2}|2[0-4][0-9]|25[0-5])\\.){3}([0-9]|[1-9][0-9]|1[0-9]{2}|2[0-4][0-9]|25[0-5])(/(3[0-2]|[1-2][0-9]|[0-9]))$" } } } \ No newline at end of file diff --git a/bootstrap/azuredevops/locals.tf b/bootstrap/azuredevops/locals.tf index 5ca3c132..5166d686 100644 --- a/bootstrap/azuredevops/locals.tf +++ b/bootstrap/azuredevops/locals.tf @@ -1,4 +1,4 @@ -# Resource Name Setup -locals { - resource_names = module.resource_names.resource_names -} \ No newline at end of file +# Resource Name Setup +locals { + resource_names = module.resource_names.resource_names +} diff --git a/bootstrap/azuredevops/main.tf b/bootstrap/azuredevops/main.tf index 4e2e6280..e940a955 100644 --- a/bootstrap/azuredevops/main.tf +++ b/bootstrap/azuredevops/main.tf @@ -1,91 +1,90 @@ -data "azurerm_client_config" "current" {} -data "azurerm_subscription" "current" {} - -module "resource_names" { - source = "./../modules/resource_names" - azure_location = var.azure_location - environment_name = var.environment_name - service_name = var.service_name - postfix_number = var.postfix_number - resource_names = var.resource_names -} - -module "azure" { - source = "./../modules/azure" - create_federated_credential = module.azure_devops.is_authentication_scheme_workload_identity_federation - federated_credential_subjects = { sc = module.azure_devops.subject } - federated_credential_issuer = module.azure_devops.issuer - federated_credential_name = local.resource_names.user_assigned_managed_identity_federated_credentials - create_agents_resource_group = module.azure_devops.is_authentication_scheme_managed_identity - resource_group_identity_name = local.resource_names.resource_group_identity - resource_group_agents_name = local.resource_names.resource_group_agents - resource_group_state_name = local.resource_names.resource_group_state - storage_account_name = local.resource_names.storage_account - storage_container_name = local.resource_names.storage_container - azure_location = var.azure_location - user_assigned_managed_identity_name = local.resource_names.user_assigned_managed_identity - create_agents = module.azure_devops.is_authentication_scheme_managed_identity - agent_container_instances = { - agent_01 = { - container_instance_name = local.resource_names.container_instance_01 - agent_name = local.resource_names.agent_01 - } - agent_02 = { - container_instance_name = local.resource_names.container_instance_02 - agent_name = local.resource_names.agent_02 - } - } - agent_container_instance_image = var.agent_container_image - agent_pool_name = module.azure_devops.agent_pool_name - agent_organization_url = module.azure_devops.organization_url - agent_token = var.version_control_system_access_token - target_subscriptions = var.target_subscriptions - root_management_group_display_name = var.root_management_group_display_name -} - -locals { - starter_module_path = abspath("${path.module}/${var.template_folder_path}/${var.starter_module}") - ci_cd_module_path = abspath("${path.module}/${var.template_folder_path}/${var.ci_cd_module}") -} - -module "starter_module_files" { - source = "./../modules/files" - folder_path = local.starter_module_path - flag = "module" -} - -module "ci_cd_module_files" { - source = "./../modules/files" - folder_path = local.ci_cd_module_path - exclusions = [".github"] - flag = "cicd" -} - -module "azure_devops" { - source = "./../modules/azure_devops" - access_token = var.version_control_system_access_token - use_legacy_organization_url = var.azure_devops_use_organisation_legacy_url - organization_name = var.version_control_system_organization - authentication_scheme = var.azure_devops_authentication_scheme - create_project = var.azure_devops_create_project - project_name = var.azure_devops_project_name - environment_name_plan = local.resource_names.version_control_system_environment_plan - environment_name_apply = local.resource_names.version_control_system_environment_apply - repository_name = local.resource_names.version_control_system_repository - repository_files = merge(module.starter_module_files.files, module.ci_cd_module_files.files) - service_connection_name = local.resource_names.version_control_system_service_connection - variable_group_name = local.resource_names.version_control_system_variable_group - managed_identity_client_id = module.azure.user_assigned_managed_identity_client_id - azure_tenant_id = data.azurerm_client_config.current.tenant_id - azure_subscription_id = data.azurerm_client_config.current.subscription_id - azure_subscription_name = data.azurerm_subscription.current.display_name - pipeline_ci_file = ".azuredevops/ci.yaml" - pipeline_cd_file = ".azuredevops/cd.yaml" - agent_pool_name = local.resource_names.version_control_system_agent_pool - backend_azure_resource_group_name = local.resource_names.resource_group_state - backend_azure_storage_account_name = local.resource_names.storage_account - backend_azure_storage_account_container_name = local.resource_names.storage_container - approvers = var.apply_approvers - group_name = local.resource_names.version_control_system_group -} - +data "azurerm_client_config" "current" {} +data "azurerm_subscription" "current" {} + +module "resource_names" { + source = "./../modules/resource_names" + azure_location = var.azure_location + environment_name = var.environment_name + service_name = var.service_name + postfix_number = var.postfix_number + resource_names = var.resource_names +} + +module "azure" { + source = "./../modules/azure" + create_federated_credential = module.azure_devops.is_authentication_scheme_workload_identity_federation + federated_credential_subjects = { sc = module.azure_devops.subject } + federated_credential_issuer = module.azure_devops.issuer + federated_credential_name = local.resource_names.user_assigned_managed_identity_federated_credentials + create_agents_resource_group = module.azure_devops.is_authentication_scheme_managed_identity + resource_group_identity_name = local.resource_names.resource_group_identity + resource_group_agents_name = local.resource_names.resource_group_agents + resource_group_state_name = local.resource_names.resource_group_state + storage_account_name = local.resource_names.storage_account + storage_container_name = local.resource_names.storage_container + azure_location = var.azure_location + user_assigned_managed_identity_name = local.resource_names.user_assigned_managed_identity + create_agents = module.azure_devops.is_authentication_scheme_managed_identity + agent_container_instances = { + agent_01 = { + container_instance_name = local.resource_names.container_instance_01 + agent_name = local.resource_names.agent_01 + } + agent_02 = { + container_instance_name = local.resource_names.container_instance_02 + agent_name = local.resource_names.agent_02 + } + } + agent_container_instance_image = var.agent_container_image + agent_pool_name = module.azure_devops.agent_pool_name + agent_organization_url = module.azure_devops.organization_url + agent_token = var.version_control_system_access_token + target_subscriptions = var.target_subscriptions + root_management_group_display_name = var.root_management_group_display_name +} + +locals { + starter_module_path = abspath("${path.module}/${var.template_folder_path}/${var.starter_module}") + ci_cd_module_path = abspath("${path.module}/${var.template_folder_path}/${var.ci_cd_module}") +} + +module "starter_module_files" { + source = "./../modules/files" + folder_path = local.starter_module_path + flag = "module" +} + +module "ci_cd_module_files" { + source = "./../modules/files" + folder_path = local.ci_cd_module_path + exclusions = [".github"] + flag = "cicd" +} + +module "azure_devops" { + source = "./../modules/azure_devops" + use_legacy_organization_url = var.azure_devops_use_organisation_legacy_url + organization_name = var.version_control_system_organization + authentication_scheme = var.azure_devops_authentication_scheme + create_project = var.azure_devops_create_project + project_name = var.azure_devops_project_name + environment_name_plan = local.resource_names.version_control_system_environment_plan + environment_name_apply = local.resource_names.version_control_system_environment_apply + repository_name = local.resource_names.version_control_system_repository + repository_files = merge(module.starter_module_files.files, module.ci_cd_module_files.files) + service_connection_name = local.resource_names.version_control_system_service_connection + variable_group_name = local.resource_names.version_control_system_variable_group + managed_identity_client_id = module.azure.user_assigned_managed_identity_client_id + azure_tenant_id = data.azurerm_client_config.current.tenant_id + azure_subscription_id = data.azurerm_client_config.current.subscription_id + azure_subscription_name = data.azurerm_subscription.current.display_name + pipeline_ci_file = ".azuredevops/ci.yaml" + pipeline_cd_file = ".azuredevops/cd.yaml" + agent_pool_name = local.resource_names.version_control_system_agent_pool + backend_azure_resource_group_name = local.resource_names.resource_group_state + backend_azure_storage_account_name = local.resource_names.storage_account + backend_azure_storage_account_container_name = local.resource_names.storage_container + approvers = var.apply_approvers + group_name = local.resource_names.version_control_system_group +} + diff --git a/bootstrap/azuredevops/providers.tf b/bootstrap/azuredevops/providers.tf index 11046c4d..f1b918f3 100644 --- a/bootstrap/azuredevops/providers.tf +++ b/bootstrap/azuredevops/providers.tf @@ -1,26 +1,30 @@ -terraform { - required_providers { - azurerm = { - source = "hashicorp/azurerm" - version = "3.61.0" - } - azuredevops = { - source = "microsoft/azuredevops" - version = ">=0.9.0" - } - } -} - -provider "azurerm" { - features { - resource_group { - prevent_deletion_if_contains_resources = false - } - } -} - -provider "azuredevops" { - personal_access_token = var.version_control_system_access_token - org_service_url = module.azure_devops.organization_url -} - +terraform { + required_providers { + azurerm = { + source = "hashicorp/azurerm" + version = "~> 3.61" + } + azuredevops = { + source = "microsoft/azuredevops" + version = "~> 0.9" + } + random = { + source = "hashicorp/random" + version = "~> 3.5" + } + } +} + +provider "azurerm" { + features { + resource_group { + prevent_deletion_if_contains_resources = false + } + } +} + +provider "azuredevops" { + personal_access_token = var.version_control_system_access_token + org_service_url = module.azure_devops.organization_url +} + diff --git a/bootstrap/azuredevops/terraform.tfvars b/bootstrap/azuredevops/terraform.tfvars index 0740bb7e..6c0f8b5c 100644 --- a/bootstrap/azuredevops/terraform.tfvars +++ b/bootstrap/azuredevops/terraform.tfvars @@ -1,28 +1,28 @@ -# Version Control System Variables -template_folder_path = "../../templates" -ci_cd_module = ".ci_cd" - -# Azure Variables -agent_container_image = "jaredfholgate/azure-devops-agent:0.0.3" - -# Names -resource_names = { - resource_group_state = "rg-{{service_name}}-{{environment_name}}-state-{{azure_location}}-{{postfix_number}}" - resource_group_identity = "rg-{{service_name}}-{{environment_name}}-identity-{{azure_location}}-{{postfix_number}}" - resource_group_agents = "rg-{{service_name}}-{{environment_name}}-agents-{{azure_location}}-{{postfix_number}}" - user_assigned_managed_identity = "id-{{service_name}}-{{environment_name}}-{{azure_location}}-{{postfix_number}}" - user_assigned_managed_identity_federated_credentials = "id-{{service_name}}-{{environment_name}}-{{azure_location}}-{{postfix_number}}" - storage_account = "sto{{service_name}}{{environment_name}}{{azure_location_short}}{{postfix_number}}{{random_string}}" - storage_container = "{{environment_name}}-tfstate" - container_instance_01 = "aci-{{service_name}}-{{environment_name}}-{{azure_location}}-{{postfix_number}}" - container_instance_02 = "aci-{{service_name}}-{{environment_name}}-{{azure_location}}-{{postfix_number_plus_one}}" - agent_01 = "agent-{{service_name}}-{{environment_name}}-{{postfix_number}}" - agent_02 = "agent-{{service_name}}-{{environment_name}}-{{postfix_number_plus_one}}" - version_control_system_repository = "{{service_name}}-{{environment_name}}" - version_control_system_service_connection = "sc-{{service_name}}-{{environment_name}}" - version_control_system_environment_plan = "{{service_name}}-{{environment_name}}-plan" - version_control_system_environment_apply = "{{service_name}}-{{environment_name}}-apply" - version_control_system_variable_group = "{{service_name}}-{{environment_name}}" - version_control_system_agent_pool = "{{service_name}}-{{environment_name}}" - version_control_system_group = "{{service_name}}-{{environment_name}}-approvers" -} \ No newline at end of file +# Version Control System Variables +template_folder_path = "../../templates" +ci_cd_module = ".ci_cd" + +# Azure Variables +agent_container_image = "jaredfholgate/azure-devops-agent:0.0.3" + +# Names +resource_names = { + resource_group_state = "rg-{{service_name}}-{{environment_name}}-state-{{azure_location}}-{{postfix_number}}" + resource_group_identity = "rg-{{service_name}}-{{environment_name}}-identity-{{azure_location}}-{{postfix_number}}" + resource_group_agents = "rg-{{service_name}}-{{environment_name}}-agents-{{azure_location}}-{{postfix_number}}" + user_assigned_managed_identity = "id-{{service_name}}-{{environment_name}}-{{azure_location}}-{{postfix_number}}" + user_assigned_managed_identity_federated_credentials = "id-{{service_name}}-{{environment_name}}-{{azure_location}}-{{postfix_number}}" + storage_account = "sto{{service_name}}{{environment_name}}{{azure_location_short}}{{postfix_number}}{{random_string}}" + storage_container = "{{environment_name}}-tfstate" + container_instance_01 = "aci-{{service_name}}-{{environment_name}}-{{azure_location}}-{{postfix_number}}" + container_instance_02 = "aci-{{service_name}}-{{environment_name}}-{{azure_location}}-{{postfix_number_plus_one}}" + agent_01 = "agent-{{service_name}}-{{environment_name}}-{{postfix_number}}" + agent_02 = "agent-{{service_name}}-{{environment_name}}-{{postfix_number_plus_one}}" + version_control_system_repository = "{{service_name}}-{{environment_name}}" + version_control_system_service_connection = "sc-{{service_name}}-{{environment_name}}" + version_control_system_environment_plan = "{{service_name}}-{{environment_name}}-plan" + version_control_system_environment_apply = "{{service_name}}-{{environment_name}}-apply" + version_control_system_variable_group = "{{service_name}}-{{environment_name}}" + version_control_system_agent_pool = "{{service_name}}-{{environment_name}}" + version_control_system_group = "{{service_name}}-{{environment_name}}-approvers" +} diff --git a/bootstrap/azuredevops/variables.tf b/bootstrap/azuredevops/variables.tf index bb17ccfa..2e95e015 100644 --- a/bootstrap/azuredevops/variables.tf +++ b/bootstrap/azuredevops/variables.tf @@ -100,4 +100,4 @@ variable "ci_cd_module" { variable "resource_names" { type = map(string) description = "Overrides for resource names|hidden" -} \ No newline at end of file +} diff --git a/bootstrap/github/locals.tf b/bootstrap/github/locals.tf index 5ca3c132..5166d686 100644 --- a/bootstrap/github/locals.tf +++ b/bootstrap/github/locals.tf @@ -1,4 +1,4 @@ -# Resource Name Setup -locals { - resource_names = module.resource_names.resource_names -} \ No newline at end of file +# Resource Name Setup +locals { + resource_names = module.resource_names.resource_names +} diff --git a/bootstrap/github/main.tf b/bootstrap/github/main.tf index 3b370b61..b4e79626 100644 --- a/bootstrap/github/main.tf +++ b/bootstrap/github/main.tf @@ -1,64 +1,61 @@ -data "azurerm_client_config" "current" {} - -module "resource_names" { - source = "./../modules/resource_names" - azure_location = var.azure_location - environment_name = var.environment_name - service_name = var.service_name - postfix_number = var.postfix_number - resource_names = var.resource_names -} - -module "azure" { - source = "./../modules/azure" - federated_credential_subjects = module.github.subjects - federated_credential_issuer = module.github.issuer - federated_credential_name = local.resource_names.user_assigned_managed_identity_federated_credentials - resource_group_identity_name = local.resource_names.resource_group_identity - resource_group_state_name = local.resource_names.resource_group_state - storage_account_name = local.resource_names.storage_account - storage_container_name = local.resource_names.storage_container - azure_location = var.azure_location - user_assigned_managed_identity_name = local.resource_names.user_assigned_managed_identity - target_subscriptions = var.target_subscriptions - root_management_group_display_name = var.root_management_group_display_name -} - -locals { - starter_module_path = abspath("${path.module}/${var.template_folder_path}/${var.starter_module}") - ci_cd_module_path = abspath("${path.module}/${var.template_folder_path}/${var.ci_cd_module}") -} - -module "starter_module_files" { - source = "./../modules/files" - folder_path = local.starter_module_path - flag = "module" -} - -module "ci_cd_module_files" { - source = "./../modules/files" - folder_path = local.ci_cd_module_path - exclusions = [".azuredevops"] - flag = "cicd" -} - -module "github" { - source = "./../modules/github" - access_token = var.version_control_system_access_token - organization_name = var.version_control_system_organization - environment_name_plan = local.resource_names.version_control_system_environment_plan - environment_name_apply = local.resource_names.version_control_system_environment_apply - repository_name = local.resource_names.version_control_system_repository - repository_visibility = var.repository_visibility - repository_files = merge(module.starter_module_files.files, module.ci_cd_module_files.files) - managed_identity_client_id = module.azure.user_assigned_managed_identity_client_id - azure_tenant_id = data.azurerm_client_config.current.tenant_id - azure_subscription_id = data.azurerm_client_config.current.subscription_id - pipeline_ci_file = ".github/workflows/ci.yaml" - pipeline_cd_file = ".github/workflows/cd.yaml" - backend_azure_resource_group_name = local.resource_names.resource_group_state - backend_azure_storage_account_name = local.resource_names.storage_account - backend_azure_storage_account_container_name = local.resource_names.storage_container - approvers = var.apply_approvers - team_name = local.resource_names.version_control_system_team -} \ No newline at end of file +data "azurerm_client_config" "current" {} + +module "resource_names" { + source = "./../modules/resource_names" + azure_location = var.azure_location + environment_name = var.environment_name + service_name = var.service_name + postfix_number = var.postfix_number + resource_names = var.resource_names +} + +module "azure" { + source = "./../modules/azure" + federated_credential_subjects = module.github.subjects + federated_credential_issuer = module.github.issuer + federated_credential_name = local.resource_names.user_assigned_managed_identity_federated_credentials + resource_group_identity_name = local.resource_names.resource_group_identity + resource_group_state_name = local.resource_names.resource_group_state + storage_account_name = local.resource_names.storage_account + storage_container_name = local.resource_names.storage_container + azure_location = var.azure_location + user_assigned_managed_identity_name = local.resource_names.user_assigned_managed_identity + target_subscriptions = var.target_subscriptions + root_management_group_display_name = var.root_management_group_display_name +} + +locals { + starter_module_path = abspath("${path.module}/${var.template_folder_path}/${var.starter_module}") + ci_cd_module_path = abspath("${path.module}/${var.template_folder_path}/${var.ci_cd_module}") +} + +module "starter_module_files" { + source = "./../modules/files" + folder_path = local.starter_module_path + flag = "module" +} + +module "ci_cd_module_files" { + source = "./../modules/files" + folder_path = local.ci_cd_module_path + exclusions = [".azuredevops"] + flag = "cicd" +} + +module "github" { + source = "./../modules/github" + organization_name = var.version_control_system_organization + environment_name_plan = local.resource_names.version_control_system_environment_plan + environment_name_apply = local.resource_names.version_control_system_environment_apply + repository_name = local.resource_names.version_control_system_repository + repository_visibility = var.repository_visibility + repository_files = merge(module.starter_module_files.files, module.ci_cd_module_files.files) + managed_identity_client_id = module.azure.user_assigned_managed_identity_client_id + azure_tenant_id = data.azurerm_client_config.current.tenant_id + azure_subscription_id = data.azurerm_client_config.current.subscription_id + backend_azure_resource_group_name = local.resource_names.resource_group_state + backend_azure_storage_account_name = local.resource_names.storage_account + backend_azure_storage_account_container_name = local.resource_names.storage_container + approvers = var.apply_approvers + team_name = local.resource_names.version_control_system_team +} diff --git a/bootstrap/github/providers.tf b/bootstrap/github/providers.tf index b75629cc..b4130502 100644 --- a/bootstrap/github/providers.tf +++ b/bootstrap/github/providers.tf @@ -1,25 +1,29 @@ -terraform { - required_providers { - azurerm = { - source = "hashicorp/azurerm" - version = "3.61.0" - } - github = { - source = "integrations/github" - version = "~> 5.36" - } - } -} - -provider "azurerm" { - features { - resource_group { - prevent_deletion_if_contains_resources = false - } - } -} - -provider "github" { - token = var.version_control_system_access_token - owner = var.version_control_system_organization -} \ No newline at end of file +terraform { + required_providers { + azurerm = { + source = "hashicorp/azurerm" + version = "~> 3.61" + } + github = { + source = "integrations/github" + version = "~> 5.36" + } + random = { + source = "hashicorp/random" + version = "~> 3.5" + } + } +} + +provider "azurerm" { + features { + resource_group { + prevent_deletion_if_contains_resources = false + } + } +} + +provider "github" { + token = var.version_control_system_access_token + owner = var.version_control_system_organization +} diff --git a/bootstrap/github/terraform.tfvars b/bootstrap/github/terraform.tfvars index 2f9ba3ab..4db33dd9 100644 --- a/bootstrap/github/terraform.tfvars +++ b/bootstrap/github/terraform.tfvars @@ -1,17 +1,17 @@ -# Version Control System Variables -template_folder_path = "../../templates" -ci_cd_module = ".ci_cd" - -# Naming -resource_names = { - resource_group_state = "rg-{{service_name}}-{{environment_name}}-state-{{azure_location}}-{{postfix_number}}" - resource_group_identity = "rg-{{service_name}}-{{environment_name}}-identity-{{azure_location}}-{{postfix_number}}" - user_assigned_managed_identity = "id-{{service_name}}-{{environment_name}}-{{azure_location}}-{{postfix_number}}" - user_assigned_managed_identity_federated_credentials = "id-{{service_name}}-{{environment_name}}-{{azure_location}}-{{postfix_number}}" - storage_account = "sto{{service_name}}{{environment_name}}{{azure_location_short}}{{postfix_number}}{{random_string}}" - storage_container = "{{environment_name}}-tfstate" - version_control_system_repository = "{{service_name}}-{{environment_name}}" - version_control_system_environment_plan = "{{service_name}}-{{environment_name}}-plan" - version_control_system_environment_apply = "{{service_name}}-{{environment_name}}-apply" - version_control_system_team = "{{service_name}}-{{environment_name}}-approvers" -} \ No newline at end of file +# Version Control System Variables +template_folder_path = "../../templates" +ci_cd_module = ".ci_cd" + +# Naming +resource_names = { + resource_group_state = "rg-{{service_name}}-{{environment_name}}-state-{{azure_location}}-{{postfix_number}}" + resource_group_identity = "rg-{{service_name}}-{{environment_name}}-identity-{{azure_location}}-{{postfix_number}}" + user_assigned_managed_identity = "id-{{service_name}}-{{environment_name}}-{{azure_location}}-{{postfix_number}}" + user_assigned_managed_identity_federated_credentials = "id-{{service_name}}-{{environment_name}}-{{azure_location}}-{{postfix_number}}" + storage_account = "sto{{service_name}}{{environment_name}}{{azure_location_short}}{{postfix_number}}{{random_string}}" + storage_container = "{{environment_name}}-tfstate" + version_control_system_repository = "{{service_name}}-{{environment_name}}" + version_control_system_environment_plan = "{{service_name}}-{{environment_name}}-plan" + version_control_system_environment_apply = "{{service_name}}-{{environment_name}}-apply" + version_control_system_team = "{{service_name}}-{{environment_name}}-approvers" +} diff --git a/bootstrap/github/variables.tf b/bootstrap/github/variables.tf index fdace3d3..04c0c1b3 100644 --- a/bootstrap/github/variables.tf +++ b/bootstrap/github/variables.tf @@ -74,4 +74,4 @@ variable "ci_cd_module" { variable "resource_names" { type = map(string) description = "Overrides for resource names|hidden" -} \ No newline at end of file +} diff --git a/bootstrap/modules/azure/azure_devops_agents.tf b/bootstrap/modules/azure/azure_devops_agents.tf index 3b80686a..78e8183d 100644 --- a/bootstrap/modules/azure/azure_devops_agents.tf +++ b/bootstrap/modules/azure/azure_devops_agents.tf @@ -1,37 +1,37 @@ -resource "azurerm_container_group" "alz" { - for_each = var.create_agents ? var.agent_container_instances : {} - name = each.value.container_instance_name - location = var.azure_location - resource_group_name = azurerm_resource_group.agents[0].name - ip_address_type = "None" - os_type = "Linux" - - identity { - type = "UserAssigned" - identity_ids = [ - azurerm_user_assigned_identity.alz.id - ] - } - - container { - name = each.value.container_instance_name - image = var.agent_container_instance_image - cpu = "1" - memory = "4" - - ports { - port = 80 - protocol = "TCP" - } - - environment_variables = { - AZP_URL = var.agent_organization_url - AZP_POOL = var.agent_pool_name - AZP_AGENT_NAME = each.value.agent_name - } - - secure_environment_variables = { - AZP_TOKEN = var.agent_token - } - } -} \ No newline at end of file +resource "azurerm_container_group" "alz" { + for_each = var.create_agents ? var.agent_container_instances : {} + name = each.value.container_instance_name + location = var.azure_location + resource_group_name = azurerm_resource_group.agents[0].name + ip_address_type = "None" + os_type = "Linux" + + identity { + type = "UserAssigned" + identity_ids = [ + azurerm_user_assigned_identity.alz.id + ] + } + + container { + name = each.value.container_instance_name + image = var.agent_container_instance_image + cpu = "1" + memory = "4" + + ports { + port = 80 + protocol = "TCP" + } + + environment_variables = { + AZP_URL = var.agent_organization_url + AZP_POOL = var.agent_pool_name + AZP_AGENT_NAME = each.value.agent_name + } + + secure_environment_variables = { + AZP_TOKEN = var.agent_token + } + } +} diff --git a/bootstrap/modules/azure/locals.tf b/bootstrap/modules/azure/locals.tf index 6e5bcb73..cc452036 100644 --- a/bootstrap/modules/azure/locals.tf +++ b/bootstrap/modules/azure/locals.tf @@ -1,3 +1,3 @@ -locals { - audience = "api://AzureADTokenExchange" -} \ No newline at end of file +locals { + audience = "api://AzureADTokenExchange" +} diff --git a/bootstrap/modules/azure/managed_identity.tf b/bootstrap/modules/azure/managed_identity.tf index 1eeec5ff..3474668b 100644 --- a/bootstrap/modules/azure/managed_identity.tf +++ b/bootstrap/modules/azure/managed_identity.tf @@ -1,45 +1,45 @@ -resource "azurerm_user_assigned_identity" "alz" { - location = var.azure_location - name = var.user_assigned_managed_identity_name - resource_group_name = azurerm_resource_group.identity.name -} - -locals { - federated_credentials = var.create_federated_credential ? var.federated_credential_subjects : {} -} - -resource "azurerm_federated_identity_credential" "alz" { - for_each = local.federated_credentials - name = "${var.federated_credential_name}-${each.key}" - resource_group_name = azurerm_resource_group.identity.name - audience = [local.audience] - issuer = var.federated_credential_issuer - parent_id = azurerm_user_assigned_identity.alz.id - subject = each.value -} - -locals { - subscription_ids = { for subscription_id in distinct(var.target_subscriptions) : subscription_id => subscription_id } -} - -data "azurerm_subscription" "alz" { - for_each = local.subscription_ids - subscription_id = each.key -} - -resource "azurerm_role_assignment" "alz_subscriptions" { - for_each = local.subscription_ids - scope = data.azurerm_subscription.alz[each.key].id - role_definition_name = "Owner" - principal_id = azurerm_user_assigned_identity.alz.principal_id -} - -data "azurerm_management_group" "alz" { - display_name = var.root_management_group_display_name -} - -resource "azurerm_role_assignment" "alz_management_group" { - scope = data.azurerm_management_group.alz.id - role_definition_name = "Management Group Contributor" - principal_id = azurerm_user_assigned_identity.alz.principal_id -} \ No newline at end of file +resource "azurerm_user_assigned_identity" "alz" { + location = var.azure_location + name = var.user_assigned_managed_identity_name + resource_group_name = azurerm_resource_group.identity.name +} + +locals { + federated_credentials = var.create_federated_credential ? var.federated_credential_subjects : {} +} + +resource "azurerm_federated_identity_credential" "alz" { + for_each = local.federated_credentials + name = "${var.federated_credential_name}-${each.key}" + resource_group_name = azurerm_resource_group.identity.name + audience = [local.audience] + issuer = var.federated_credential_issuer + parent_id = azurerm_user_assigned_identity.alz.id + subject = each.value +} + +locals { + subscription_ids = { for subscription_id in distinct(var.target_subscriptions) : subscription_id => subscription_id } +} + +data "azurerm_subscription" "alz" { + for_each = local.subscription_ids + subscription_id = each.key +} + +resource "azurerm_role_assignment" "alz_subscriptions" { + for_each = local.subscription_ids + scope = data.azurerm_subscription.alz[each.key].id + role_definition_name = "Owner" + principal_id = azurerm_user_assigned_identity.alz.principal_id +} + +data "azurerm_management_group" "alz" { + display_name = var.root_management_group_display_name +} + +resource "azurerm_role_assignment" "alz_management_group" { + scope = data.azurerm_management_group.alz.id + role_definition_name = "Management Group Contributor" + principal_id = azurerm_user_assigned_identity.alz.principal_id +} diff --git a/bootstrap/modules/azure/outputs.tf b/bootstrap/modules/azure/outputs.tf index e834e746..ecd8b2f7 100644 --- a/bootstrap/modules/azure/outputs.tf +++ b/bootstrap/modules/azure/outputs.tf @@ -1,3 +1,3 @@ -output "user_assigned_managed_identity_client_id" { - value = azurerm_user_assigned_identity.alz.client_id -} \ No newline at end of file +output "user_assigned_managed_identity_client_id" { + value = azurerm_user_assigned_identity.alz.client_id +} diff --git a/bootstrap/modules/azure/providers.tf b/bootstrap/modules/azure/providers.tf index d300f8b9..032b41eb 100644 --- a/bootstrap/modules/azure/providers.tf +++ b/bootstrap/modules/azure/providers.tf @@ -1,8 +1,8 @@ -terraform { - required_providers { - azurerm = { - source = "hashicorp/azurerm" - version = "3.61.0" - } - } -} \ No newline at end of file +terraform { + required_providers { + azurerm = { + source = "hashicorp/azurerm" + version = "3.61.0" + } + } +} diff --git a/bootstrap/modules/azure/resource_groups.tf b/bootstrap/modules/azure/resource_groups.tf index 62c7a145..35f530ac 100644 --- a/bootstrap/modules/azure/resource_groups.tf +++ b/bootstrap/modules/azure/resource_groups.tf @@ -12,4 +12,4 @@ resource "azurerm_resource_group" "agents" { count = var.create_agents_resource_group ? 1 : 0 name = var.resource_group_agents_name location = var.azure_location -} \ No newline at end of file +} diff --git a/bootstrap/modules/azure/storage.tf b/bootstrap/modules/azure/storage.tf index aa03dec1..0d25f3d1 100644 --- a/bootstrap/modules/azure/storage.tf +++ b/bootstrap/modules/azure/storage.tf @@ -17,4 +17,4 @@ resource "azurerm_role_assignment" "alz_storage_container" { scope = azurerm_storage_container.alz.resource_manager_id role_definition_name = "Storage Blob Data Owner" principal_id = azurerm_user_assigned_identity.alz.principal_id -} \ No newline at end of file +} diff --git a/bootstrap/modules/azure/variables.tf b/bootstrap/modules/azure/variables.tf index e3957211..3c35da66 100644 --- a/bootstrap/modules/azure/variables.tf +++ b/bootstrap/modules/azure/variables.tf @@ -1,93 +1,93 @@ -variable "azure_location" { - type = string -} - -variable "user_assigned_managed_identity_name" { - type = string -} - -variable "create_federated_credential" { - type = bool - default = true -} - -variable "federated_credential_subjects" { - type = map(string) -} - -variable "federated_credential_issuer" { - type = string -} - -variable "federated_credential_name" { - type = string -} - -variable "create_agents_resource_group" { - type = bool - default = false -} - -variable "resource_group_identity_name" { - type = string -} - -variable "resource_group_agents_name" { - type = string - default = "" -} - -variable "resource_group_state_name" { - type = string -} - -variable "storage_account_name" { - type = string -} - -variable "storage_container_name" { - type = string -} - -variable "create_agents" { - type = bool - default = false -} - -variable "agent_container_instances" { - type = map(object({ - container_instance_name = string - agent_name = string - })) - default = {} -} - -variable "agent_container_instance_image" { - type = string - default = "" -} - -variable "agent_pool_name" { - type = string - default = "" -} - -variable "agent_organization_url" { - type = string - default = "" -} - -variable "agent_token" { - type = string - sensitive = true - default = "" -} - -variable "target_subscriptions" { - type = list(string) -} - -variable "root_management_group_display_name" { - description = "The root management group display name" - type = string -} \ No newline at end of file +variable "azure_location" { + type = string +} + +variable "user_assigned_managed_identity_name" { + type = string +} + +variable "create_federated_credential" { + type = bool + default = true +} + +variable "federated_credential_subjects" { + type = map(string) +} + +variable "federated_credential_issuer" { + type = string +} + +variable "federated_credential_name" { + type = string +} + +variable "create_agents_resource_group" { + type = bool + default = false +} + +variable "resource_group_identity_name" { + type = string +} + +variable "resource_group_agents_name" { + type = string + default = "" +} + +variable "resource_group_state_name" { + type = string +} + +variable "storage_account_name" { + type = string +} + +variable "storage_container_name" { + type = string +} + +variable "create_agents" { + type = bool + default = false +} + +variable "agent_container_instances" { + type = map(object({ + container_instance_name = string + agent_name = string + })) + default = {} +} + +variable "agent_container_instance_image" { + type = string + default = "" +} + +variable "agent_pool_name" { + type = string + default = "" +} + +variable "agent_organization_url" { + type = string + default = "" +} + +variable "agent_token" { + type = string + sensitive = true + default = "" +} + +variable "target_subscriptions" { + type = list(string) +} + +variable "root_management_group_display_name" { + description = "The root management group display name" + type = string +} diff --git a/bootstrap/modules/azure_devops/agent_pool.tf b/bootstrap/modules/azure_devops/agent_pool.tf index 35119068..e4518d50 100644 --- a/bootstrap/modules/azure_devops/agent_pool.tf +++ b/bootstrap/modules/azure_devops/agent_pool.tf @@ -1,11 +1,11 @@ - -resource "azuredevops_agent_pool" "alz" { - name = var.agent_pool_name - auto_provision = false - auto_update = true -} - -resource "azuredevops_agent_queue" "alz" { - project_id = local.project_id - agent_pool_id = azuredevops_agent_pool.alz.id -} \ No newline at end of file + +resource "azuredevops_agent_pool" "alz" { + name = var.agent_pool_name + auto_provision = false + auto_update = true +} + +resource "azuredevops_agent_queue" "alz" { + project_id = local.project_id + agent_pool_id = azuredevops_agent_pool.alz.id +} diff --git a/bootstrap/modules/azure_devops/environment.tf b/bootstrap/modules/azure_devops/environment.tf index fcb3dd2c..7fcc4a09 100644 --- a/bootstrap/modules/azure_devops/environment.tf +++ b/bootstrap/modules/azure_devops/environment.tf @@ -1,37 +1,37 @@ -resource "azuredevops_environment" "alz_plan" { - name = var.environment_name_plan - project_id = local.project_id -} - -resource "azuredevops_environment" "alz_apply" { - name = var.environment_name_apply - project_id = local.project_id -} - -resource "azuredevops_check_approval" "alz" { - count = var.approvers == [] ? 0 : 1 - project_id = local.project_id - target_resource_id = azuredevops_environment.alz_apply.id - target_resource_type = "environment" - - requester_can_approve = length(var.approvers) == 1 - approvers = [ - azuredevops_group.alz_approvers.origin_id - ] - - timeout = 43200 -} - -resource "azuredevops_check_exclusive_lock" "alz_plan" { - project_id = local.project_id - target_resource_id = azuredevops_environment.alz_plan.id - target_resource_type = "environment" - timeout = 43200 -} - -resource "azuredevops_check_exclusive_lock" "alz_apply" { - project_id = local.project_id - target_resource_id = azuredevops_environment.alz_apply.id - target_resource_type = "environment" - timeout = 43200 -} \ No newline at end of file +resource "azuredevops_environment" "alz_plan" { + name = var.environment_name_plan + project_id = local.project_id +} + +resource "azuredevops_environment" "alz_apply" { + name = var.environment_name_apply + project_id = local.project_id +} + +resource "azuredevops_check_approval" "alz" { + count = length(var.approvers) == 0 ? 0 : 1 + project_id = local.project_id + target_resource_id = azuredevops_environment.alz_apply.id + target_resource_type = "environment" + + requester_can_approve = length(var.approvers) == 1 + approvers = [ + azuredevops_group.alz_approvers.origin_id + ] + + timeout = 43200 +} + +resource "azuredevops_check_exclusive_lock" "alz_plan" { + project_id = local.project_id + target_resource_id = azuredevops_environment.alz_plan.id + target_resource_type = "environment" + timeout = 43200 +} + +resource "azuredevops_check_exclusive_lock" "alz_apply" { + project_id = local.project_id + target_resource_id = azuredevops_environment.alz_apply.id + target_resource_type = "environment" + timeout = 43200 +} diff --git a/bootstrap/modules/azure_devops/groups.tf b/bootstrap/modules/azure_devops/groups.tf index b80644a1..fff7c5bb 100644 --- a/bootstrap/modules/azure_devops/groups.tf +++ b/bootstrap/modules/azure_devops/groups.tf @@ -1,21 +1,21 @@ -resource "azuredevops_group" "alz_approvers" { - scope = local.project_id - display_name = var.group_name - description = "Approvers for the Landing Zone Terraform Apply" -} - -data "azuredevops_users" "alz" { - for_each = { for approver in var.approvers : approver => approver } - principal_name = each.key -} - -locals { - approvers = toset(flatten([for approver in data.azuredevops_users.alz : - [for user in approver.users : user.descriptor] - ])) -} - -resource "azuredevops_group_membership" "alz_approvers" { - group = azuredevops_group.alz_approvers.descriptor - members = local.approvers -} \ No newline at end of file +resource "azuredevops_group" "alz_approvers" { + scope = local.project_id + display_name = var.group_name + description = "Approvers for the Landing Zone Terraform Apply" +} + +data "azuredevops_users" "alz" { + for_each = { for approver in var.approvers : approver => approver } + principal_name = each.key +} + +locals { + approvers = toset(flatten([for approver in data.azuredevops_users.alz : + [for user in approver.users : user.descriptor] + ])) +} + +resource "azuredevops_group_membership" "alz_approvers" { + group = azuredevops_group.alz_approvers.descriptor + members = local.approvers +} diff --git a/bootstrap/modules/azure_devops/locals.tf b/bootstrap/modules/azure_devops/locals.tf index c44df10c..ef150c3f 100644 --- a/bootstrap/modules/azure_devops/locals.tf +++ b/bootstrap/modules/azure_devops/locals.tf @@ -1,10 +1,10 @@ -locals { - organization_url = var.use_legacy_organization_url ? "https://${var.organization_name}.visualstudio.com" : "https://dev.azure.com/${var.organization_name}" -} - -locals { - authentication_scheme_managed_identity = "ManagedServiceIdentity" - authentication_scheme_workload_identity_federation = "WorkloadIdentityFederation" - is_authentication_scheme_managed_identity = var.authentication_scheme == local.authentication_scheme_managed_identity - is_authentication_scheme_workload_identity_federation = var.authentication_scheme == local.authentication_scheme_workload_identity_federation -} \ No newline at end of file +locals { + organization_url = var.use_legacy_organization_url ? "https://${var.organization_name}.visualstudio.com" : "https://dev.azure.com/${var.organization_name}" +} + +locals { + authentication_scheme_managed_identity = "ManagedServiceIdentity" + authentication_scheme_workload_identity_federation = "WorkloadIdentityFederation" + is_authentication_scheme_managed_identity = var.authentication_scheme == local.authentication_scheme_managed_identity + is_authentication_scheme_workload_identity_federation = var.authentication_scheme == local.authentication_scheme_workload_identity_federation +} diff --git a/bootstrap/modules/azure_devops/outputs.tf b/bootstrap/modules/azure_devops/outputs.tf index f2d91bf0..922a105d 100644 --- a/bootstrap/modules/azure_devops/outputs.tf +++ b/bootstrap/modules/azure_devops/outputs.tf @@ -1,23 +1,23 @@ -output "organization_url" { - value = local.organization_url -} - -output "subject" { - value = local.is_authentication_scheme_workload_identity_federation ? azuredevops_serviceendpoint_azurerm.alz.workload_identity_federation_subject : "" -} - -output "issuer" { - value = local.is_authentication_scheme_workload_identity_federation ? azuredevops_serviceendpoint_azurerm.alz.workload_identity_federation_issuer : "" -} - -output "agent_pool_name" { - value = local.is_authentication_scheme_managed_identity ? azuredevops_agent_pool.alz.name : "" -} - -output "is_authentication_scheme_managed_identity" { - value = local.is_authentication_scheme_managed_identity -} - -output "is_authentication_scheme_workload_identity_federation" { - value = local.is_authentication_scheme_workload_identity_federation -} \ No newline at end of file +output "organization_url" { + value = local.organization_url +} + +output "subject" { + value = local.is_authentication_scheme_workload_identity_federation ? azuredevops_serviceendpoint_azurerm.alz.workload_identity_federation_subject : "" +} + +output "issuer" { + value = local.is_authentication_scheme_workload_identity_federation ? azuredevops_serviceendpoint_azurerm.alz.workload_identity_federation_issuer : "" +} + +output "agent_pool_name" { + value = local.is_authentication_scheme_managed_identity ? azuredevops_agent_pool.alz.name : "" +} + +output "is_authentication_scheme_managed_identity" { + value = local.is_authentication_scheme_managed_identity +} + +output "is_authentication_scheme_workload_identity_federation" { + value = local.is_authentication_scheme_workload_identity_federation +} diff --git a/bootstrap/modules/azure_devops/pipeline.tf b/bootstrap/modules/azure_devops/pipeline.tf index 33e7de0c..9da9cde2 100644 --- a/bootstrap/modules/azure_devops/pipeline.tf +++ b/bootstrap/modules/azure_devops/pipeline.tf @@ -1,61 +1,61 @@ -locals { - pipelines = { - ci = { - name = "Azure Landing Zone Continuous Integration" - file = azuredevops_git_repository_file.alz[var.pipeline_ci_file].file - } - cd = { - name = "Azure Landing Zone Continuous Delivery" - file = azuredevops_git_repository_file.alz[var.pipeline_cd_file].file - } - } -} - -resource "azuredevops_build_definition" "alz" { - for_each = local.pipelines - project_id = local.project_id - name = each.value.name - - ci_trigger { - use_yaml = true - } - - repository { - repo_type = "TfsGit" - repo_id = azuredevops_git_repository.alz.id - branch_name = azuredevops_git_repository.alz.default_branch - yml_path = each.value.file - } -} - -resource "azuredevops_pipeline_authorization" "alz_environment_plan" { - for_each = local.pipelines - project_id = local.project_id - resource_id = azuredevops_environment.alz_plan.id - type = "environment" - pipeline_id = azuredevops_build_definition.alz[each.key].id -} - -resource "azuredevops_pipeline_authorization" "alz_environment_apply" { - for_each = local.pipelines - project_id = local.project_id - resource_id = azuredevops_environment.alz_apply.id - type = "environment" - pipeline_id = azuredevops_build_definition.alz[each.key].id -} - -resource "azuredevops_pipeline_authorization" "alz_service_connection" { - for_each = local.pipelines - project_id = local.project_id - resource_id = azuredevops_serviceendpoint_azurerm.alz.id - type = "endpoint" - pipeline_id = azuredevops_build_definition.alz[each.key].id -} - -resource "azuredevops_pipeline_authorization" "alz" { - for_each = local.pipelines - project_id = local.project_id - resource_id = azuredevops_agent_queue.alz.id - type = "queue" - pipeline_id = azuredevops_build_definition.alz[each.key].id -} \ No newline at end of file +locals { + pipelines = { + ci = { + name = "Azure Landing Zone Continuous Integration" + file = azuredevops_git_repository_file.alz[var.pipeline_ci_file].file + } + cd = { + name = "Azure Landing Zone Continuous Delivery" + file = azuredevops_git_repository_file.alz[var.pipeline_cd_file].file + } + } +} + +resource "azuredevops_build_definition" "alz" { + for_each = local.pipelines + project_id = local.project_id + name = each.value.name + + ci_trigger { + use_yaml = true + } + + repository { + repo_type = "TfsGit" + repo_id = azuredevops_git_repository.alz.id + branch_name = azuredevops_git_repository.alz.default_branch + yml_path = each.value.file + } +} + +resource "azuredevops_pipeline_authorization" "alz_environment_plan" { + for_each = local.pipelines + project_id = local.project_id + resource_id = azuredevops_environment.alz_plan.id + type = "environment" + pipeline_id = azuredevops_build_definition.alz[each.key].id +} + +resource "azuredevops_pipeline_authorization" "alz_environment_apply" { + for_each = local.pipelines + project_id = local.project_id + resource_id = azuredevops_environment.alz_apply.id + type = "environment" + pipeline_id = azuredevops_build_definition.alz[each.key].id +} + +resource "azuredevops_pipeline_authorization" "alz_service_connection" { + for_each = local.pipelines + project_id = local.project_id + resource_id = azuredevops_serviceendpoint_azurerm.alz.id + type = "endpoint" + pipeline_id = azuredevops_build_definition.alz[each.key].id +} + +resource "azuredevops_pipeline_authorization" "alz" { + for_each = local.pipelines + project_id = local.project_id + resource_id = azuredevops_agent_queue.alz.id + type = "queue" + pipeline_id = azuredevops_build_definition.alz[each.key].id +} diff --git a/bootstrap/modules/azure_devops/project.tf b/bootstrap/modules/azure_devops/project.tf index 4fd03dd5..6509b127 100644 --- a/bootstrap/modules/azure_devops/project.tf +++ b/bootstrap/modules/azure_devops/project.tf @@ -1,13 +1,13 @@ -resource "azuredevops_project" "alz" { - count = var.create_project ? 1 : 0 - name = var.project_name -} - -data "azuredevops_project" "alz" { - count = var.create_project ? 0 : 1 - name = var.project_name -} - -locals { - project_id = var.create_project ? azuredevops_project.alz[0].id : data.azuredevops_project.alz[0].id -} +resource "azuredevops_project" "alz" { + count = var.create_project ? 1 : 0 + name = var.project_name +} + +data "azuredevops_project" "alz" { + count = var.create_project ? 0 : 1 + name = var.project_name +} + +locals { + project_id = var.create_project ? azuredevops_project.alz[0].id : data.azuredevops_project.alz[0].id +} diff --git a/bootstrap/modules/azure_devops/providers.tf b/bootstrap/modules/azure_devops/providers.tf index e890fc9b..f6c5b58a 100644 --- a/bootstrap/modules/azure_devops/providers.tf +++ b/bootstrap/modules/azure_devops/providers.tf @@ -1,8 +1,8 @@ -terraform { - required_providers { - azuredevops = { - source = "microsoft/azuredevops" - version = ">=0.8.0" - } - } -} \ No newline at end of file +terraform { + required_providers { + azuredevops = { + source = "microsoft/azuredevops" + version = ">=0.8.0" + } + } +} diff --git a/bootstrap/modules/azure_devops/repository.tf b/bootstrap/modules/azure_devops/repository.tf index 925903b0..f96b4a72 100644 --- a/bootstrap/modules/azure_devops/repository.tf +++ b/bootstrap/modules/azure_devops/repository.tf @@ -103,4 +103,4 @@ resource "azuredevops_branch_policy_build_validation" "alz" { match_type = "Exact" } } -} \ No newline at end of file +} diff --git a/bootstrap/modules/azure_devops/service_connections.tf b/bootstrap/modules/azure_devops/service_connections.tf index 5d369e06..962ee287 100644 --- a/bootstrap/modules/azure_devops/service_connections.tf +++ b/bootstrap/modules/azure_devops/service_connections.tf @@ -1,17 +1,17 @@ -resource "azuredevops_serviceendpoint_azurerm" "alz" { - project_id = local.project_id - service_endpoint_name = var.service_connection_name - description = "Managed by Terraform" - service_endpoint_authentication_scheme = var.authentication_scheme - - dynamic "credentials" { - for_each = local.is_authentication_scheme_workload_identity_federation ? [1] : [] - content { - serviceprincipalid = var.managed_identity_client_id - } - } - - azurerm_spn_tenantid = var.azure_tenant_id - azurerm_subscription_id = var.azure_subscription_id - azurerm_subscription_name = var.azure_subscription_name -} \ No newline at end of file +resource "azuredevops_serviceendpoint_azurerm" "alz" { + project_id = local.project_id + service_endpoint_name = var.service_connection_name + description = "Managed by Terraform" + service_endpoint_authentication_scheme = var.authentication_scheme + + dynamic "credentials" { + for_each = local.is_authentication_scheme_workload_identity_federation ? [1] : [] + content { + serviceprincipalid = var.managed_identity_client_id + } + } + + azurerm_spn_tenantid = var.azure_tenant_id + azurerm_subscription_id = var.azure_subscription_id + azurerm_subscription_name = var.azure_subscription_name +} diff --git a/bootstrap/modules/azure_devops/variable_group.tf b/bootstrap/modules/azure_devops/variable_group.tf index 7b3d6be7..ebebcc2e 100644 --- a/bootstrap/modules/azure_devops/variable_group.tf +++ b/bootstrap/modules/azure_devops/variable_group.tf @@ -1,21 +1,21 @@ -resource "azuredevops_variable_group" "example" { - project_id = local.project_id - name = var.variable_group_name - description = var.variable_group_name - allow_access = true - - variable { - name = "BACKEND_AZURE_RESOURCE_GROUP_NAME" - value = var.backend_azure_resource_group_name - } - - variable { - name = "BACKEND_AZURE_STORAGE_ACCOUNT_NAME" - value = var.backend_azure_storage_account_name - } - - variable { - name = "BACKEND_AZURE_STORAGE_ACCOUNT_CONTAINER_NAME" - value = var.backend_azure_storage_account_container_name - } -} \ No newline at end of file +resource "azuredevops_variable_group" "example" { + project_id = local.project_id + name = var.variable_group_name + description = var.variable_group_name + allow_access = true + + variable { + name = "BACKEND_AZURE_RESOURCE_GROUP_NAME" + value = var.backend_azure_resource_group_name + } + + variable { + name = "BACKEND_AZURE_STORAGE_ACCOUNT_NAME" + value = var.backend_azure_storage_account_name + } + + variable { + name = "BACKEND_AZURE_STORAGE_ACCOUNT_CONTAINER_NAME" + value = var.backend_azure_storage_account_container_name + } +} diff --git a/bootstrap/modules/azure_devops/variables.tf b/bootstrap/modules/azure_devops/variables.tf index e8e1a582..11c3d223 100644 --- a/bootstrap/modules/azure_devops/variables.tf +++ b/bootstrap/modules/azure_devops/variables.tf @@ -1,103 +1,98 @@ -variable "access_token" { - type = string - sensitive = true -} - -variable "authentication_scheme" { - type = string - validation { - condition = can(regex("^(ManagedServiceIdentity|WorkloadIdentityFederation)$", var.authentication_scheme)) - error_message = "authentication_scheme must be either ManagedServiceIdentity or WorkloadIdentityFederation" - } -} - -variable "use_legacy_organization_url" { - type = bool -} - -variable "organization_name" { - type = string -} - -variable "create_project" { - type = bool -} - -variable "project_name" { - type = string -} - -variable "environment_name_plan" { - type = string -} - -variable "environment_name_apply" { - type = string -} - -variable "repository_name" { - type = string -} - -variable "repository_files" { - type = map(object({ - path = string - flag = string - })) -} - -variable "pipeline_ci_file" { - type = string -} - -variable "pipeline_cd_file" { - type = string -} - -variable "service_connection_name" { - type = string -} - -variable "variable_group_name" { - type = string -} - -variable "agent_pool_name" { - type = string -} - -variable "managed_identity_client_id" { - type = string -} - -variable "azure_tenant_id" { - type = string -} - -variable "azure_subscription_id" { - type = string -} - -variable "azure_subscription_name" { - type = string -} - -variable "backend_azure_resource_group_name" { - type = string -} - -variable "backend_azure_storage_account_name" { - type = string -} - -variable "backend_azure_storage_account_container_name" { - type = string -} - -variable "approvers" { - type = list(string) -} - -variable "group_name" { - type = string -} +variable "authentication_scheme" { + type = string + validation { + condition = can(regex("^(ManagedServiceIdentity|WorkloadIdentityFederation)$", var.authentication_scheme)) + error_message = "authentication_scheme must be either ManagedServiceIdentity or WorkloadIdentityFederation" + } +} + +variable "use_legacy_organization_url" { + type = bool +} + +variable "organization_name" { + type = string +} + +variable "create_project" { + type = bool +} + +variable "project_name" { + type = string +} + +variable "environment_name_plan" { + type = string +} + +variable "environment_name_apply" { + type = string +} + +variable "repository_name" { + type = string +} + +variable "repository_files" { + type = map(object({ + path = string + flag = string + })) +} + +variable "pipeline_ci_file" { + type = string +} + +variable "pipeline_cd_file" { + type = string +} + +variable "service_connection_name" { + type = string +} + +variable "variable_group_name" { + type = string +} + +variable "agent_pool_name" { + type = string +} + +variable "managed_identity_client_id" { + type = string +} + +variable "azure_tenant_id" { + type = string +} + +variable "azure_subscription_id" { + type = string +} + +variable "azure_subscription_name" { + type = string +} + +variable "backend_azure_resource_group_name" { + type = string +} + +variable "backend_azure_storage_account_name" { + type = string +} + +variable "backend_azure_storage_account_container_name" { + type = string +} + +variable "approvers" { + type = list(string) +} + +variable "group_name" { + type = string +} diff --git a/bootstrap/modules/files/main.tf b/bootstrap/modules/files/main.tf index 681902f2..148cb777 100644 --- a/bootstrap/modules/files/main.tf +++ b/bootstrap/modules/files/main.tf @@ -1,14 +1,14 @@ -locals { - files = fileset(var.folder_path, "**") - filtered_files = length(var.exclusions) == 0 ? sort(local.files) : sort(flatten([ - for f in local.files : [ - for e in var.exclusions : - strcontains(f, e) ? [] : [f] - ] - ])) - file_map = { for file in local.filtered_files : file => { - path = "${var.folder_path}/${file}" - flag = var.flag - } - } -} \ No newline at end of file +locals { + files = fileset(var.folder_path, "**") + filtered_files = length(var.exclusions) == 0 ? sort(local.files) : sort(flatten([ + for f in local.files : [ + for e in var.exclusions : + strcontains(f, e) ? [] : [f] + ] + ])) + file_map = { for file in local.filtered_files : file => { + path = "${var.folder_path}/${file}" + flag = var.flag + } + } +} diff --git a/bootstrap/modules/files/outputs.tf b/bootstrap/modules/files/outputs.tf index d866feb4..9f7831c2 100644 --- a/bootstrap/modules/files/outputs.tf +++ b/bootstrap/modules/files/outputs.tf @@ -1,3 +1,3 @@ -output "files" { - value = local.file_map -} \ No newline at end of file +output "files" { + value = local.file_map +} diff --git a/bootstrap/modules/files/variables.tf b/bootstrap/modules/files/variables.tf index 43b4025e..2827fe14 100644 --- a/bootstrap/modules/files/variables.tf +++ b/bootstrap/modules/files/variables.tf @@ -1,16 +1,16 @@ -variable "folder_path" { - description = "Template folder path" - type = string -} - -variable "exclusions" { - description = "List of files / partial file names to exclude" - type = list(string) - default = [] -} - -variable "flag" { - description = "A flag to add to each file object" - type = string - default = "" -} \ No newline at end of file +variable "folder_path" { + description = "Template folder path" + type = string +} + +variable "exclusions" { + description = "List of files / partial file names to exclude" + type = list(string) + default = [] +} + +variable "flag" { + description = "A flag to add to each file object" + type = string + default = "" +} diff --git a/bootstrap/modules/github/action_variables.tf b/bootstrap/modules/github/action_variables.tf index f4c0a3c8..2637100d 100644 --- a/bootstrap/modules/github/action_variables.tf +++ b/bootstrap/modules/github/action_variables.tf @@ -1,35 +1,35 @@ -resource "github_actions_variable" "azure_client_id" { - repository = github_repository.alz.name - variable_name = "AZURE_CLIENT_ID" - value = var.managed_identity_client_id -} - -resource "github_actions_variable" "azure_subscription_id" { - repository = github_repository.alz.name - variable_name = "AZURE_SUBSCRIPTION_ID" - value = var.azure_subscription_id -} - -resource "github_actions_variable" "azure_tenant_id" { - repository = github_repository.alz.name - variable_name = "AZURE_TENANT_ID" - value = var.azure_tenant_id -} - -resource "github_actions_variable" "backend_azure_resource_group_name" { - repository = github_repository.alz.name - variable_name = "BACKEND_AZURE_RESOURCE_GROUP_NAME" - value = var.backend_azure_resource_group_name -} - -resource "github_actions_variable" "backend_azure_storage_account_name" { - repository = github_repository.alz.name - variable_name = "BACKEND_AZURE_STORAGE_ACCOUNT_NAME" - value = var.backend_azure_storage_account_name -} - -resource "github_actions_variable" "backend_azure_storage_account_container_name" { - repository = github_repository.alz.name - variable_name = "BACKEND_AZURE_STORAGE_ACCOUNT_CONTAINER_NAME" - value = var.backend_azure_storage_account_container_name -} \ No newline at end of file +resource "github_actions_variable" "azure_client_id" { + repository = github_repository.alz.name + variable_name = "AZURE_CLIENT_ID" + value = var.managed_identity_client_id +} + +resource "github_actions_variable" "azure_subscription_id" { + repository = github_repository.alz.name + variable_name = "AZURE_SUBSCRIPTION_ID" + value = var.azure_subscription_id +} + +resource "github_actions_variable" "azure_tenant_id" { + repository = github_repository.alz.name + variable_name = "AZURE_TENANT_ID" + value = var.azure_tenant_id +} + +resource "github_actions_variable" "backend_azure_resource_group_name" { + repository = github_repository.alz.name + variable_name = "BACKEND_AZURE_RESOURCE_GROUP_NAME" + value = var.backend_azure_resource_group_name +} + +resource "github_actions_variable" "backend_azure_storage_account_name" { + repository = github_repository.alz.name + variable_name = "BACKEND_AZURE_STORAGE_ACCOUNT_NAME" + value = var.backend_azure_storage_account_name +} + +resource "github_actions_variable" "backend_azure_storage_account_container_name" { + repository = github_repository.alz.name + variable_name = "BACKEND_AZURE_STORAGE_ACCOUNT_CONTAINER_NAME" + value = var.backend_azure_storage_account_container_name +} diff --git a/bootstrap/modules/github/locals.tf b/bootstrap/modules/github/locals.tf index 6c613787..db7ff1be 100644 --- a/bootstrap/modules/github/locals.tf +++ b/bootstrap/modules/github/locals.tf @@ -1,3 +1,3 @@ -locals { - organization_url = "https://github.com/${var.organization_name}" -} \ No newline at end of file +locals { + organization_url = "https://github.com/${var.organization_name}" +} diff --git a/bootstrap/modules/github/outputs.tf b/bootstrap/modules/github/outputs.tf index 6de43e0d..e363348a 100644 --- a/bootstrap/modules/github/outputs.tf +++ b/bootstrap/modules/github/outputs.tf @@ -1,18 +1,18 @@ -output "organization_url" { - value = local.organization_url -} - -output "subjects" { - value = { - plan = "repo:${var.organization_name}/${var.repository_name}:environment:${var.environment_name_plan}" - apply = "repo:${var.organization_name}/${var.repository_name}:environment:${var.environment_name_apply}" - } -} - -output "issuer" { - value = "https://token.actions.githubusercontent.com" -} - -output "organization_users" { - value = data.github_organization.alz.users -} \ No newline at end of file +output "organization_url" { + value = local.organization_url +} + +output "subjects" { + value = { + plan = "repo:${var.organization_name}/${var.repository_name}:environment:${var.environment_name_plan}" + apply = "repo:${var.organization_name}/${var.repository_name}:environment:${var.environment_name_apply}" + } +} + +output "issuer" { + value = "https://token.actions.githubusercontent.com" +} + +output "organization_users" { + value = data.github_organization.alz.users +} diff --git a/bootstrap/modules/github/providers.tf b/bootstrap/modules/github/providers.tf index 3ceec425..0cf4e411 100644 --- a/bootstrap/modules/github/providers.tf +++ b/bootstrap/modules/github/providers.tf @@ -1,8 +1,8 @@ -terraform { - required_providers { - github = { - source = "integrations/github" - version = "~> 5.36" - } - } -} \ No newline at end of file +terraform { + required_providers { + github = { + source = "integrations/github" + version = "~> 5.36" + } + } +} diff --git a/bootstrap/modules/github/repository.tf b/bootstrap/modules/github/repository.tf index c5d8b545..80f6f52a 100644 --- a/bootstrap/modules/github/repository.tf +++ b/bootstrap/modules/github/repository.tf @@ -48,4 +48,4 @@ resource "github_branch_protection" "alz" { restrict_dismissals = true required_approving_review_count = 1 } -} \ No newline at end of file +} diff --git a/bootstrap/modules/github/team.tf b/bootstrap/modules/github/team.tf index 19104e50..ef6e2a3e 100644 --- a/bootstrap/modules/github/team.tf +++ b/bootstrap/modules/github/team.tf @@ -1,26 +1,26 @@ -data "github_organization" "alz" { - name = var.organization_name -} - -locals { - approvers = [for user in data.github_organization.alz.users : user.login if contains(var.approvers, user.email)] -} - -resource "github_team" "alz" { - name = var.team_name - description = "Approvers for the Landing Zone Terraform Apply" - privacy = "closed" -} - -resource "github_team_membership" "alz" { - for_each = { for approver in local.approvers : approver => approver } - team_id = github_team.alz.id - username = each.key - role = "member" -} - -resource "github_team_repository" "alz" { - team_id = github_team.alz.id - repository = github_repository.alz.name - permission = "push" -} \ No newline at end of file +data "github_organization" "alz" { + name = var.organization_name +} + +locals { + approvers = [for user in data.github_organization.alz.users : user.login if contains(var.approvers, user.email)] +} + +resource "github_team" "alz" { + name = var.team_name + description = "Approvers for the Landing Zone Terraform Apply" + privacy = "closed" +} + +resource "github_team_membership" "alz" { + for_each = { for approver in local.approvers : approver => approver } + team_id = github_team.alz.id + username = each.key + role = "member" +} + +resource "github_team_repository" "alz" { + team_id = github_team.alz.id + repository = github_repository.alz.name + permission = "push" +} diff --git a/bootstrap/modules/github/variables.tf b/bootstrap/modules/github/variables.tf index c14488fc..0f4c5330 100644 --- a/bootstrap/modules/github/variables.tf +++ b/bootstrap/modules/github/variables.tf @@ -1,71 +1,58 @@ -variable "access_token" { - type = string - sensitive = true -} - -variable "organization_name" { - type = string -} - -variable "environment_name_plan" { - type = string -} - -variable "environment_name_apply" { - type = string -} - -variable "repository_name" { - type = string -} - -variable "repository_visibility" { - type = string -} - -variable "repository_files" { - type = map(object({ - path = string - flag = string - })) -} - -variable "pipeline_ci_file" { - type = string -} - -variable "pipeline_cd_file" { - type = string -} - -variable "managed_identity_client_id" { - type = string -} - -variable "azure_tenant_id" { - type = string -} - -variable "azure_subscription_id" { - type = string -} - -variable "backend_azure_resource_group_name" { - type = string -} - -variable "backend_azure_storage_account_name" { - type = string -} - -variable "backend_azure_storage_account_container_name" { - type = string -} - -variable "approvers" { - type = list(string) -} - -variable "team_name" { - type = string -} \ No newline at end of file +variable "organization_name" { + type = string +} + +variable "environment_name_plan" { + type = string +} + +variable "environment_name_apply" { + type = string +} + +variable "repository_name" { + type = string +} + +variable "repository_visibility" { + type = string +} + +variable "repository_files" { + type = map(object({ + path = string + flag = string + })) +} + +variable "managed_identity_client_id" { + type = string +} + +variable "azure_tenant_id" { + type = string +} + +variable "azure_subscription_id" { + type = string +} + +variable "backend_azure_resource_group_name" { + type = string +} + +variable "backend_azure_storage_account_name" { + type = string +} + +variable "backend_azure_storage_account_container_name" { + type = string +} + +variable "approvers" { + type = list(string) +} + +variable "team_name" { + type = string +} diff --git a/bootstrap/modules/resource_names/locals.tf b/bootstrap/modules/resource_names/locals.tf index 82684c27..edf0000f 100644 --- a/bootstrap/modules/resource_names/locals.tf +++ b/bootstrap/modules/resource_names/locals.tf @@ -1,22 +1,22 @@ -# Resource Name Setup -resource "random_string" "alz" { - length = 4 - special = false - upper = false -} - -locals { - formatted_postfix_number = format("%03d", var.postfix_number) - formatted_postfix_number_plus_one = format("%03d", var.postfix_number + 1) - random_string = random_string.alz.result - resource_names = { - for key, value in var.resource_names : key => replace(replace(replace(replace(replace(replace(replace(value, - "{{service_name}}", var.service_name), - "{{environment_name}}", var.environment_name), - "{{azure_location}}", var.azure_location), - "{{azure_location_short}}", substr(var.azure_location, 0, 3)), - "{{postfix_number}}", local.formatted_postfix_number), - "{{postfix_number_plus_one}}", local.formatted_postfix_number_plus_one), - "{{random_string}}", local.random_string) - } -} \ No newline at end of file +# Resource Name Setup +resource "random_string" "alz" { + length = 4 + special = false + upper = false +} + +locals { + formatted_postfix_number = format("%03d", var.postfix_number) + formatted_postfix_number_plus_one = format("%03d", var.postfix_number + 1) + random_string = random_string.alz.result + resource_names = { + for key, value in var.resource_names : key => replace(replace(replace(replace(replace(replace(replace(value, + "{{service_name}}", var.service_name), + "{{environment_name}}", var.environment_name), + "{{azure_location}}", var.azure_location), + "{{azure_location_short}}", substr(var.azure_location, 0, 3)), + "{{postfix_number}}", local.formatted_postfix_number), + "{{postfix_number_plus_one}}", local.formatted_postfix_number_plus_one), + "{{random_string}}", local.random_string) + } +} diff --git a/bootstrap/modules/resource_names/outputs.tf b/bootstrap/modules/resource_names/outputs.tf index 4aef6c14..2b0596d0 100644 --- a/bootstrap/modules/resource_names/outputs.tf +++ b/bootstrap/modules/resource_names/outputs.tf @@ -1,3 +1,3 @@ -output "resource_names" { - value = local.resource_names -} \ No newline at end of file +output "resource_names" { + value = local.resource_names +} diff --git a/bootstrap/modules/resource_names/providers.tf b/bootstrap/modules/resource_names/providers.tf new file mode 100644 index 00000000..0b35089d --- /dev/null +++ b/bootstrap/modules/resource_names/providers.tf @@ -0,0 +1,8 @@ +terraform { + required_providers { + random = { + source = "hashicorp/random" + version = "~> 3.5" + } + } +} diff --git a/bootstrap/modules/resource_names/variables.tf b/bootstrap/modules/resource_names/variables.tf index 93856bae..5f6320ce 100644 --- a/bootstrap/modules/resource_names/variables.tf +++ b/bootstrap/modules/resource_names/variables.tf @@ -1,19 +1,19 @@ -variable "azure_location" { - type = string -} - -variable "environment_name" { - type = string -} - -variable "service_name" { - type = string -} - -variable "postfix_number" { - type = number -} - -variable "resource_names" { - type = map(string) -} \ No newline at end of file +variable "azure_location" { + type = string +} + +variable "environment_name" { + type = string +} + +variable "service_name" { + type = string +} + +variable "postfix_number" { + type = number +} + +variable "resource_names" { + type = map(string) +} diff --git a/docs/wiki/Frequently-Asked-Questions.md b/docs/wiki/Frequently-Asked-Questions.md index f1a93c01..1ddd5e63 100644 --- a/docs/wiki/Frequently-Asked-Questions.md +++ b/docs/wiki/Frequently-Asked-Questions.md @@ -38,9 +38,9 @@ You'll now be able to delete the `./v#.#.#` folder and run the `New-ALZEnvironme ## Multiple landing zone deployments -### I want to deploy multiple landing zones, but the PowerShell command keeps trying to overrwrite my existing environment. +### I want to deploy multiple landing zones, but the PowerShell command keeps trying to overrwrite my existing environment -After bootstrapping, the PowerShell leaves the folder structure intact, including the Terraform state file. This is by design, so you have an opportunity to amend or destroy the environment. +After bootstrapping, the PowerShell leaves the folder structure intact, including the Terraform state file. This is by design, so you have an opportunity to amend or destroy the environment. If you want to deploy to a separate environment, the simplest approach is to specify a separate folder for each deployment using the `-Output` parameter. For example: diff --git a/docs/wiki/Home.md b/docs/wiki/Home.md index 4acf8baf..d3782bb6 100644 --- a/docs/wiki/Home.md +++ b/docs/wiki/Home.md @@ -116,7 +116,3 @@ The following diagram and links detail the Azure landing zone, but you can learn [alz_tf_registry]: https://registry.terraform.io/modules/Azure/caf-enterprise-scale/azurerm/latest "Terraform Registry: Azure landing zones Terraform module" [alz_architecture]: https://learn.microsoft.com/azure/cloud-adoption-framework/ready/landing-zone#azure-landing-zone-conceptual-architecture -[alz_hierarchy]: https://learn.microsoft.com/azure/cloud-adoption-framework/ready/landing-zone/design-area/resource-org -[alz_management]: https://learn.microsoft.com/azure/cloud-adoption-framework/ready/landing-zone/design-area/management -[alz_connectivity]: https://learn.microsoft.com/azure/cloud-adoption-framework/ready/landing-zone/design-area/network-topology-and-connectivity -[alz_identity]: https://learn.microsoft.com/azure/cloud-adoption-framework/ready/landing-zone/design-area/identity-access diff --git a/docs/wiki/Raising-an-Issue.md b/docs/wiki/Raising-an-Issue.md index 9da15a1c..ed57bf8e 100644 --- a/docs/wiki/Raising-an-Issue.md +++ b/docs/wiki/Raising-an-Issue.md @@ -6,4 +6,4 @@ Fill out the Bug or Feature template in full and submit the issue for triage. -[Issues]: https://github.com/Azure/alz-terraform-accelerator/issues "Our issues log" \ No newline at end of file +[Issues]: https://github.com/Azure/alz-terraform-accelerator/issues "Our issues log" diff --git a/docs/wiki/Troubleshooting.md b/docs/wiki/Troubleshooting.md index 55e31029..7e50a027 100644 --- a/docs/wiki/Troubleshooting.md +++ b/docs/wiki/Troubleshooting.md @@ -4,3 +4,5 @@ Having trouble using the module and unable to find a solution in the Wiki? If it isn't listed below, let us know about it in our [Issues][Issues] log. We'll do our best to help and you may find your issue documented here. + +[Issues]: https://github.com/Azure/alz-terraform-accelerator/issues "Our issues log" diff --git a/docs/wiki/User-Guide.md b/docs/wiki/User-Guide.md index abec7366..3174f70b 100644 --- a/docs/wiki/User-Guide.md +++ b/docs/wiki/User-Guide.md @@ -5,9 +5,9 @@ Please refer to the following to learn about the accelerator: - [Getting Started][wiki_getting_started] - [Quick Start][wiki_quick_start] - - [Quick Start Phase 1][wiki_quick_start_phase_1] - - [Quick Start Phase 2][wiki_quick_start_phase_2] - - [Quick Start Phase 3][wiki_quick_start_phase_3] + - [Quick Start Phase 1][wiki_quick_start_phase_1] + - [Quick Start Phase 2][wiki_quick_start_phase_2] + - [Quick Start Phase 3][wiki_quick_start_phase_3] [//]: # (************************) @@ -18,4 +18,4 @@ Please refer to the following to learn about the accelerator: [wiki_quick_start]: %5BUser-Guide%5D-Quick-Start "Wiki - Quick Start" [wiki_quick_start_phase_1]: %5BUser-Guide%5D-Quick-Start-Phase-1 "Wiki - Quick Start - Phase 1" [wiki_quick_start_phase_2]: %5BUser-Guide%5D-Quick-Start-Phase-2 "Wiki - Quick Start - Phase 2" -[wiki_quick_start_phase_3]: %5BUser-Guide%5D-Quick-Start-Phase-3 "Wiki - Quick Start - Phase 3" \ No newline at end of file +[wiki_quick_start_phase_3]: %5BUser-Guide%5D-Quick-Start-Phase-3 "Wiki - Quick Start - Phase 3" diff --git a/docs/wiki/[User-Guide]-Getting-Started.md b/docs/wiki/[User-Guide]-Getting-Started.md index ae92ea07..83e1d461 100644 --- a/docs/wiki/[User-Guide]-Getting-Started.md +++ b/docs/wiki/[User-Guide]-Getting-Started.md @@ -15,4 +15,4 @@ This guidance will be updated in the coming months. [//]: # "INSERT LINK LABELS BELOW" [//]: # "************************" -[wiki_quick_start]: %5BUser-Guide%5D-Quick-Start "Wiki - Quick start" \ No newline at end of file +[wiki_quick_start]: %5BUser-Guide%5D-Quick-Start "Wiki - Quick start" diff --git a/docs/wiki/[User-Guide]-Quick-Start-Phase-1.md b/docs/wiki/[User-Guide]-Quick-Start-Phase-1.md index dee26586..4ac7b879 100644 --- a/docs/wiki/[User-Guide]-Quick-Start-Phase-1.md +++ b/docs/wiki/[User-Guide]-Quick-Start-Phase-1.md @@ -1,173 +1,173 @@ - -Phase 1 of the accelerator is to setup your pre-requisites. Follow the steps below to do that. - -## 1.1 Tools - -You'll need to install the following tools before getting started. - -- PowerShell Core: [Follow the instructions for your operating system](https://learn.microsoft.com/en-us/powershell/scripting/install/installing-powershell) -- Terraform CLI: [Follow the instructions for your operating system](https://developer.hashicorp.com/terraform/downloads) -- Azure CLI: [Follow the instructions for your operating system](https://learn.microsoft.com/en-us/cli/azure/install-azure-cli) -- Git: [Follow the instructions for your operating system](https://git-scm.com/downloads) - -[!NOTE] -In all cases, ensure that the tools are available from a PowerShell core (pwsh) terminal. You may need to add them to your environment path if they are not. - -## 1.2 Azure Subscriptions - -We recommend setting up 3 subscriptions for Azure landing zones. These are management, identity and networking. You can read more about this in the [Landing Zone docs](https://learn.microsoft.com/en-us/azure/cloud-adoption-framework/ready/landing-zone/deploy-landing-zones-with-terraform). - -To create the subscriptions you will need access to a billing agreement. The following links detail the permissions required for each type of agreement: - -- [Enterprise Agreement (EA)](https://learn.microsoft.com/en-us/azure/cost-management-billing/manage/create-enterprise-subscription) -- [Microsoft Customer Agreement (MCA)](https://learn.microsoft.com/en-us/azure/cost-management-billing/manage/create-subscription) - -Once you have the access required, create three subscriptions following your desired naming convention with the following purposes: - -- management -- identity -- networking - -Take note of the subscription id of each subscription as we'll need them later. - -## 1.3 Azure Credentials - -You need an Azure User or Service Principal with the following permissions to run the bootstrap: - -- `Management Group Contributor` on you root management groups (usually called `Tenant Root Group`) -- `Owner` on your Azure landing zone subscriptions - -For simplicity we recommend using a User account since this is a one off proceess that you are unlikely to repeat. - -### 1.3.1 Azure Permissions - -It is likely that if you were able to create the subscriptions you already have the level of access required for a user account, however you should follow these steps to validate them. - -If your preference is to run the bootstrap in the context of a Service Principal, follow these steps to create one: - -#### 1.3.1.1 Create Service Principal (Skip this if using a User account) - -1. Navigate to the [Azure Portal](https://portal.azure.com) and sign in to your tenant. -1. Search for `Azure Active Directory` and open it. -1. Copy the `Tenant ID` field and save it somewhere safe, making a note it is the `ARM_TENANT_ID`. -1. Click `App registrations` in the left navigation. -1. Click `+ New registration`. -1. Choose a name (SPN) that you will remember and make a note of it, we recommend using `sp-alz-boostrap`. -1. Type the chosen name into the `Name` field. -1. Leave the other settings as default and click `Register`. -1. Wait for it to be created. -1. Copy the `Application (client) ID` field and save it somewhere safe, making a note it is the `ARM_CLIENT_ID`. -1. Click `Certificates & secrets` in the left navigation. -1. Ensure the `Client secrets` tab is selected and click `+ New client secret`. -1. Enter `ALZ Bootstrap` in the `Description` field. -1. Change the `Expires` field, choose `Custom`. -1. Set the `Start` field to todays date. -1. Set the `End` field to tomorrows date. -1. Click `Add`. -1. Copy the `Value` field save it somewhere safe, making a note that it is the `ARM_CLIENT_SECRET`. - -#### 1.3.1.2 Create Permissions - -1. The service principal name (SPN) is the username of the User account or the name of the app registration you c reated. -1. Search for `Subscriptions` and click to navigate to the subscription view. -1. For each of the subscriptions you created in the previous step: - 1. Navigate to the subscription. - 1. Click `Access control (IAM)` in the left navigation. - 1. Click `+ Add` and choose `Add role assignment`. - 1. Choose the `Priviledged administrator roles` tab. - 1. Click `Owner` to highlight the row and then click `Next`. - 1. Leave the `User, group or service principal` option checked. - 1. Click `+ Select Members` and search for your SPN in the search box on the right. - 1. Click on your User to highlight it and then click `Select`. - 1. Click `Review + assign`, then click `Review + assign` again when the warning appears. - 1. Wait for the role to be assinged and move onto the next subscription. -1. Search for `Management Groups` and click to navigate to the management groups view. -1. Click the `Tenant Root Group` management group (Note, it is possible someone changed the name of your root management group, select the one at the very top of the hierarchy if that is the case) -1. Click `Access control (IAM)` in the left navigation. -1. Click `+ Add` and choose `Add role assignment`. -1. Remain on the `Job function roles` tab. -1. Search for `Management Group Contributor` and click the row to highlight that role. -1. Click `Next`. -1. Leave the `User, group or service principal` option checked. -1. Click `+ Select Members` and search for your SPN in the search box on the right. -1. Click on your User to highlight it and then click `Select`. -1. Click `Review + assign`, then click `Review + assign` again when the warning appears. -1. Wait for the role to be assinged and you are done with this part. - -## 1.4 Login / Set Credentials - -Follow these steps to login as a User or user Service Princiapl credentials: - -### 1.4.1 User Login - -1. Open a new PowerShell Core (pwsh) terminal. -1. Run `az login`. -1. You'll be redirected to a browser to login, perform MFA, etc. -1. Find the subscription id of the management subscription you made a note of earlier. -1. Type `az account set --subscription ""` and hit enter. -1. Type `az account show` and verify that you are connected to the management subscription. - -### 1.4.2 Service Principal Credentials - -1. Open a new PowerShell Core (pwsh) terminal. -1. Find the `ARM_TENANT_ID` you made a note of earlier. -1. Type `$env:ARM_TENANT_ID=""` and hit enter. -1. Find the `ARM_CLIENT_ID` you made a note of earlier. -1. Type `$env:ARM_CLIENT_ID=""` and hit enter. -1. Find the `ARM_CLIENT_SECRET` you made a note of earlier. -1. Type `$env:ARM_CLIENT_SECRET=""` and hit enter. -1. Find the subscription id of the manangement subscription you made a note of earlier. -1. Type `$env:ARM_SUBSCRIPTION_ID=""` and hit enter. - -[!NOTE] -If you close your PowerShell prompt prior to running the bootstrap, you need to re-enter these environment variables. - -## 1.5 Version Control System Personal Access Token (PAT) - -You'll need to decide whether you are using GitHub or Azure DevOps and follow the instructions below to generate a PAT: - -### 1.5.1 Azure DevOps - -1. Navigate to [dev.azure.com](https://dev.azure.com) and sign in to your organization. -1. Ensure you navigate to the organization you want to deploy to. -1. Click the `User settings` icon in the top right and select `Personal access tokens`. -1. Click `+ New Token`. -1. Enter `Azure Landing Zone Terraform Accelerator` in the `Name` field. -1. Alter the `Expiration` drop down and select `Custom defined`. -1. Choose tommorrows date in the date picker. -1. Click the `Show all scopes` link at the bottom. -1. Check the following scopes: - 1. `Agent Pools`: `Read & manage` - 1. `Build`: `Read & execute` - 1. `Code`: `Full` - 1. `Environment`: `Read & manage` - 1. `Graph`: `Read & manage` - 1. `Pipeline Resources`: `Use & manage` - 1. `Project and Team`: `Read, write & manage` - 1. `Service Connections`: `Read, write & manage` - 1. `Variable Groups`: `Read, create & manage` -1. Click `Create`. -1. Copy the token and save it somewhere safe. -1. Click `Close`. - -### 1.5.2 GitHub - -1. Navigate to [github.com](https://github.com). -1. Click on your user icon in the top right and select `Settings`. -1. Scroll down and click on `Developer Settings` in the left navigation. -1. Click `Personal access tokens` in the left navigation and select `Tokens (classic)`. -1. Click `Generate new token` at the top and select `Generate new token (classic)`. -1. Enter `Azure Landing Zone Terraform Accelerator` in the `Note` field. -1. Alter the `Expiration` drop down and select `Custom`. -1. Choose tommorrows date in the date picker. -1. Check the following scopes: - 1. `repo` - 1. `workflow` - 1. `admin:org`: `write:org` - 1. `user`: `read:user` - 1. `user`: `user:email` - 1. `delete_repo` -1. Click `Generate token`. -1. Copy the token and save it somewhere safe. -1. If your organization uses single sign on, then click the `Configure SSO` link next to your new PAT. -1. Select your organization and click `Authorize`, then follow the prompts to allow SSO. + +Phase 1 of the accelerator is to setup your pre-requisites. Follow the steps below to do that. + +## 1.1 Tools + +You'll need to install the following tools before getting started. + +- PowerShell Core: [Follow the instructions for your operating system](https://learn.microsoft.com/en-us/powershell/scripting/install/installing-powershell) +- Terraform CLI: [Follow the instructions for your operating system](https://developer.hashicorp.com/terraform/downloads) +- Azure CLI: [Follow the instructions for your operating system](https://learn.microsoft.com/en-us/cli/azure/install-azure-cli) +- Git: [Follow the instructions for your operating system](https://git-scm.com/downloads) + +[!NOTE] +In all cases, ensure that the tools are available from a PowerShell core (pwsh) terminal. You may need to add them to your environment path if they are not. + +## 1.2 Azure Subscriptions + +We recommend setting up 3 subscriptions for Azure landing zones. These are management, identity and networking. You can read more about this in the [Landing Zone docs](https://learn.microsoft.com/en-us/azure/cloud-adoption-framework/ready/landing-zone/deploy-landing-zones-with-terraform). + +To create the subscriptions you will need access to a billing agreement. The following links detail the permissions required for each type of agreement: + +- [Enterprise Agreement (EA)](https://learn.microsoft.com/en-us/azure/cost-management-billing/manage/create-enterprise-subscription) +- [Microsoft Customer Agreement (MCA)](https://learn.microsoft.com/en-us/azure/cost-management-billing/manage/create-subscription) + +Once you have the access required, create three subscriptions following your desired naming convention with the following purposes: + +- management +- identity +- networking + +Take note of the subscription id of each subscription as we'll need them later. + +## 1.3 Azure Credentials + +You need an Azure User or Service Principal with the following permissions to run the bootstrap: + +- `Management Group Contributor` on you root management groups (usually called `Tenant Root Group`) +- `Owner` on your Azure landing zone subscriptions + +For simplicity we recommend using a User account since this is a one off proceess that you are unlikely to repeat. + +### 1.3.1 Azure Permissions + +It is likely that if you were able to create the subscriptions you already have the level of access required for a user account, however you should follow these steps to validate them. + +If your preference is to run the bootstrap in the context of a Service Principal, follow these steps to create one: + +#### 1.3.1.1 Create Service Principal (Skip this if using a User account) + +1. Navigate to the [Azure Portal](https://portal.azure.com) and sign in to your tenant. +1. Search for `Azure Active Directory` and open it. +1. Copy the `Tenant ID` field and save it somewhere safe, making a note it is the `ARM_TENANT_ID`. +1. Click `App registrations` in the left navigation. +1. Click `+ New registration`. +1. Choose a name (SPN) that you will remember and make a note of it, we recommend using `sp-alz-boostrap`. +1. Type the chosen name into the `Name` field. +1. Leave the other settings as default and click `Register`. +1. Wait for it to be created. +1. Copy the `Application (client) ID` field and save it somewhere safe, making a note it is the `ARM_CLIENT_ID`. +1. Click `Certificates & secrets` in the left navigation. +1. Ensure the `Client secrets` tab is selected and click `+ New client secret`. +1. Enter `ALZ Bootstrap` in the `Description` field. +1. Change the `Expires` field, choose `Custom`. +1. Set the `Start` field to todays date. +1. Set the `End` field to tomorrows date. +1. Click `Add`. +1. Copy the `Value` field save it somewhere safe, making a note that it is the `ARM_CLIENT_SECRET`. + +#### 1.3.1.2 Create Permissions + +1. The service principal name (SPN) is the username of the User account or the name of the app registration you c reated. +1. Search for `Subscriptions` and click to navigate to the subscription view. +1. For each of the subscriptions you created in the previous step: + 1. Navigate to the subscription. + 1. Click `Access control (IAM)` in the left navigation. + 1. Click `+ Add` and choose `Add role assignment`. + 1. Choose the `Priviledged administrator roles` tab. + 1. Click `Owner` to highlight the row and then click `Next`. + 1. Leave the `User, group or service principal` option checked. + 1. Click `+ Select Members` and search for your SPN in the search box on the right. + 1. Click on your User to highlight it and then click `Select`. + 1. Click `Review + assign`, then click `Review + assign` again when the warning appears. + 1. Wait for the role to be assinged and move onto the next subscription. +1. Search for `Management Groups` and click to navigate to the management groups view. +1. Click the `Tenant Root Group` management group (Note, it is possible someone changed the name of your root management group, select the one at the very top of the hierarchy if that is the case) +1. Click `Access control (IAM)` in the left navigation. +1. Click `+ Add` and choose `Add role assignment`. +1. Remain on the `Job function roles` tab. +1. Search for `Management Group Contributor` and click the row to highlight that role. +1. Click `Next`. +1. Leave the `User, group or service principal` option checked. +1. Click `+ Select Members` and search for your SPN in the search box on the right. +1. Click on your User to highlight it and then click `Select`. +1. Click `Review + assign`, then click `Review + assign` again when the warning appears. +1. Wait for the role to be assinged and you are done with this part. + +## 1.4 Login / Set Credentials + +Follow these steps to login as a User or user Service Princiapl credentials: + +### 1.4.1 User Login + +1. Open a new PowerShell Core (pwsh) terminal. +1. Run `az login`. +1. You'll be redirected to a browser to login, perform MFA, etc. +1. Find the subscription id of the management subscription you made a note of earlier. +1. Type `az account set --subscription ""` and hit enter. +1. Type `az account show` and verify that you are connected to the management subscription. + +### 1.4.2 Service Principal Credentials + +1. Open a new PowerShell Core (pwsh) terminal. +1. Find the `ARM_TENANT_ID` you made a note of earlier. +1. Type `$env:ARM_TENANT_ID=""` and hit enter. +1. Find the `ARM_CLIENT_ID` you made a note of earlier. +1. Type `$env:ARM_CLIENT_ID=""` and hit enter. +1. Find the `ARM_CLIENT_SECRET` you made a note of earlier. +1. Type `$env:ARM_CLIENT_SECRET=""` and hit enter. +1. Find the subscription id of the manangement subscription you made a note of earlier. +1. Type `$env:ARM_SUBSCRIPTION_ID=""` and hit enter. + +[!NOTE] +If you close your PowerShell prompt prior to running the bootstrap, you need to re-enter these environment variables. + +## 1.5 Version Control System Personal Access Token (PAT) + +You'll need to decide whether you are using GitHub or Azure DevOps and follow the instructions below to generate a PAT: + +### 1.5.1 Azure DevOps + +1. Navigate to [dev.azure.com](https://dev.azure.com) and sign in to your organization. +1. Ensure you navigate to the organization you want to deploy to. +1. Click the `User settings` icon in the top right and select `Personal access tokens`. +1. Click `+ New Token`. +1. Enter `Azure Landing Zone Terraform Accelerator` in the `Name` field. +1. Alter the `Expiration` drop down and select `Custom defined`. +1. Choose tommorrows date in the date picker. +1. Click the `Show all scopes` link at the bottom. +1. Check the following scopes: + 1. `Agent Pools`: `Read & manage` + 1. `Build`: `Read & execute` + 1. `Code`: `Full` + 1. `Environment`: `Read & manage` + 1. `Graph`: `Read & manage` + 1. `Pipeline Resources`: `Use & manage` + 1. `Project and Team`: `Read, write & manage` + 1. `Service Connections`: `Read, write & manage` + 1. `Variable Groups`: `Read, create & manage` +1. Click `Create`. +1. Copy the token and save it somewhere safe. +1. Click `Close`. + +### 1.5.2 GitHub + +1. Navigate to [github.com](https://github.com). +1. Click on your user icon in the top right and select `Settings`. +1. Scroll down and click on `Developer Settings` in the left navigation. +1. Click `Personal access tokens` in the left navigation and select `Tokens (classic)`. +1. Click `Generate new token` at the top and select `Generate new token (classic)`. +1. Enter `Azure Landing Zone Terraform Accelerator` in the `Note` field. +1. Alter the `Expiration` drop down and select `Custom`. +1. Choose tommorrows date in the date picker. +1. Check the following scopes: + 1. `repo` + 1. `workflow` + 1. `admin:org`: `write:org` + 1. `user`: `read:user` + 1. `user`: `user:email` + 1. `delete_repo` +1. Click `Generate token`. +1. Copy the token and save it somewhere safe. +1. If your organization uses single sign on, then click the `Configure SSO` link next to your new PAT. +1. Select your organization and click `Authorize`, then follow the prompts to allow SSO. diff --git a/docs/wiki/[User-Guide]-Quick-Start-Phase-2.md b/docs/wiki/[User-Guide]-Quick-Start-Phase-2.md index 3906ce6a..44a9b1d2 100644 --- a/docs/wiki/[User-Guide]-Quick-Start-Phase-2.md +++ b/docs/wiki/[User-Guide]-Quick-Start-Phase-2.md @@ -1,65 +1,65 @@ - -Phase 2 of the accelerator is to run the boostrap. Follow the steps below to do that. - -## 2.1 Install the ALZ PowerShell module - -1. In your PowerShell Core (pwsh) terminal type `Install-Module -Name ALZ`. -1. The module should download and install the latest version. - -## 2.2 Run the Bootstrap - -You are now ready to run the boostrap and setup your environment. If you want to use custom names for your resources, please refer to our [FAQs](https://github.com/Azure/alz-terraform-accelerator/wiki/Frequently-Asked-Questions) section. - -The inputs differ depending on the VCS you have chosen: - -### 2.2.1 Azure DevOps - -1. In your PowerShell Core (pwsh) terminal type `New-ALZEnvironment -IaC "terraform" -Cicd "azuredevops"`. -1. The module will download the latest accelerator and then prompt you for inputs. -1. Fill out the following inputs: - 1. `starter_module`: This is the choice of [Starter Modules][wiki_starter_modules], which is the baseline configuration you want for your Azure landing zone. This also determine the second set of input you'll be prompted for here. - 1. `version_control_system_access_token`: Enter the Azure DevOps PAT you generated in a previous step. - 1. `version_control_system_organization`: Enter the name of your Azure DevOps organization. - 1. `azure_location`: Enter the Azure region where you would like to deploy the storage account and identity for your continuous delivery pipeline. This field expects the `name` of the region, such as `uksouth`. You can find a full list of names by running `az account list-locations -o table`. - 1. `service_name`: This is used to build up the names of your Azure and Azure DevOps resources, for example `rg--mgmt-uksouth-001`. We recommend using `alz` for this. - 1. `environment_name`: This is used to build up the names of your Azure and Azure DevOps resources, for example `rg-alz--uksouth-001`. We recommend using `mgmt` for this. - 1. `postfix_number`: This is used to build up the names of your Azure and Azure DevOps resources, for example `rg-alz-mgmt-uksouth-`. We recommend using `1` for this. - 1. `azure_devops_use_organisation_legacy_url`: If you have not migrated to the modern url (still using `https://.visualstudio.com`) for your Azure DevOps organisation, then set this to `true`. - 1. `azure_devops_create_project`: If you have an existing project you want to use rather than creating a new one, select `true`. We recommend creating a new project to ensure it is isolated by a strong security boundary. - 1. `azure_devops_project_name`: Enter the name of the Azure DevOps project to create or the name of an existing poroject if you set `azure_devops_create_project` to `false`. - 1. `azure_devops_authentication_scheme`: Enter the authentication scheme that your pipeline will use to authenticate to Azure. [WorkloadIdentityFederation](https://learn.microsoft.com/en-us/azure/devops/pipelines/library/connect-to-azure?view=azure-devops#create-an-azure-resource-manager-service-connection-using-workload-identity-federation) uses OpenId Connect and is the recommended approach. [ManagedServiceIdentity](https://learn.microsoft.com/en-us/azure/devops/pipelines/library/connect-to-azure?view=azure-devops#create-an-azure-resource-manager-service-connection-to-a-vm-with-a-managed-service-identity) requires the deployment of self-shoted agents are part of the bootstrap setup. - 1. `apply_approvers`: This is a list of service principal names (SPN) of people you wish to be in the group that approves apply of the Azure landing zone module. This is a comma-separated list like `abc@xyz.com,def@xyz.com,ghi@xyz.com`. You may need to check what the SPN is prior to filling this out as it can vary based on identity provider. - 1. `root_management_group_display_name`: The is the name of the root management group that you applied permissions to in a previous step. This defaults to `Tenant Root Group`, but if you organization has changed it you'll need to enter the new display name. -1. You will now see a green message telling you that the next section is specigic to the starter module you choose. Navigate to the documentation for the relevant starter module to get details of the specific inputs. -1. Once you have entered the starter module input, you see that a Terraform `init` and `apply` happen. -1. There will be a pause after the `plan` phase you allow you to validate what is going to be deployed. -1. If you are happy with the plan, then type `yes` and hit enter. -1. The Terraform will `apply` and your environment will be bootstrapped. - -### 2.2.2 GitHub - -1. In your PowerShell Core (pwsh) terminal type `New-ALZEnvironment -IaC "terraform" -Cicd "github"`. -1. The module will download the latest accelerator and then prompt you for inputs. -1. Fill out the following inputs: - 1. `starter_module`: This is the choice of [Starter Module](), which is the baseline configuration you want for your Azure landing zone. This also determine the second set of input you'll be prompted for here. - 1. `version_control_system_access_token`: Enter the GitHub PAT you generated in a previous step. - 1. `version_control_system_organization`: Enter the name of your GitHub organization. - 1. `azure_location`: Enter the Azure region where you would like to deploy the storage account and identity for your continuous delivery pipeline. This field expects the `name` of the region, such as `uksouth`. You can find a full list of names by running `az account list-locations -o table`. - 1. `service_name`: This is used to build up the names of your Azure and GitHub resources, for example `rg--mgmt-uksouth-001`. We recommend using `alz` for this. - 1. `environment_name`: This is used to build up the names of your Azure and GitHub resources, for example `rg-alz--uksouth-001`. We recommend using `mgmt` for this. - 1. `postfix_number`: This is used to build up the names of your Azure and GitHub resources, for example `rg-alz-mgmt-uksouth-`. We recommend using `1` for this. - 1. `apply_approvers`: This is a list of service principal names (SPN) of people you wish to be in the group that approves apply of the Azure landing zone module. This is a comma-separated list like `abc@xyz.com,def@xyz.com,ghi@xyz.com`. You may need to check what the SPN is prior to filling this out as it can vary based on identity provider. - 1. `repository_visibility`: This determines whether the repository is `public` or `private`. We recommend you choose `private`, but if you are testing and don't have a licensed GitHub organization, you will need to choose `public` or the boostrapping will fail due to missing functionality. - 1. `root_management_group_display_name`: The is the name of the root management group that you applied permissions to in a previous step. This defaults to `Tenant Root Group`, but if you organization has changed it you'll need to enter the new display name. -1. You will now see a green message telling you that the next section is specigic to the starter module you choose. Navigate to the documentation for the relevant starter module to get details of the specific inputs. -1. Once you have entered the starter module input, you see that a Terraform `init` and `apply` happen. -1. There will be a pause after the `plan` phase you allow you to validate what is going to be deployed. -1. If you are happy with the plan, then type `yes` and hit enter. -1. The Terraform will `apply` and your environment will be bootstrapped. - - - [//]: # (************************) - [//]: # (INSERT LINK LABELS BELOW) - [//]: # (************************) - -[wiki_starter_modules]: %5BUser-Guide%5D-Starter-Modules "Wiki - Starter Modules" \ No newline at end of file + +Phase 2 of the accelerator is to run the boostrap. Follow the steps below to do that. + +## 2.1 Install the ALZ PowerShell module + +1. In your PowerShell Core (pwsh) terminal type `Install-Module -Name ALZ`. +1. The module should download and install the latest version. + +## 2.2 Run the Bootstrap + +You are now ready to run the boostrap and setup your environment. If you want to use custom names for your resources, please refer to our [FAQs](https://github.com/Azure/alz-terraform-accelerator/wiki/Frequently-Asked-Questions) section. + +The inputs differ depending on the VCS you have chosen: + +### 2.2.1 Azure DevOps + +1. In your PowerShell Core (pwsh) terminal type `New-ALZEnvironment -IaC "terraform" -Cicd "azuredevops"`. +1. The module will download the latest accelerator and then prompt you for inputs. +1. Fill out the following inputs: + 1. `starter_module`: This is the choice of [Starter Modules][wiki_starter_modules], which is the baseline configuration you want for your Azure landing zone. This also determine the second set of input you'll be prompted for here. + 1. `version_control_system_access_token`: Enter the Azure DevOps PAT you generated in a previous step. + 1. `version_control_system_organization`: Enter the name of your Azure DevOps organization. + 1. `azure_location`: Enter the Azure region where you would like to deploy the storage account and identity for your continuous delivery pipeline. This field expects the `name` of the region, such as `uksouth`. You can find a full list of names by running `az account list-locations -o table`. + 1. `service_name`: This is used to build up the names of your Azure and Azure DevOps resources, for example `rg--mgmt-uksouth-001`. We recommend using `alz` for this. + 1. `environment_name`: This is used to build up the names of your Azure and Azure DevOps resources, for example `rg-alz--uksouth-001`. We recommend using `mgmt` for this. + 1. `postfix_number`: This is used to build up the names of your Azure and Azure DevOps resources, for example `rg-alz-mgmt-uksouth-`. We recommend using `1` for this. + 1. `azure_devops_use_organisation_legacy_url`: If you have not migrated to the modern url (still using `https://.visualstudio.com`) for your Azure DevOps organisation, then set this to `true`. + 1. `azure_devops_create_project`: If you have an existing project you want to use rather than creating a new one, select `true`. We recommend creating a new project to ensure it is isolated by a strong security boundary. + 1. `azure_devops_project_name`: Enter the name of the Azure DevOps project to create or the name of an existing poroject if you set `azure_devops_create_project` to `false`. + 1. `azure_devops_authentication_scheme`: Enter the authentication scheme that your pipeline will use to authenticate to Azure. `WorkloadIdentityFederation` uses OpenId Connect and is the recommended approach. `ManagedServiceIdentity` requires the deployment of self-hosted agents are part of the bootstrap setup. + 1. `apply_approvers`: This is a list of service principal names (SPN) of people you wish to be in the group that approves apply of the Azure landing zone module. This is a comma-separated list like `abc@xyz.com,def@xyz.com,ghi@xyz.com`. You may need to check what the SPN is prior to filling this out as it can vary based on identity provider. + 1. `root_management_group_display_name`: The is the name of the root management group that you applied permissions to in a previous step. This defaults to `Tenant Root Group`, but if you organization has changed it you'll need to enter the new display name. +1. You will now see a green message telling you that the next section is specigic to the starter module you choose. Navigate to the documentation for the relevant starter module to get details of the specific inputs. +1. Once you have entered the starter module input, you see that a Terraform `init` and `apply` happen. +1. There will be a pause after the `plan` phase you allow you to validate what is going to be deployed. +1. If you are happy with the plan, then type `yes` and hit enter. +1. The Terraform will `apply` and your environment will be bootstrapped. + +### 2.2.2 GitHub + +1. In your PowerShell Core (pwsh) terminal type `New-ALZEnvironment -IaC "terraform" -Cicd "github"`. +1. The module will download the latest accelerator and then prompt you for inputs. +1. Fill out the following inputs: + 1. `starter_module`: This is the choice of [Starter Module][wiki_starter_modules], which is the baseline configuration you want for your Azure landing zone. This also determine the second set of input you'll be prompted for here. + 1. `version_control_system_access_token`: Enter the GitHub PAT you generated in a previous step. + 1. `version_control_system_organization`: Enter the name of your GitHub organization. + 1. `azure_location`: Enter the Azure region where you would like to deploy the storage account and identity for your continuous delivery pipeline. This field expects the `name` of the region, such as `uksouth`. You can find a full list of names by running `az account list-locations -o table`. + 1. `service_name`: This is used to build up the names of your Azure and GitHub resources, for example `rg--mgmt-uksouth-001`. We recommend using `alz` for this. + 1. `environment_name`: This is used to build up the names of your Azure and GitHub resources, for example `rg-alz--uksouth-001`. We recommend using `mgmt` for this. + 1. `postfix_number`: This is used to build up the names of your Azure and GitHub resources, for example `rg-alz-mgmt-uksouth-`. We recommend using `1` for this. + 1. `apply_approvers`: This is a list of service principal names (SPN) of people you wish to be in the group that approves apply of the Azure landing zone module. This is a comma-separated list like `abc@xyz.com,def@xyz.com,ghi@xyz.com`. You may need to check what the SPN is prior to filling this out as it can vary based on identity provider. + 1. `repository_visibility`: This determines whether the repository is `public` or `private`. We recommend you choose `private`, but if you are testing and don't have a licensed GitHub organization, you will need to choose `public` or the boostrapping will fail due to missing functionality. + 1. `root_management_group_display_name`: The is the name of the root management group that you applied permissions to in a previous step. This defaults to `Tenant Root Group`, but if you organization has changed it you'll need to enter the new display name. +1. You will now see a green message telling you that the next section is specigic to the starter module you choose. Navigate to the documentation for the relevant starter module to get details of the specific inputs. +1. Once you have entered the starter module input, you see that a Terraform `init` and `apply` happen. +1. There will be a pause after the `plan` phase you allow you to validate what is going to be deployed. +1. If you are happy with the plan, then type `yes` and hit enter. +1. The Terraform will `apply` and your environment will be bootstrapped. + + + [//]: # (************************) + [//]: # (INSERT LINK LABELS BELOW) + [//]: # (************************) + +[wiki_starter_modules]: %5BUser-Guide%5D-Starter-Modules "Wiki - Starter Modules" diff --git a/docs/wiki/[User-Guide]-Quick-Start-Phase-3.md b/docs/wiki/[User-Guide]-Quick-Start-Phase-3.md index 2cea0080..68ed3fea 100644 --- a/docs/wiki/[User-Guide]-Quick-Start-Phase-3.md +++ b/docs/wiki/[User-Guide]-Quick-Start-Phase-3.md @@ -1,29 +1,29 @@ - -Phase 3 of the accelerator is to run pipeline. Follow the steps below to do that. - -## 3.1 Deploy the Landing Zone - -Now you have created your boostrapped environment you can deploy you Azure landing zone by triggering the continuous delivery pipeline in your version control system. - -### 3.1.1 Azure DevOps - -1. Navigate to [dev.azure.com](https://dev.azure.com) and sign in to your organization. -1. Navigate to your project. -1. Click `Pipelines` in the left navigation. -1. Click the `Azure Landing Zone Continuous Delivery` pipeline. -1. Click `Run pipeline` in the top right. -1. Take the defaults and click `Run`. -1. Your pipeline will run a `plan`. -1. If you provided `apply_approvers` to the bootstrap, it will prompt you to approve the `apply` stage. -1. Your pipeline will run an `apply` and deploy an Azure landing zone based on the starter module you choose. - -### 3.1.2 GitHub - -1. Navigate to [github.com](https://github.com). -1. Navigate to your repository. -1. Click `Actions` in the top navigation. -1. Click the `Azure Landing Zone Continuous Delivery` pipeline in the left navigation. -1. Click `Run workflow` in the top right, then keep the default branch and click `Run workflow`. -1. Your pipeline will run a `plan`. -1. If you provided `apply_approvers` to the bootstrap, it will prompt you to approve the `apply` job. -1. Your pipeline will run an `apply` and deploy an Azure landing zone based on the starter module you choose. \ No newline at end of file + +Phase 3 of the accelerator is to run pipeline. Follow the steps below to do that. + +## 3.1 Deploy the Landing Zone + +Now you have created your boostrapped environment you can deploy you Azure landing zone by triggering the continuous delivery pipeline in your version control system. + +### 3.1.1 Azure DevOps + +1. Navigate to [dev.azure.com](https://dev.azure.com) and sign in to your organization. +1. Navigate to your project. +1. Click `Pipelines` in the left navigation. +1. Click the `Azure Landing Zone Continuous Delivery` pipeline. +1. Click `Run pipeline` in the top right. +1. Take the defaults and click `Run`. +1. Your pipeline will run a `plan`. +1. If you provided `apply_approvers` to the bootstrap, it will prompt you to approve the `apply` stage. +1. Your pipeline will run an `apply` and deploy an Azure landing zone based on the starter module you choose. + +### 3.1.2 GitHub + +1. Navigate to [github.com](https://github.com). +1. Navigate to your repository. +1. Click `Actions` in the top navigation. +1. Click the `Azure Landing Zone Continuous Delivery` pipeline in the left navigation. +1. Click `Run workflow` in the top right, then keep the default branch and click `Run workflow`. +1. Your pipeline will run a `plan`. +1. If you provided `apply_approvers` to the bootstrap, it will prompt you to approve the `apply` job. +1. Your pipeline will run an `apply` and deploy an Azure landing zone based on the starter module you choose. diff --git a/docs/wiki/[User-Guide]-Quick-Start.md b/docs/wiki/[User-Guide]-Quick-Start.md index e2815d2d..7db6d079 100644 --- a/docs/wiki/[User-Guide]-Quick-Start.md +++ b/docs/wiki/[User-Guide]-Quick-Start.md @@ -25,4 +25,4 @@ The accelerator follows a 3 phase approach: [wiki_quick_start_phase_1]: %5BUser-Guide%5D-Quick-Start-Phase-1 "Wiki - Quick Start - Phase 1" [wiki_quick_start_phase_2]: %5BUser-Guide%5D-Quick-Start-Phase-2 "Wiki - Quick Start - Phase 2" -[wiki_quick_start_phase_3]: %5BUser-Guide%5D-Quick-Start-Phase-3 "Wiki - Quick Start - Phase 3" \ No newline at end of file +[wiki_quick_start_phase_3]: %5BUser-Guide%5D-Quick-Start-Phase-3 "Wiki - Quick Start - Phase 3" diff --git a/docs/wiki/[User-Guide]-Starter-Module-Basic.md b/docs/wiki/[User-Guide]-Starter-Module-Basic.md index 31c86fd5..30dcd4b8 100644 --- a/docs/wiki/[User-Guide]-Starter-Module-Basic.md +++ b/docs/wiki/[User-Guide]-Starter-Module-Basic.md @@ -1,12 +1,12 @@ - - -The `basic` starter module creates a management group hierarchy and assigns policies. - -## Inputs - -- `default_location`: The location for Azure resources (e.g 'uksouth'). -- `subscription_id_connectivity`: The identifier of the Connectivity Subscription. -- `subscription_id_identity`: The identifier of the Identity Subscription. -- `subscription_id_management`: The identifier of the Management Subscription. -- `root_id`: The root id is the identity for the root managment group and a prefix applied to all management group identities. -- `root_name`: The display name for the root management group. \ No newline at end of file + + +The `basic` starter module creates a management group hierarchy and assigns policies. + +## Inputs + +- `default_location`: The location for Azure resources (e.g 'uksouth'). +- `subscription_id_connectivity`: The identifier of the Connectivity Subscription. +- `subscription_id_identity`: The identifier of the Identity Subscription. +- `subscription_id_management`: The identifier of the Management Subscription. +- `root_id`: The root id is the identity for the root managment group and a prefix applied to all management group identities. +- `root_name`: The display name for the root management group. diff --git a/docs/wiki/[User-Guide]-Starter-Module-HubNetworking.md b/docs/wiki/[User-Guide]-Starter-Module-HubNetworking.md index 9313085f..8914f523 100644 --- a/docs/wiki/[User-Guide]-Starter-Module-HubNetworking.md +++ b/docs/wiki/[User-Guide]-Starter-Module-HubNetworking.md @@ -1,16 +1,16 @@ - - -The `hubnetworking` starter module creates a management group hierarchy, assigns policies and deploys hub networking resources. - -## Inputs - -- `default_location`: The location for Azure resources (e.g 'uksouth'). -- `subscription_id_connectivity`: The identifier of the Connectivity Subscription. -- `subscription_id_identity`: The identifier of the Identity Subscription. -- `subscription_id_management`: The identifier of the Management Subscription. -- `root_id`: The root id is the identity for the root managment group and a prefix applied to all management group identities. -- `root_name`: The display name for the root management group. -- `hub_virtual_network_address_prefix`: The IP address range for the hub network in CIDR format. -- `firewall_subnet_address_prefix`: The IP address range foe the firewall subnet in CIDR format. -- `gateway_subnet_address_prefix`: The IP address range foe the gatway subnet in CIDR format. -- `virtual_network_gateway_creation_enabled`: Whether the virtual network gateway is created. \ No newline at end of file + + +The `hubnetworking` starter module creates a management group hierarchy, assigns policies and deploys hub networking resources. + +## Inputs + +- `default_location`: The location for Azure resources (e.g 'uksouth'). +- `subscription_id_connectivity`: The identifier of the Connectivity Subscription. +- `subscription_id_identity`: The identifier of the Identity Subscription. +- `subscription_id_management`: The identifier of the Management Subscription. +- `root_id`: The root id is the identity for the root managment group and a prefix applied to all management group identities. +- `root_name`: The display name for the root management group. +- `hub_virtual_network_address_prefix`: The IP address range for the hub network in CIDR format. +- `firewall_subnet_address_prefix`: The IP address range foe the firewall subnet in CIDR format. +- `gateway_subnet_address_prefix`: The IP address range foe the gatway subnet in CIDR format. +- `virtual_network_gateway_creation_enabled`: Whether the virtual network gateway is created. diff --git a/docs/wiki/[User-Guide]-Starter-Modules.md b/docs/wiki/[User-Guide]-Starter-Modules.md index be804fc1..3fae883e 100644 --- a/docs/wiki/[User-Guide]-Starter-Modules.md +++ b/docs/wiki/[User-Guide]-Starter-Modules.md @@ -1,17 +1,17 @@ - - -The Azure landing zones Terraform accelerator includes a number of starter modules that provide opinionated implementations of the [Azure landing zones Terraform module](https://github.com/Azure/terraform-azurerm-caf-enterprise-scale). - -These are called starter modules because the expectation is you'll update these modules as the needs of your organization evolves and you want to add or remove features to your landing zone. - -Each starter module expects different inputs and the following pages detail those inputs. You'll be prompted for these inputs when you run the ALZ PowerShell module. - -- [Basic Starter Module][wiki_starter_module_basic]: Management groups and policies. -- [Hub Networking Starter Module][wiki_starter_module_hubnetworking]: Management groups, policies and hub networking. - - [//]: # (************************) - [//]: # (INSERT LINK LABELS BELOW) - [//]: # (************************) - -[wiki_starter_module_basic]: %5BUser-Guide%5D-Starter-Module-Basic "Wiki - Starter Modules - Basic" -[wiki_starter_module_hubnetworking]: %5BUser-Guide%5D-Starter-Module-HubNetworking "Wiki - Start Modules - Hub Networking" \ No newline at end of file + + +The Azure landing zones Terraform accelerator includes a number of starter modules that provide opinionated implementations of the [Azure landing zones Terraform module](https://github.com/Azure/terraform-azurerm-caf-enterprise-scale). + +These are called starter modules because the expectation is you'll update these modules as the needs of your organization evolves and you want to add or remove features to your landing zone. + +Each starter module expects different inputs and the following pages detail those inputs. You'll be prompted for these inputs when you run the ALZ PowerShell module. + +- [Basic Starter Module][wiki_starter_module_basic]: Management groups and policies. +- [Hub Networking Starter Module][wiki_starter_module_hubnetworking]: Management groups, policies and hub networking. + + [//]: # (************************) + [//]: # (INSERT LINK LABELS BELOW) + [//]: # (************************) + +[wiki_starter_module_basic]: %5BUser-Guide%5D-Starter-Module-Basic "Wiki - Starter Modules - Basic" +[wiki_starter_module_hubnetworking]: %5BUser-Guide%5D-Starter-Module-HubNetworking "Wiki - Start Modules - Hub Networking" diff --git a/docs/wiki/_Sidebar.md b/docs/wiki/_Sidebar.md index 5d2c2cd3..94de3513 100644 --- a/docs/wiki/_Sidebar.md +++ b/docs/wiki/_Sidebar.md @@ -41,4 +41,4 @@ [wiki_raising_an_issue]: Raising-an-Issue "Wiki - Raising an issue" [wiki_feature_requests]: Feature-Requests "Wiki - Feature requests" [wiki_contributing_to_code]: Contributing-to-Code "Wiki - Contributing to code" -[wiki_contributing_to_documentation]: Contributing-to-Documentation "Wiki - Contributing to documentation" \ No newline at end of file +[wiki_contributing_to_documentation]: Contributing-to-Documentation "Wiki - Contributing to documentation" diff --git a/templates/.ci_cd/.azuredevops/cd.yaml b/templates/.ci_cd/.azuredevops/cd.yaml index 5c4199de..aacc9e86 100644 --- a/templates/.ci_cd/.azuredevops/cd.yaml +++ b/templates/.ci_cd/.azuredevops/cd.yaml @@ -1,110 +1,125 @@ -trigger: -- none - -lockBehavior: sequential -stages: -- stage: plan - displayName: Plan - variables: - - group: ${variable_group_name} - jobs: - - deployment: plan - displayName: Plan with Terraform - pool: - ${agent_pool_configuration} - environment: ${environment_name_plan} - strategy: - runOnce: - deploy: - steps: - - checkout: self - displayName: Checkout Terraform Module - - task: TerraformInstaller@0 - displayName: Install Terraform - inputs: - terraformVersion: 'latest' - - task: TerraformTaskV4@4 - displayName: Terraform Init - inputs: - provider: 'azurerm' - command: 'init' - backendServiceArm: '${service_connection_name}' - backendAzureRmResourceGroupName: '$(BACKEND_AZURE_RESOURCE_GROUP_NAME)' - backendAzureRmStorageAccountName: '$(BACKEND_AZURE_STORAGE_ACCOUNT_NAME)' - backendAzureRmContainerName: '$(BACKEND_AZURE_STORAGE_ACCOUNT_CONTAINER_NAME)' - backendAzureRmKey: 'terraform.tfstate' - env: - ARM_USE_AZUREAD: true - - task: TerraformTaskV4@4 - displayName: Terraform Plan - inputs: - provider: 'azurerm' - command: 'plan' - commandOptions: '-out tfplan' - environmentServiceNameAzureRM: '${service_connection_name}' - env: - ARM_USE_AZUREAD: true - - task: CopyFiles@2 - displayName: Create Module Artifact - inputs: - SourceFolder: '$(Build.SourcesDirectory)' - Contents: | - *.tf - *.tfvars - tfplan - TargetFolder: '$(Build.ArtifactsStagingDirectory)' - CleanTargetFolder: true - OverWrite: true - - task: PublishPipelineArtifact@1 - displayName: Publish Module Artifact - inputs: - targetPath: '$(Build.ArtifactsStagingDirectory)' - artifact: 'module' - publishLocation: 'pipeline' -- stage: apply - displayName: Apply - dependsOn: plan - variables: - - group: ${variable_group_name} - jobs: - - deployment: apply - displayName: Apply with Terraform - pool: - ${agent_pool_configuration} - environment: ${environment_name_apply} - strategy: - runOnce: - deploy: - steps: - - download: none - - task: DownloadPipelineArtifact@2 - displayName: Download Module Artifact - inputs: - buildType: 'current' - artifactName: 'module' - targetPath: '$(Build.SourcesDirectory)' - - task: TerraformInstaller@0 - displayName: Install Terraform - inputs: - terraformVersion: 'latest' - - task: TerraformTaskV4@4 - displayName: Terraform Init - inputs: - provider: 'azurerm' - command: 'init' - backendServiceArm: '${service_connection_name}' - backendAzureRmResourceGroupName: '$(BACKEND_AZURE_RESOURCE_GROUP_NAME)' - backendAzureRmStorageAccountName: '$(BACKEND_AZURE_STORAGE_ACCOUNT_NAME)' - backendAzureRmContainerName: '$(BACKEND_AZURE_STORAGE_ACCOUNT_CONTAINER_NAME)' - backendAzureRmKey: 'terraform.tfstate' - env: - ARM_USE_AZUREAD: true - - task: TerraformTaskV4@4 - displayName: Terraform Apply - inputs: - provider: 'azurerm' - command: 'apply' - commandOptions: '-auto-approve tfplan' - environmentServiceNameAzureRM: '${service_connection_name}' - env: - ARM_USE_AZUREAD: true \ No newline at end of file +--- +trigger: + - none + +parameters: + - name: terraform_action + displayName: Terraform Action to perform + type: string + default: 'apply' + values: + - 'apply' + - 'destroy' + +lockBehavior: sequential +stages: + - stage: plan + displayName: Plan + variables: + - group: ${variable_group_name} + jobs: + - deployment: plan + displayName: Plan with Terraform + pool: + ${agent_pool_configuration} + environment: ${environment_name_plan} + strategy: + runOnce: + deploy: + steps: + - checkout: self + displayName: Checkout Terraform Module + - task: TerraformInstaller@0 + displayName: Install Terraform + inputs: + terraformVersion: 'latest' + - task: TerraformTaskV4@4 + displayName: Terraform Init + inputs: + provider: 'azurerm' + command: 'init' + backendServiceArm: '${service_connection_name}' + backendAzureRmResourceGroupName: '$(BACKEND_AZURE_RESOURCE_GROUP_NAME)' + backendAzureRmStorageAccountName: '$(BACKEND_AZURE_STORAGE_ACCOUNT_NAME)' + backendAzureRmContainerName: '$(BACKEND_AZURE_STORAGE_ACCOUNT_CONTAINER_NAME)' + backendAzureRmKey: 'terraform.tfstate' + env: + ARM_USE_AZUREAD: true + - task: TerraformTaskV4@4 + displayName: Terraform Plan for $${{ parameters.terraform_action }} + inputs: + provider: 'azurerm' + command: 'plan' + $${{ if eq(parameters.terraform_action, 'apply') }}: + commandOptions: '-out=tfplan -input=false' + $${{ if eq(parameters.terraform_action, 'destroy') }}: + commandOptions: "-out=tfplan -input=false -destroy" + environmentServiceNameAzureRM: '${service_connection_name}' + env: + ARM_USE_AZUREAD: true + - task: CopyFiles@2 + displayName: Create Module Artifact + inputs: + SourceFolder: '$(Build.SourcesDirectory)' + Contents: | + *.tf + *.tfvars + tfplan + TargetFolder: '$(Build.ArtifactsStagingDirectory)' + CleanTargetFolder: true + OverWrite: true + - task: PublishPipelineArtifact@1 + displayName: Publish Module Artifact + inputs: + targetPath: '$(Build.ArtifactsStagingDirectory)' + artifact: 'module' + publishLocation: 'pipeline' + - pwsh: terraform show tfplan + displayName: Show the Plan for Review + - stage: apply + displayName: Apply + dependsOn: plan + variables: + - group: ${variable_group_name} + jobs: + - deployment: apply + displayName: Apply with Terraform + pool: + ${agent_pool_configuration} + environment: ${environment_name_apply} + strategy: + runOnce: + deploy: + steps: + - download: none + - task: DownloadPipelineArtifact@2 + displayName: Download Module Artifact + inputs: + buildType: 'current' + artifactName: 'module' + targetPath: '$(Build.SourcesDirectory)' + - task: TerraformInstaller@0 + displayName: Install Terraform + inputs: + terraformVersion: 'latest' + - task: TerraformTaskV4@4 + displayName: Terraform Init + inputs: + provider: 'azurerm' + command: 'init' + backendServiceArm: '${service_connection_name}' + backendAzureRmResourceGroupName: '$(BACKEND_AZURE_RESOURCE_GROUP_NAME)' + backendAzureRmStorageAccountName: '$(BACKEND_AZURE_STORAGE_ACCOUNT_NAME)' + backendAzureRmContainerName: '$(BACKEND_AZURE_STORAGE_ACCOUNT_CONTAINER_NAME)' + backendAzureRmKey: 'terraform.tfstate' + env: + ARM_USE_AZUREAD: true + - task: TerraformTaskV4@4 + displayName: Terraform $${{ parameters.terraform_action }} + inputs: + provider: 'azurerm' + command: 'apply' + commandOptions: '-auto-approve tfplan' + environmentServiceNameAzureRM: '${service_connection_name}' + env: + ARM_USE_AZUREAD: true diff --git a/templates/.ci_cd/.azuredevops/ci.yaml b/templates/.ci_cd/.azuredevops/ci.yaml index 06279381..3f05a959 100644 --- a/templates/.ci_cd/.azuredevops/ci.yaml +++ b/templates/.ci_cd/.azuredevops/ci.yaml @@ -1,61 +1,62 @@ -trigger: -- none - -lockBehavior: sequential -stages: -- stage: validate - displayName: Validation Terraform - variables: - - group: ${variable_group_name} - jobs: - - job: validate - displayName: Validate Terraform - pool: - vmImage: ubuntu-latest - steps: - - task: TerraformInstaller@0 - displayName: Install Terraform - inputs: - terraformVersion: 'latest' - - pwsh: terraform fmt -check - displayName: Terraform Format Check - - pwsh: terraform init -backend=false - displayName: Terraform Init - - pwsh: terraform validate - displayName: Terraform Validate - - deployment: plan - dependsOn: validate - displayName: Validate Terraform Plan - pool: - ${agent_pool_configuration} - environment: ${environment_name_plan} - strategy: - runOnce: - deploy: - steps: - - checkout: self - displayName: Checkout Terraform Module - - task: TerraformInstaller@0 - displayName: Install Terraform - inputs: - terraformVersion: 'latest' - - task: TerraformTaskV4@4 - displayName: Terraform Init - inputs: - provider: 'azurerm' - command: 'init' - backendServiceArm: '${service_connection_name}' - backendAzureRmResourceGroupName: '$(BACKEND_AZURE_RESOURCE_GROUP_NAME)' - backendAzureRmStorageAccountName: '$(BACKEND_AZURE_STORAGE_ACCOUNT_NAME)' - backendAzureRmContainerName: '$(BACKEND_AZURE_STORAGE_ACCOUNT_CONTAINER_NAME)' - backendAzureRmKey: 'terraform.tfstate' - env: - ARM_USE_AZUREAD: true - - task: TerraformTaskV4@4 - displayName: Terraform Plan - inputs: - provider: 'azurerm' - command: 'plan' - environmentServiceNameAzureRM: '${service_connection_name}' - env: - ARM_USE_AZUREAD: true \ No newline at end of file +--- +trigger: + - none + +lockBehavior: sequential +stages: + - stage: validate + displayName: Validation Terraform + variables: + - group: ${variable_group_name} + jobs: + - job: validate + displayName: Validate Terraform + pool: + vmImage: ubuntu-latest + steps: + - task: TerraformInstaller@0 + displayName: Install Terraform + inputs: + terraformVersion: 'latest' + - pwsh: terraform fmt -check + displayName: Terraform Format Check + - pwsh: terraform init -backend=false + displayName: Terraform Init + - pwsh: terraform validate + displayName: Terraform Validate + - deployment: plan + dependsOn: validate + displayName: Validate Terraform Plan + pool: + ${agent_pool_configuration} + environment: ${environment_name_plan} + strategy: + runOnce: + deploy: + steps: + - checkout: self + displayName: Checkout Terraform Module + - task: TerraformInstaller@0 + displayName: Install Terraform + inputs: + terraformVersion: 'latest' + - task: TerraformTaskV4@4 + displayName: Terraform Init + inputs: + provider: 'azurerm' + command: 'init' + backendServiceArm: '${service_connection_name}' + backendAzureRmResourceGroupName: '$(BACKEND_AZURE_RESOURCE_GROUP_NAME)' + backendAzureRmStorageAccountName: '$(BACKEND_AZURE_STORAGE_ACCOUNT_NAME)' + backendAzureRmContainerName: '$(BACKEND_AZURE_STORAGE_ACCOUNT_CONTAINER_NAME)' + backendAzureRmKey: 'terraform.tfstate' + env: + ARM_USE_AZUREAD: true + - task: TerraformTaskV4@4 + displayName: Terraform Plan + inputs: + provider: 'azurerm' + command: 'plan' + environmentServiceNameAzureRM: '${service_connection_name}' + env: + ARM_USE_AZUREAD: true diff --git a/templates/.ci_cd/.github/workflows/cd.yaml b/templates/.ci_cd/.github/workflows/cd.yaml index 80102b57..643049bb 100644 --- a/templates/.ci_cd/.github/workflows/cd.yaml +++ b/templates/.ci_cd/.github/workflows/cd.yaml @@ -1,85 +1,100 @@ -name: Azure Landing Zone Continuous Delivery -on: - workflow_dispatch: - -permissions: - id-token: write - contents: read - -jobs: - plan: - name: Plan with Terraform - concurrency: ${environment_name_plan} - environment: ${environment_name_plan} - runs-on: ubuntu-latest - env: - ARM_CLIENT_ID: "$${{ vars.AZURE_CLIENT_ID }}" - ARM_SUBSCRIPTION_ID: "$${{ vars.AZURE_SUBSCRIPTION_ID }}" - ARM_TENANT_ID: "$${{ vars.AZURE_TENANT_ID }}" - ARM_USE_AZUREAD: true - ARM_USE_OIDC: true - - steps: - - name: Checkout Code - uses: actions/checkout@v2.5.0 - - - name: Install Terraform - uses: hashicorp/setup-terraform@v2.0.3 - - - name: Terraform Init - run: | - terraform init \ - -backend-config="resource_group_name=$${{vars.BACKEND_AZURE_RESOURCE_GROUP_NAME}}" \ - -backend-config="storage_account_name=$${{vars.BACKEND_AZURE_STORAGE_ACCOUNT_NAME}}" \ - -backend-config="container_name=$${{vars.BACKEND_AZURE_STORAGE_ACCOUNT_CONTAINER_NAME}}" \ - -backend-config="key=terraform.tfstate" - - - name: Terraform Plan - run: terraform plan -out tfplan -input=false - - - name: Create Module Artifact - run: | - New-Item -Path . -Name "staging" -ItemType "directory" - Copy-Item -Path "./*.tf" -Destination "./staging" - Copy-Item -Path "./*.tfvars" -Destination "./staging" - Copy-Item -Path "./tfplan" -Destination "./staging" - shell: pwsh - - - name: Publish Module Artifact - uses: actions/upload-artifact@v3.1.3 - with: - name: module - path: ./staging/ - - apply: - needs: plan - name: Apply with Terraform - concurrency: ${environment_name_apply} - environment: ${environment_name_apply} - runs-on: ubuntu-latest - env: - ARM_CLIENT_ID: "$${{ vars.AZURE_CLIENT_ID }}" - ARM_SUBSCRIPTION_ID: "$${{ vars.AZURE_SUBSCRIPTION_ID }}" - ARM_TENANT_ID: "$${{ vars.AZURE_TENANT_ID }}" - ARM_USE_AZUREAD: true - ARM_USE_OIDC: true - - steps: - - name: Download a Build Artifact - uses: actions/download-artifact@v2.1.1 - with: - name: module - - - name: Install Terraform - uses: hashicorp/setup-terraform@v2.0.3 - - - name: Terraform Init - run: | - terraform init \ - -backend-config="resource_group_name=$${{vars.BACKEND_AZURE_RESOURCE_GROUP_NAME}}" \ - -backend-config="storage_account_name=$${{vars.BACKEND_AZURE_STORAGE_ACCOUNT_NAME}}" \ - -backend-config="container_name=$${{vars.BACKEND_AZURE_STORAGE_ACCOUNT_CONTAINER_NAME}}" \ - -backend-config="key=terraform.tfstate" - - - name: Terraform Apply - run: terraform apply -input=false -auto-approve tfplan \ No newline at end of file +--- +name: Azure Landing Zone Continuous Delivery +on: + workflow_dispatch: + inputs: + terraform_action: + description: 'Terraform Action to perform' + required: true + default: 'apply' + type: choice + options: + - 'apply' + - 'destroy' + +permissions: + id-token: write + contents: read + +jobs: + plan: + name: Plan with Terraform + concurrency: ${environment_name_plan} + environment: ${environment_name_plan} + runs-on: ubuntu-latest + env: + ARM_CLIENT_ID: "$${{ vars.AZURE_CLIENT_ID }}" + ARM_SUBSCRIPTION_ID: "$${{ vars.AZURE_SUBSCRIPTION_ID }}" + ARM_TENANT_ID: "$${{ vars.AZURE_TENANT_ID }}" + ARM_USE_AZUREAD: true + ARM_USE_OIDC: true + + steps: + - name: Checkout Code + uses: actions/checkout@v4 + + - name: Install Terraform + uses: hashicorp/setup-terraform@v2 + + - name: Terraform Init + run: | + terraform init \ + -backend-config="resource_group_name=$${{vars.BACKEND_AZURE_RESOURCE_GROUP_NAME}}" \ + -backend-config="storage_account_name=$${{vars.BACKEND_AZURE_STORAGE_ACCOUNT_NAME}}" \ + -backend-config="container_name=$${{vars.BACKEND_AZURE_STORAGE_ACCOUNT_CONTAINER_NAME}}" \ + -backend-config="key=terraform.tfstate" + + - name: Terraform Plan for $${{ github.event.inputs.terraform_action }} + run: | + # shellcheck disable=SC2086 + terraform plan -out=tfplan -input=false $${{ github.event.inputs.terraform_action == 'destroy' && '-destroy' || '' }} + + - name: Create Module Artifact + run: | + New-Item -Path . -Name "staging" -ItemType "directory" + Copy-Item -Path "./*.tf" -Destination "./staging" + Copy-Item -Path "./*.tfvars" -Destination "./staging" + Copy-Item -Path "./tfplan" -Destination "./staging" + shell: pwsh + + - name: Publish Module Artifact + uses: actions/upload-artifact@v3 + with: + name: module + path: ./staging/ + + - name: Show the Plan for Review + run: terraform show tfplan + + apply: + needs: plan + name: Apply with Terraform + concurrency: ${environment_name_apply} + environment: ${environment_name_apply} + runs-on: ubuntu-latest + env: + ARM_CLIENT_ID: "$${{ vars.AZURE_CLIENT_ID }}" + ARM_SUBSCRIPTION_ID: "$${{ vars.AZURE_SUBSCRIPTION_ID }}" + ARM_TENANT_ID: "$${{ vars.AZURE_TENANT_ID }}" + ARM_USE_AZUREAD: true + ARM_USE_OIDC: true + + steps: + - name: Download a Build Artifact + uses: actions/download-artifact@v3 + with: + name: module + + - name: Install Terraform + uses: hashicorp/setup-terraform@v2 + + - name: Terraform Init + run: | + terraform init \ + -backend-config="resource_group_name=$${{vars.BACKEND_AZURE_RESOURCE_GROUP_NAME}}" \ + -backend-config="storage_account_name=$${{vars.BACKEND_AZURE_STORAGE_ACCOUNT_NAME}}" \ + -backend-config="container_name=$${{vars.BACKEND_AZURE_STORAGE_ACCOUNT_CONTAINER_NAME}}" \ + -backend-config="key=terraform.tfstate" + + - name: Terraform $${{ github.event.inputs.terraform_action }} + run: terraform apply -input=false -auto-approve tfplan diff --git a/templates/.ci_cd/.github/workflows/ci.yaml b/templates/.ci_cd/.github/workflows/ci.yaml index 66bdf991..c5e9ca0d 100644 --- a/templates/.ci_cd/.github/workflows/ci.yaml +++ b/templates/.ci_cd/.github/workflows/ci.yaml @@ -1,95 +1,96 @@ -name: Azure Landing Zone Continuous Integration -on: - pull_request: - branches: - - main - workflow_dispatch: - -permissions: - id-token: write - contents: read - pull-requests: write - -jobs: - validate: - name: Validate Terraform - runs-on: ubuntu-latest - - steps: - - name: Checkout Code - uses: actions/checkout@v2.5.0 - - - name: Install Terraform - uses: hashicorp/setup-terraform@v2.0.3 - - - name: Terraform Format Check - run: terraform fmt -check - - - name: Terraform Init - run: terraform init -backend=false - - - name: Terraform Validate - run: terraform validate - - plan: - name: Validate Terraform Plan - needs: validate - runs-on: ubuntu-latest - concurrency: ${environment_name_plan} - environment: ${environment_name_plan} - env: - ARM_CLIENT_ID: "$${{ vars.AZURE_CLIENT_ID }}" - ARM_SUBSCRIPTION_ID: "$${{ vars.AZURE_SUBSCRIPTION_ID }}" - ARM_TENANT_ID: "$${{ vars.AZURE_TENANT_ID }}" - ARM_USE_AZUREAD: true - ARM_USE_OIDC: true - steps: - - name: Checkout Code - uses: actions/checkout@v2.5.0 - - - name: Install Terraform - uses: hashicorp/setup-terraform@v2.0.3 - - - name: Terraform Init - run: | - terraform init \ - -backend-config="resource_group_name=$${{vars.BACKEND_AZURE_RESOURCE_GROUP_NAME}}" \ - -backend-config="storage_account_name=$${{vars.BACKEND_AZURE_STORAGE_ACCOUNT_NAME}}" \ - -backend-config="container_name=$${{vars.BACKEND_AZURE_STORAGE_ACCOUNT_CONTAINER_NAME}}" \ - -backend-config="key=terraform.tfstate" - - - name: Terraform Plan - id: plan - run: terraform plan -no-color -input=false - continue-on-error: true - - - name: Update Pull Request - if: github.event_name == 'pull_request' - uses: actions/github-script@v6 - env: - PLAN: "terraform\n$${{ steps.plan.outputs.stdout }}" - with: - github-token: $${{ secrets.GITHUB_TOKEN }} - script: | - const output = `#### Terraform Plan 📖\`$${{ steps.plan.outcome }}\` - -
Show Plan - - \`\`\`\n - $${process.env.PLAN} - \`\`\` - -
- - *Pushed by: @$${{ github.actor }}, Action: \`$${{ github.event_name }}\`*`; - - github.rest.issues.createComment({ - issue_number: context.issue.number, - owner: context.repo.owner, - repo: context.repo.repo, - body: output - }) - - - name: Terraform Plan Status - if: steps.plan.outcome == 'failure' - run: exit 1 \ No newline at end of file +--- +name: Azure Landing Zone Continuous Integration +on: + pull_request: + branches: + - main + workflow_dispatch: + +permissions: + id-token: write + contents: read + pull-requests: write + +jobs: + validate: + name: Validate Terraform + runs-on: ubuntu-latest + + steps: + - name: Checkout Code + uses: actions/checkout@v4 + + - name: Install Terraform + uses: hashicorp/setup-terraform@v2 + + - name: Terraform Format Check + run: terraform fmt -check + + - name: Terraform Init + run: terraform init -backend=false + + - name: Terraform Validate + run: terraform validate + + plan: + name: Validate Terraform Plan + needs: validate + runs-on: ubuntu-latest + concurrency: ${environment_name_plan} + environment: ${environment_name_plan} + env: + ARM_CLIENT_ID: "$${{ vars.AZURE_CLIENT_ID }}" + ARM_SUBSCRIPTION_ID: "$${{ vars.AZURE_SUBSCRIPTION_ID }}" + ARM_TENANT_ID: "$${{ vars.AZURE_TENANT_ID }}" + ARM_USE_AZUREAD: true + ARM_USE_OIDC: true + steps: + - name: Checkout Code + uses: actions/checkout@v4 + + - name: Install Terraform + uses: hashicorp/setup-terraform@v2 + + - name: Terraform Init + run: | + terraform init \ + -backend-config="resource_group_name=$${{vars.BACKEND_AZURE_RESOURCE_GROUP_NAME}}" \ + -backend-config="storage_account_name=$${{vars.BACKEND_AZURE_STORAGE_ACCOUNT_NAME}}" \ + -backend-config="container_name=$${{vars.BACKEND_AZURE_STORAGE_ACCOUNT_CONTAINER_NAME}}" \ + -backend-config="key=terraform.tfstate" + + - name: Terraform Plan + id: plan + run: terraform plan -no-color -input=false + continue-on-error: true + + - name: Update Pull Request + if: github.event_name == 'pull_request' + uses: actions/github-script@v6 + env: + PLAN: "terraform\n$${{ steps.plan.outputs.stdout }}" + with: + github-token: $${{ secrets.GITHUB_TOKEN }} + script: | + const output = `#### Terraform Plan 📖\`$${{ steps.plan.outcome }}\` + +
Show Plan + + \`\`\`\n + $${process.env.PLAN} + \`\`\` + +
+ + *Pushed by: @$${{ github.actor }}, Action: \`$${{ github.event_name }}\`*`; + + github.rest.issues.createComment({ + issue_number: context.issue.number, + owner: context.repo.owner, + repo: context.repo.repo, + body: output + }) + + - name: Terraform Plan Status + if: steps.plan.outcome == 'failure' + run: exit 1 diff --git a/templates/.test/main.tf b/templates/.test/main.tf index a95ebcfd..df00b8a0 100644 --- a/templates/.test/main.tf +++ b/templates/.test/main.tf @@ -1,2 +1,2 @@ -data "azurerm_client_config" "current" {} -data "azurerm_subscription" "current" {} \ No newline at end of file +data "azurerm_client_config" "current" {} +data "azurerm_subscription" "current" {} diff --git a/templates/.test/outputs.tf b/templates/.test/outputs.tf index 363c3c42..f2388a6c 100644 --- a/templates/.test/outputs.tf +++ b/templates/.test/outputs.tf @@ -1,15 +1,43 @@ -output "connection" { - value = data.azurerm_client_config.current -} - -output "subscription" { - value = data.azurerm_subscription.current -} - -output "test_output_01" { - value = var.test_variable_01 -} - -output "test_output_02" { - value = var.test_variable_02 -} \ No newline at end of file +output "connection" { + value = data.azurerm_client_config.current +} + +output "subscription" { + value = data.azurerm_subscription.current +} + +output "test_output_01" { + value = var.test_variable_01 +} + +output "test_output_02" { + value = var.test_variable_02 +} + +output "test_output_03" { + value = var.test_variable_03 +} + +output "test_output_04" { + value = var.test_variable_04 +} + +output "test_output_05" { + value = var.test_variable_05 +} + +output "test_output_06" { + value = var.test_variable_06 +} + +output "subscription_id_connectivity" { + value = var.subscription_id_connectivity +} + +output "subscription_id_identity" { + value = var.subscription_id_identity +} + +output "subscription_id_management" { + value = var.subscription_id_management +} diff --git a/templates/.test/providers.tf b/templates/.test/providers.tf index b35d8790..6da4526d 100644 --- a/templates/.test/providers.tf +++ b/templates/.test/providers.tf @@ -1,13 +1,13 @@ -terraform { - required_providers { - azurerm = { - source = "hashicorp/azurerm" - version = "3.61.0" - } - } - # backend "azurerm" {} -} - -provider "azurerm" { - features {} -} \ No newline at end of file +terraform { + required_providers { + azurerm = { + source = "hashicorp/azurerm" + version = "3.61.0" + } + } + # backend "azurerm" {} +} + +provider "azurerm" { + features {} +} diff --git a/templates/.test/terraform.tfvars b/templates/.test/terraform.tfvars index 27b4d333..95d2298b 100644 --- a/templates/.test/terraform.tfvars +++ b/templates/.test/terraform.tfvars @@ -1,9 +1,9 @@ -test_variable_01 = "testing1" -test_variable_02 = 123 -test_variable_03 = true -test_variable_04 = "uksouth" -test_variable_05 = "00000000-0000-0000-0000-000000000000" -test_variable_06 = "some-thing" -subscription_id_connectivity = "00000000-0000-0000-0000-000000000000" -subscription_id_identity = "00000000-0000-0000-0000-000000000000" -subscription_id_management = "00000000-0000-0000-0000-000000000000" \ No newline at end of file +test_variable_01 = "testing1" +test_variable_02 = 123 +test_variable_03 = true +test_variable_04 = "uksouth" +test_variable_05 = "00000000-0000-0000-0000-000000000000" +test_variable_06 = "some-thing" +subscription_id_connectivity = "00000000-0000-0000-0000-000000000000" +subscription_id_identity = "00000000-0000-0000-0000-000000000000" +subscription_id_management = "00000000-0000-0000-0000-000000000000" diff --git a/templates/.test/variables.tf b/templates/.test/variables.tf index 388c3a88..05212121 100644 --- a/templates/.test/variables.tf +++ b/templates/.test/variables.tf @@ -1,45 +1,45 @@ -variable "test_variable_01" { - type = string - description = "This is the first test variable|4|azure_name" -} - -variable "test_variable_02" { - type = number - description = "This is the second test variable|5|number" -} - -variable "test_variable_03" { - type = bool - description = "This is the third test variable|6|bool" -} - -variable "test_variable_04" { - type = string - description = "This is the fourth test variable|7|azure_location" -} - -variable "test_variable_05" { - type = string - description = "This is the fifth test variable|8|guid" -} - -variable "test_variable_06" { - type = string - description = "This is the sixth test variable.|9|azure_name" - default = "testing-123" -} - -variable "subscription_id_connectivity" { - description = "The identifier of the Connectivity Subscription. (e.g '00000000-0000-0000-0000-000000000000')|1|azure_subscription_id" - type = string -} - -variable "subscription_id_identity" { - description = "The identifier of the Identity Subscription. (e.g '00000000-0000-0000-0000-000000000000')|2|azure_subscription_id" - type = string -} - -variable "subscription_id_management" { - description = "The identifier of the Management Subscription. (e.g 00000000-0000-0000-0000-000000000000)|3|azure_subscription_id" - type = string -} \ No newline at end of file +variable "test_variable_01" { + type = string + description = "This is the first test variable|4|azure_name" +} + +variable "test_variable_02" { + type = number + description = "This is the second test variable|5|number" +} + +variable "test_variable_03" { + type = bool + description = "This is the third test variable|6|bool" +} + +variable "test_variable_04" { + type = string + description = "This is the fourth test variable|7|azure_location" +} + +variable "test_variable_05" { + type = string + description = "This is the fifth test variable|8|guid" +} + +variable "test_variable_06" { + type = string + description = "This is the sixth test variable.|9|azure_name" + default = "testing-123" +} + +variable "subscription_id_connectivity" { + description = "The identifier of the Connectivity Subscription. (e.g '00000000-0000-0000-0000-000000000000')|1|azure_subscription_id" + type = string +} + +variable "subscription_id_identity" { + description = "The identifier of the Identity Subscription. (e.g '00000000-0000-0000-0000-000000000000')|2|azure_subscription_id" + type = string +} + +variable "subscription_id_management" { + description = "The identifier of the Management Subscription. (e.g 00000000-0000-0000-0000-000000000000)|3|azure_subscription_id" + type = string +} diff --git a/templates/basic/data.tf b/templates/basic/data.tf index 7d20a023..d5783ec3 100644 --- a/templates/basic/data.tf +++ b/templates/basic/data.tf @@ -1 +1 @@ -data "azurerm_client_config" "core" {} \ No newline at end of file +data "azurerm_client_config" "core" {} diff --git a/templates/hubnetworking/data.tf b/templates/hubnetworking/data.tf index 7d20a023..d5783ec3 100644 --- a/templates/hubnetworking/data.tf +++ b/templates/hubnetworking/data.tf @@ -1 +1 @@ -data "azurerm_client_config" "core" {} \ No newline at end of file +data "azurerm_client_config" "core" {}