diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index de611b3c..1768bff0 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -1,41 +1,42 @@ +--- name: Release on: release: - types: [ created ] + types: [created] workflow_dispatch: pull_request: branches: - main permissions: - contents: write + contents: write jobs: release: name: Generate Release runs-on: ubuntu-latest steps: - - uses: actions/checkout@v4 - - - name: Zip and Tar - run: | - cd templates - tar -cvzf ../starter_modules.tar.gz . - zip -r ../starter_modules.zip . - - - name: Upload Artifacts - uses: actions/upload-artifact@v4 - with: - name: starter_modules - path: | - starter_modules.tar.gz - starter_modules.zip + - uses: actions/checkout@v4 - - name: Release - uses: softprops/action-gh-release@v2 - if: startsWith(github.ref, 'refs/tags/') - with: - files: | - ./starter_modules.tar.gz - ./starter_modules.zip + - name: Zip and Tar + run: | + cd templates + tar -cvzf ../starter_modules.tar.gz . + zip -r ../starter_modules.zip . + + - name: Upload Artifacts + uses: actions/upload-artifact@v4 + with: + name: starter_modules + path: | + starter_modules.tar.gz + starter_modules.zip + + - name: Release + uses: softprops/action-gh-release@v2 + if: startsWith(github.ref, 'refs/tags/') + with: + files: | + ./starter_modules.tar.gz + ./starter_modules.zip diff --git a/docs/wiki/Home.md b/docs/wiki/Home.md index 537f1184..7fb17434 100644 --- a/docs/wiki/Home.md +++ b/docs/wiki/Home.md @@ -23,14 +23,12 @@ The accelerator follows a 3 phase approach: ![Azure landing zone accelerator process][alz_accelerator_overview] -The components of the environment are similar, but differ depending on your choice of VCS and authentication: +The components of the environment are similar, but differ depending on your choice of VCS: ![Components][components] ### GitHub -We only support federated credentials for GitHub as a best practice. - - Azure: - Resource Group for State - Storage Account and Container for State @@ -54,9 +52,7 @@ We only support federated credentials for GitHub as a best practice. - Customised OIDC Token Subject for governed Actions - [Optional] Runner Group -### Azure DevOps with Workload identity federation (WIF / OIDC) - -This is the recommended authentication method for Azure DevOps. +### Azure DevOps - Azure: - Resource Group for State @@ -83,36 +79,6 @@ This is the recommended authentication method for Azure DevOps. - Group and Members for Apply Approval - [Optional] Agent Pool -### Azure DevOps with Managed identity and self-hosted agents - -We include this option as Workload identity federation (WIF) is still in preview, but it will be removed once WIF is generally available to simplify the accelerator and promote best practice. - -- Azure: - - Resource Group for State - - Storage Account and Container for State - - Resource Group for Identity - - User Assigned Managed Identities (UAMI) for Plan and Apply - - Permissions for the UAMI on state storage container, subscriptions and management groups - - Resource Group for Agents - - Container Instances with UAMI hosting Azure DevOps Agents - - [Optional] Virtual network, subnets, private DNS zone and private endpoint. - -- Azure DevOps - - Project (can be supplied or created) - - Repository for the Module - - Repository for the Pipeline Templates - - Starter Terraform module with tfvars - - Branch policy - - Pipeline for Continuous Integration - - Pipeline for Continuous Delivery - - Environment for Plan - - Environment for Apply - - Variable Group for Backend - - Service Connections with Managed identity for Plan and Apply - - Service Connection Approvals, Template Validation and Concurrency Control - - Group and Members for Apply Approval - - Agent Pools for Plan and Apply - ### Local File System This outputs the ALZ module files to the file system, so you can apply them manually or with your own VCS / automation. diff --git a/docs/wiki/[User-Guide]-Quick-Start-Phase-2-Azure-DevOps.md b/docs/wiki/[User-Guide]-Quick-Start-Phase-2-Azure-DevOps.md index 1236a96b..0f738329 100644 --- a/docs/wiki/[User-Guide]-Quick-Start-Phase-2-Azure-DevOps.md +++ b/docs/wiki/[User-Guide]-Quick-Start-Phase-2-Azure-DevOps.md @@ -16,10 +16,9 @@ 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`. This is ignored if you supply an fqdn to `version_control_system_organization`. 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 project 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. `use_self_hosted_agents`: This controls if you want to deploy self-hosted agents. If you are using `ManagedServiceIdentity` for `azure_devops_authentication_scheme`, then you will need to deploy self-hosted agents as part of the bootstrap, so this setting will have no effect. This will default to `true`. + 1. `use_self_hosted_agents`: This controls if you want to deploy self-hosted agents. This will default to `true`. 1. `azure_devops_agents_personal_access_token`: Enter the Azure DevOps PAT you generated in a previous step specifically for the self-hosted agents. This only applies if you have `use_self_hosted_agents` set to `true`. This defaults to `""`. - 1. `use_private_networking`: This controls whether private networking is deployed for your self-hosted agents and storage account. This only applies if you have `use_self_hosted_agents` set to `true` or `azure_devops_authentication_scheme` is set to `ManagedServiceIdentity`. This defaults to `true`. + 1. `use_private_networking`: This controls whether private networking is deployed for your self-hosted agents and storage account. This only applies if you have `use_self_hosted_agents` set to `true`. This defaults to `true`. 1. `allow_storage_access_from_my_ip`: This controls whether to allow access to the storage account from your IP address. This is only needed for trouble shooting. This only applies if you have `use_private_networking` set to `true`. This defaults to `false`. 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. You will now see a green message telling you that the next section is specific to the starter module you choose. Navigate to the documentation for the relevant starter module to get details of the specific inputs. diff --git a/docs/wiki/[User-Guide]-Quick-Start-Phase-2-GitHub.md b/docs/wiki/[User-Guide]-Quick-Start-Phase-2-GitHub.md index 1797079d..a9bb5c21 100644 --- a/docs/wiki/[User-Guide]-Quick-Start-Phase-2-GitHub.md +++ b/docs/wiki/[User-Guide]-Quick-Start-Phase-2-GitHub.md @@ -13,9 +13,9 @@ 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. `use_self_hosted_agents`: This controls if you want to deploy self-hosted runners. If you are using `ManagedServiceIdentity` for `azure_devops_authentication_scheme`, then you will need to deploy self-hosted runners as part of the bootstrap, so this setting will have no effect. This will default to `true`. + 1. `use_self_hosted_agents`: This controls if you want to deploy self-hosted runners. This will default to `true`. 1. `github_runners_personal_access_token`: Enter the GitHub PAT you generated in a previous step specifically for the self-hosted runners. This only applies if you have `use_self_hosted_agents` set to `true`. This defaults to `""`. - 1. `use_private_networking`: This controls whether private networking is deployed for your self-hosted runners and storage account. This only applies if you have `use_self_hosted_agents` set to `true` or `azure_devops_authentication_scheme` is set to `ManagedServiceIdentity`. This defaults to `true`. + 1. `use_private_networking`: This controls whether private networking is deployed for your self-hosted runners and storage account. This only applies if you have `use_self_hosted_agents` set to `true`. This defaults to `true`. 1. `use_runner_group`: This controls whether to use a Runner Group for self hosted agents. This only applies if `use_self_hosted_agents` is `true` and your GitHub Organization is part of a licensed GitHub Enterprise. This defaults to `true`. 1. `allow_storage_access_from_my_ip`: This controls whether to allow access to the storage account from your IP address. This is only needed for trouble shooting. This only applies if you have `use_private_networking` set to `true`. This defaults to `false`. 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. diff --git a/docs/wiki/[User-Guide]-Starter-Module-Complete.md b/docs/wiki/[User-Guide]-Starter-Module-Complete.md index 46e7dcd6..6b9228ca 100644 --- a/docs/wiki/[User-Guide]-Starter-Module-Complete.md +++ b/docs/wiki/[User-Guide]-Starter-Module-Complete.md @@ -213,7 +213,6 @@ postfix_number: "1" azure_devops_use_organisation_legacy_url: "false" azure_devops_create_project: "true" azure_devops_project_name: "alz-demo" -azure_devops_authentication_scheme: "WorkloadIdentityFederation" version_control_system_use_separate_repository_for_templates: "true" use_self_hosted_agents: "true" use_private_networking: "true" diff --git a/docs/wiki/examples/powershell-inputs/inputs-azure-devops.yaml b/docs/wiki/examples/powershell-inputs/inputs-azure-devops.yaml index 5c32c04e..9c3ea5bf 100644 --- a/docs/wiki/examples/powershell-inputs/inputs-azure-devops.yaml +++ b/docs/wiki/examples/powershell-inputs/inputs-azure-devops.yaml @@ -58,11 +58,6 @@ azure_devops_create_project: "true" # The name of the Azure DevOps project to use or create for the deployment azure_devops_project_name: "" -# The authentication scheme to use for the Azure DevOps Pipelines -# (A valid authentication scheme e.g. 'WorkloadIdentityFederation') -# [allowed: WorkloadIdentityFederation ManagedServiceIdentity] -azure_devops_authentication_scheme: "WorkloadIdentityFederation" - # Controls whether to use self-hosted agents for the pipelines use_self_hosted_agents: "true" diff --git a/templates/ci_cd/azuredevops/cd.yaml b/templates/ci_cd/azuredevops/cd.yaml deleted file mode 100644 index 61de64b4..00000000 --- a/templates/ci_cd/azuredevops/cd.yaml +++ /dev/null @@ -1,27 +0,0 @@ ---- -trigger: - branches: - include: - - main - -resources: - repositories: - - repository: templates - type: git - name: ${project_name}/${repository_name_templates} - -parameters: - - name: terraform_action - displayName: Terraform Action to perform - type: string - default: 'apply' - values: - - 'apply' - - 'destroy' - -lockBehavior: sequential - -extends: - template: ${cd_template_path}@templates - parameters: - terraform_action: $${{ parameters.terraform_action }} diff --git a/templates/ci_cd/azuredevops/ci.yaml b/templates/ci_cd/azuredevops/ci.yaml deleted file mode 100644 index e6be7d9c..00000000 --- a/templates/ci_cd/azuredevops/ci.yaml +++ /dev/null @@ -1,14 +0,0 @@ ---- -trigger: - - none - -resources: - repositories: - - repository: templates - type: git - name: ${project_name}/${repository_name_templates} - -lockBehavior: sequential - -extends: - template: ${ci_template_path}@templates diff --git a/templates/ci_cd/azuredevops/templates/cd.yaml b/templates/ci_cd/azuredevops/templates/cd.yaml deleted file mode 100644 index 4910c76e..00000000 --- a/templates/ci_cd/azuredevops/templates/cd.yaml +++ /dev/null @@ -1,92 +0,0 @@ ---- -parameters: - - name: terraform_action - default: 'apply' - -stages: - - stage: plan - displayName: Plan - variables: - - group: ${variable_group_name} - jobs: - - deployment: plan - displayName: Plan with Terraform - pool: - ${agent_pool_configuration_plan} - environment: ${environment_name_plan} - timeoutInMinutes: 0 - strategy: - runOnce: - deploy: - steps: - - checkout: self - displayName: Checkout Terraform Module - - template: helpers/terraform-installer.yaml - parameters: - terraformVersion: 'latest' - - template: helpers/terraform-init.yaml - parameters: - serviceConnection: '${service_connection_name_plan}' - backendAzureResourceGroupName: $(BACKEND_AZURE_RESOURCE_GROUP_NAME) - backendAzureStorageAccountName: $(BACKEND_AZURE_STORAGE_ACCOUNT_NAME) - backendAzureStorageAccountContainerName: $(BACKEND_AZURE_STORAGE_ACCOUNT_CONTAINER_NAME) - - template: helpers/terraform-plan.yaml - parameters: - terraform_action: $${{ parameters.terraform_action }} - serviceConnection: '${service_connection_name_plan}' - - task: CopyFiles@2 - displayName: Create Module Artifact - inputs: - SourceFolder: '$(Build.SourcesDirectory)' - Contents: | - **/* - !.terraform/**/* - !.git/**/* - !.pipelines/**/* - 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_apply} - environment: ${environment_name_apply} - timeoutInMinutes: 0 - strategy: - runOnce: - deploy: - steps: - - download: none - - task: DownloadPipelineArtifact@2 - displayName: Download Module Artifact - inputs: - buildType: 'current' - artifactName: 'module' - targetPath: '$(Build.SourcesDirectory)' - - template: helpers/terraform-installer.yaml - parameters: - terraformVersion: 'latest' - - template: helpers/terraform-init.yaml - parameters: - serviceConnection: '${service_connection_name_apply}' - backendAzureResourceGroupName: $(BACKEND_AZURE_RESOURCE_GROUP_NAME) - backendAzureStorageAccountName: $(BACKEND_AZURE_STORAGE_ACCOUNT_NAME) - backendAzureStorageAccountContainerName: $(BACKEND_AZURE_STORAGE_ACCOUNT_CONTAINER_NAME) - - template: helpers/terraform-apply.yaml - parameters: - terraform_action: $${{ parameters.terraform_action }} - serviceConnection: '${service_connection_name_apply}' diff --git a/templates/ci_cd/azuredevops/templates/ci.yaml b/templates/ci_cd/azuredevops/templates/ci.yaml deleted file mode 100644 index f93dc5ff..00000000 --- a/templates/ci_cd/azuredevops/templates/ci.yaml +++ /dev/null @@ -1,46 +0,0 @@ ---- -stages: - - stage: validate - displayName: Validation Terraform - variables: - - group: ${variable_group_name} - jobs: - - job: validate - displayName: Validate Terraform - pool: - ${agent_pool_configuration_plan} - steps: - - template: helpers/terraform-installer.yaml - parameters: - 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_plan} - environment: ${environment_name_plan} - timeoutInMinutes: 0 - strategy: - runOnce: - deploy: - steps: - - checkout: self - displayName: Checkout Terraform Module - - template: helpers/terraform-installer.yaml - parameters: - terraformVersion: 'latest' - - template: helpers/terraform-init.yaml - parameters: - serviceConnection: '${service_connection_name_plan}' - backendAzureResourceGroupName: $(BACKEND_AZURE_RESOURCE_GROUP_NAME) - backendAzureStorageAccountName: $(BACKEND_AZURE_STORAGE_ACCOUNT_NAME) - backendAzureStorageAccountContainerName: $(BACKEND_AZURE_STORAGE_ACCOUNT_CONTAINER_NAME) - - template: helpers/terraform-plan.yaml - parameters: - serviceConnection: '${service_connection_name_plan}' diff --git a/templates/ci_cd/azuredevops/templates/helpers/terraform-apply.yaml b/templates/ci_cd/azuredevops/templates/helpers/terraform-apply.yaml deleted file mode 100644 index 2d11112b..00000000 --- a/templates/ci_cd/azuredevops/templates/helpers/terraform-apply.yaml +++ /dev/null @@ -1,44 +0,0 @@ ---- -parameters: - - name: terraform_action - default: 'apply' - - name: serviceConnection - -steps: - - task: AzureCLI@2 - displayName: Terraform Apply for $${{ coalesce(parameters.terraform_action, 'Apply') }} - inputs: - azureSubscription: $${{ parameters.serviceConnection }} - scriptType: pscore - scriptLocation: inlineScript - addSpnToEnvironment: true - inlineScript: | - # Get settings from service connection - az account show 2>$null | ConvertFrom-Json | Set-Variable account - $clientId = $account.user.name - $oidcToken ??= $env:idToken # requires addSpnToEnvironment: true - $subscriptionId = $account.id - $tenantId = $account.tenantId - $isOidc = $oidcToken -ne $null - - $env:ARM_TENANT_ID = $account.tenantId - $env:ARM_SUBSCRIPTION_ID = $account.id - - if($isOidc) { - # Note: We are using CLI auth for the provider as it caches the access token for us, which helps with edge cases like terraform test. - # The backend is hard coded to use OIDC auth as it does not support CLI auth yet. - $env:ARM_USE_CLI = 'true' - $env:ARM_OIDC_TOKEN = $oidcToken - $env:ARM_CLIENT_ID = $clientId - } else { - $env:ARM_USE_MSI = 'true' - } - - # Run Terraform Apply - $command = "terraform" - $arguments = @() - $arguments += "apply" - $arguments += "-auto-approve" - $arguments += "tfplan" - Write-Host "Running: $command $arguments" - & $command $arguments diff --git a/templates/ci_cd/azuredevops/templates/helpers/terraform-init.yaml b/templates/ci_cd/azuredevops/templates/helpers/terraform-init.yaml deleted file mode 100644 index 613fbae2..00000000 --- a/templates/ci_cd/azuredevops/templates/helpers/terraform-init.yaml +++ /dev/null @@ -1,52 +0,0 @@ ---- -parameters: - - name: serviceConnection - - name: backendAzureResourceGroupName - - name: backendAzureStorageAccountName - - name: backendAzureStorageAccountContainerName - - name: backendAzureStorageAccountContainerKeyName - default: terraform.tfstate - -steps: - - task: AzureCLI@2 - displayName: 'Terraform Init' - inputs: - azureSubscription: $${{ parameters.serviceConnection }} - scriptType: pscore - scriptLocation: inlineScript - addSpnToEnvironment: true - inlineScript: | - # Get settings from service connection - az account show 2>$null | ConvertFrom-Json | Set-Variable account - $clientId = $account.user.name - $oidcToken ??= $env:idToken # requires addSpnToEnvironment: true - $subscriptionId = $account.id - $tenantId = $account.tenantId - $isOidc = $oidcToken -ne $null - - $arguments = @() - $arguments += "init" - $arguments += "-backend-config=storage_account_name=$($env:BACKEND_AZURE_STORAGE_ACCOUNT_NAME)" - $arguments += "-backend-config=container_name=$($env:BACKEND_AZURE_STORAGE_ACCOUNT_CONTAINER_NAME)" - $arguments += "-backend-config=key=$($env:BACKEND_AZURE_STORAGE_ACCOUNT_CONTAINER_KEY_NAME)" - $arguments += "-backend-config=resource_group_name=$($env:BACKEND_AZURE_RESOURCE_GROUP_NAME)" - - $env:ARM_SUBSCRIPTION_ID = $subscriptionId - $env:ARM_TENANT_ID = $tenantId - - # Note: The backend is hardcoded to use oidc or msi auth as we want to use a different auth type for the provider during plan and apply. - if($isOidc) { - $env:ARM_OIDC_TOKEN = $oidcToken - $env:ARM_CLIENT_ID = $clientId - } - - # Run terraform init - $command = "terraform" - Write-Host "Running: $command $arguments" - & $command $arguments - - env: - BACKEND_AZURE_RESOURCE_GROUP_NAME: $${{ parameters.backendAzureResourceGroupName }} - BACKEND_AZURE_STORAGE_ACCOUNT_NAME: $${{ parameters.backendAzureStorageAccountName }} - BACKEND_AZURE_STORAGE_ACCOUNT_CONTAINER_NAME: $${{ parameters.backendAzureStorageAccountContainerName }} - BACKEND_AZURE_STORAGE_ACCOUNT_CONTAINER_KEY_NAME: $${{ parameters.backendAzureStorageAccountContainerKeyName }} diff --git a/templates/ci_cd/azuredevops/templates/helpers/terraform-installer.yaml b/templates/ci_cd/azuredevops/templates/helpers/terraform-installer.yaml deleted file mode 100644 index 977850e5..00000000 --- a/templates/ci_cd/azuredevops/templates/helpers/terraform-installer.yaml +++ /dev/null @@ -1,115 +0,0 @@ ---- -parameters: - - name: terraformVersion - default: 'latest' - -steps: - - pwsh: | - $TF_VERSION = $env:TF_VERSION - $TOOLS_PATH = $env:TOOLS_PATH - - if($TF_VERSION -eq "latest") { - $TF_VERSION = (Invoke-WebRequest -Uri "https://checkpoint-api.hashicorp.com/v1/check/terraform").Content | ConvertFrom-Json | Select -ExpandProperty current_version - } - - $commandDetails = Get-Command -Name terraform -ErrorAction SilentlyContinue - if($commandDetails) { - Write-Host "Terraform already installed in $($commandDetails.Path), checking version" - $installedVersion = terraform version -json | ConvertFrom-Json - Write-Host "Installed version: $($installedVersion.terraform_version) on $($installedVersion.platform)" - if($installedVersion.terraform_version -eq $TF_VERSION) { - Write-Host "Installed version matches required version $TF_VERSION, skipping install" - return - } - } - - $unzipdir = Join-Path -Path $TOOLS_PATH -ChildPath "terraform_$TF_VERSION" - if (Test-Path $unzipdir) { - Write-Host "Terraform $TF_VERSION already installed." - if($os -eq "windows") { - $env:PATH = "$($unzipdir);$env:PATH" - } else { - $env:PATH = "$($unzipdir):$env:PATH" - } - Write-Host "##vso[task.setvariable variable=PATH]$env:PATH" - return - } - - $os = "" - if ($IsWindows) { - $os = "windows" - } - if($IsLinux) { - $os = "linux" - } - if($IsMacOS) { - $os = "darwin" - } - - # Enum values can be seen here: https://learn.microsoft.com/en-us/dotnet/api/system.runtime.interopservices.architecture?view=net-7.0#fields - $architecture = ([System.Runtime.InteropServices.RuntimeInformation]::OSArchitecture).ToString().ToLower() - - if($architecture -eq "x64") { - $architecture = "amd64" - } - if($architecture -eq "x86") { - $architecture = "386" - } - - $osAndArchitecture = "$($os)_$($architecture)" - - $supportedOsAndArchitectures = @( - "darwin_amd64", - "darwin_arm64", - "linux_386", - "linux_amd64", - "linux_arm64", - "windows_386", - "windows_amd64" - ) - - if($supportedOsAndArchitectures -notcontains $osAndArchitecture) { - Write-Error "Unsupported OS and architecture combination: $osAndArchitecture" - exit 1 - } - - $zipfilePath = "$unzipdir.zip" - - $url = "https://releases.hashicorp.com/terraform/$($TF_VERSION)/terraform_$($TF_VERSION)_$($osAndArchitecture).zip" - - if(!(Test-Path $TOOLS_PATH)) { - New-Item -ItemType Directory -Path $TOOLS_PATH| Out-String | Write-Verbose - } - - Invoke-WebRequest -Uri $url -OutFile "$zipfilePath" | Out-String | Write-Verbose - - Expand-Archive -Path $zipfilePath -DestinationPath $unzipdir - - $toolFileName = "terraform" - - if($os -eq "windows") { - $toolFileName = "$($toolFileName).exe" - } - - $toolFilePath = Join-Path -Path $unzipdir -ChildPath $toolFileName - - if($os -ne "windows") { - $isExecutable = $(test -x $toolFilePath; 0 -eq $LASTEXITCODE) - if(!($isExecutable)) { - chmod +x $toolFilePath - } - } - - if($os -eq "windows") { - $env:PATH = "$($unzipdir);$env:PATH" - } else { - $env:PATH = "$($unzipdir):$env:PATH" - } - Write-Host "##vso[task.setvariable variable=PATH]$env:PATH" - Remove-Item $zipfilePath - Write-Host "Installed Terraform version $TF_VERSION" - - displayName: Install Terraform - env: - TF_VERSION: $${{ parameters.terraformVersion }} - TOOLS_PATH: $(Agent.ToolsDirectory) diff --git a/templates/ci_cd/azuredevops/templates/helpers/terraform-plan.yaml b/templates/ci_cd/azuredevops/templates/helpers/terraform-plan.yaml deleted file mode 100644 index 3e4712c2..00000000 --- a/templates/ci_cd/azuredevops/templates/helpers/terraform-plan.yaml +++ /dev/null @@ -1,52 +0,0 @@ ---- -parameters: - - name: terraform_action - default: 'apply' - - name: serviceConnection - -steps: - - task: AzureCLI@2 - displayName: Terraform Plan for $${{ coalesce(parameters.terraform_action, 'Apply') }} - inputs: - azureSubscription: $${{ parameters.serviceConnection }} - scriptType: pscore - scriptLocation: inlineScript - addSpnToEnvironment: true - inlineScript: | - # Get settings from service connection - az account show 2>$null | ConvertFrom-Json | Set-Variable account - $clientId = $account.user.name - $oidcToken ??= $env:idToken # requires addSpnToEnvironment: true - $subscriptionId = $account.id - $tenantId = $account.tenantId - $isOidc = $oidcToken -ne $null - - $env:ARM_TENANT_ID = $account.tenantId - $env:ARM_SUBSCRIPTION_ID = $account.id - - if($isOidc) { - # Note: We are using CLI auth for the provider as it caches the access token for us, which helps with edge cases like terraform test. - # The backend is hard coded to use OIDC auth as it does not support CLI auth yet. - $env:ARM_USE_CLI = 'true' - $env:ARM_OIDC_TOKEN = $oidcToken - $env:ARM_CLIENT_ID = $clientId - } else { - $env:ARM_USE_MSI = 'true' - } - - # Run Terraform Plan - $command = "terraform" - $arguments = @() - $arguments += "plan" - $arguments += "-out=tfplan" - $arguments += "-input=false" - - if ($env:TERRAFORM_ACTION -eq 'destroy') { - $arguments += "-destroy" - } - - Write-Host "Running: $command $arguments" - & $command $arguments - - env: - TERRAFORM_ACTION: $${{ coalesce(parameters.terraform_action, 'apply') }} diff --git a/templates/ci_cd/github/cd.yaml b/templates/ci_cd/github/cd.yaml deleted file mode 100644 index 2857e05d..00000000 --- a/templates/ci_cd/github/cd.yaml +++ /dev/null @@ -1,26 +0,0 @@ ---- -name: 02 Azure Landing Zone Continuous Delivery -on: - push: - branches: - - main - workflow_dispatch: - inputs: - terraform_action: - description: 'Terraform Action to perform' - required: true - default: 'apply' - type: choice - options: - - 'apply' - - 'destroy' - -jobs: - plan_and_apply: - uses: ${organization_name}/${repository_name_templates}/${cd_template_path}@main - name: 'CD' - permissions: - id-token: write - contents: read - with: - terraform_action: $${{ github.event.inputs.terraform_action }} diff --git a/templates/ci_cd/github/ci.yaml b/templates/ci_cd/github/ci.yaml deleted file mode 100644 index 960962e7..00000000 --- a/templates/ci_cd/github/ci.yaml +++ /dev/null @@ -1,16 +0,0 @@ ---- -name: 01 Azure Landing Zone Continuous Integration -on: - pull_request: - branches: - - main - workflow_dispatch: - -jobs: - validate_and_plan: - uses: ${organization_name}/${repository_name_templates}/${ci_template_path}@main - name: 'CI' - permissions: - id-token: write - contents: read - pull-requests: write diff --git a/templates/ci_cd/github/templates/cd.yaml b/templates/ci_cd/github/templates/cd.yaml deleted file mode 100644 index 0d9083f9..00000000 --- a/templates/ci_cd/github/templates/cd.yaml +++ /dev/null @@ -1,100 +0,0 @@ ---- -name: Continuous Delivery -on: - workflow_call: - inputs: - terraform_action: - description: 'Terraform Action to perform' - default: 'apply' - type: string - -jobs: - plan: - name: Plan with Terraform - runs-on: - ${runner_name} - concurrency: ${backend_azure_storage_account_container_name} - environment: ${environment_name_plan} - permissions: - id-token: write - contents: read - 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 == 'destroy' && 'Destroy' || 'Apply' }} - run: | - # shellcheck disable=SC2086 - terraform plan -out=tfplan -input=false $${{ github.event.inputs.terraform_action == 'destroy' && '-destroy' || '' }} - - - name: Create Module Artifact - run: | - $stagingDirectory = "staging" - New-Item -Path . -Name $stagingDirectory -ItemType "directory" - Copy-Item -Path "./*" -Exclude @(".git", ".terraform", ".github", $stagingDirectory) -Recurse -Destination "./$stagingDirectory" - - 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 - runs-on: - ${runner_name} - concurrency: ${backend_azure_storage_account_container_name} - environment: ${environment_name_apply} - permissions: - id-token: write - contents: read - 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 == 'destroy' && 'Destroy' || 'Apply' }} - run: terraform apply -input=false -auto-approve tfplan diff --git a/templates/ci_cd/github/templates/ci.yaml b/templates/ci_cd/github/templates/ci.yaml deleted file mode 100644 index 8043de39..00000000 --- a/templates/ci_cd/github/templates/ci.yaml +++ /dev/null @@ -1,89 +0,0 @@ ---- -name: Continuous Integration -on: - workflow_call: - -jobs: - validate: - name: Validate Terraform - runs-on: - ${runner_name} - environment: ${environment_name_plan} - 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: - ${runner_name} - concurrency: ${backend_azure_storage_account_container_name} - environment: ${environment_name_plan} - permissions: - # NOTE: When modifying the token subject claims and adding `environment`. - # If the `id-token` permission is granted at the workflow level - # and the workflow has at least one job that does not specify an environment - # then the action will fail with an internal error. - id-token: write - contents: read - pull-requests: write - 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 -input=false - - - name: Update Pull Request - if: (success() || failure()) && github.event_name == 'pull_request' - uses: actions/github-script@v6 - with: - github-token: $${{ secrets.GITHUB_TOKEN }} - script: | - const output = `#### Terraform Plan 📖\`$${{ steps.plan.outcome }}\` - -
Run details - - The plan was a $${{ steps.plan.outcome }} see the action for more details. - -
- - *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 - })