├── .gitignore ├── 01-terraform-azure-devops-ci-pipeline.yml ├── README.md ├── pipeline-backups ├── ci-pipeline-backup │ └── backup-azure-pipelines.yml └── release-pipeline-backup │ └── Terraform-CD.json └── terraform-manifests ├── .terraform.lock.hcl ├── c1-versions.tf ├── c2-generic-input-variables.tf ├── c3-locals.tf ├── c4-random-resources.tf ├── c5-resource-group.tf ├── c6-01-vnet-input-variables.tf ├── c6-02-virtual-network.tf ├── c6-03-web-subnet-and-nsg.tf ├── c6-04-app-subnet-and-nsg.tf ├── c6-05-db-subnet-and-nsg.tf ├── c6-06-bastion-subnet-and-nsg.tf ├── c6-07-vnet-outputs.tf ├── c7-01-web-linuxvm-input-variables.tf ├── c7-02-web-linuxvm-publicip.tf ├── c7-03-web-linuxvm-network-interface.tf ├── c7-04-web-linuxvm-network-security-group.tf ├── c7-05-web-linuxvm-resource.tf ├── c7-06-web-linuxvm-outputs.tf ├── dev.tfvars ├── prod.tfvars ├── qa.tfvars ├── ssh-keys ├── terraform-azure.pem └── terraform-azure.pub ├── stage.tfvars └── terraform.tfvars /.gitignore: -------------------------------------------------------------------------------- 1 | # Local .terraform directories 2 | **/.terraform/* 3 | 4 | # .tfstate files 5 | *.tfstate 6 | *.tfstate.* 7 | 8 | # Crash log files 9 | crash.log 10 | 11 | # Ignore any .tfvars files that are generated automatically for each Terraform run. Most 12 | # .tfvars files are managed as part of configuration and so should be included in 13 | # version control. 14 | # 15 | # example.tfvars 16 | 17 | # Ignore override files as they are usually used to override resources locally and so 18 | # are not checked in 19 | override.tf 20 | override.tf.json 21 | *_override.tf 22 | *_override.tf.json 23 | 24 | # Include override files you do wish to add to version control using negated pattern 25 | # 26 | # !example_override.tf 27 | 28 | # Include tfplan files to ignore the plan output of command: terraform plan -out=tfplan 29 | # example: *tfplan* 30 | -------------------------------------------------------------------------------- /01-terraform-azure-devops-ci-pipeline.yml: -------------------------------------------------------------------------------- 1 | trigger: 2 | - main 3 | 4 | # Stages 5 | # Stage-1: 6 | # Task-1: Copy terraform-manifests files to Build Artifact Directory 7 | # Task-2: Publish build articats to Azure Pipelines 8 | # Pipeline Hierarchial Flow: Stages -> Stage -> Jobs -> Job -> Steps -> Task1, Task2, Task3 9 | 10 | stages: 11 | # Build Stage 12 | - stage: Build 13 | displayName: Build Stage 14 | jobs: 15 | - job: Build 16 | displayName: Build Job 17 | pool: 18 | vmImage: 'ubuntu-latest' 19 | steps: 20 | ## Publish Artifacts pipeline code in addition to Build and Push 21 | - bash: echo Contents in System Default Working Directory; ls -R $(System.DefaultWorkingDirectory) 22 | - bash: echo Before copying Contents in Build Artifact Directory; ls -R $(Build.ArtifactStagingDirectory) 23 | # Task-1: Copy files (Copy files from a source folder to target folder) 24 | # Source Directory: $(System.DefaultWorkingDirectory)/terraform-manifests 25 | # Target Directory: $(Build.ArtifactStagingDirectory) 26 | - task: CopyFiles@2 27 | inputs: 28 | SourceFolder: '$(System.DefaultWorkingDirectory)/terraform-manifests' 29 | Contents: '**' 30 | TargetFolder: '$(Build.ArtifactStagingDirectory)' 31 | OverWrite: true 32 | # List files from Build Artifact Staging Directory - After Copy 33 | - bash: echo After copying to Build Artifact Directory; ls -R $(Build.ArtifactStagingDirectory) 34 | # Task-2: Publish build artifacts (Publish build to Azure Pipelines) 35 | - task: PublishBuildArtifacts@1 36 | inputs: 37 | PathtoPublish: '$(Build.ArtifactStagingDirectory)' 38 | ArtifactName: 'terraform-manifests' 39 | publishLocation: 'Container' 40 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Terraform on Azure with Azure IaC DevOps for Terraform Project 2 | 3 | 1. Implement IaC usecases with Terraform on Azure cloud using Azure DevOps 4 | 2. Implement Azure Build Pipelines (Continuous Integration Pipelines) 5 | 3. Implement Azure Release Pipelines (Continuous Delivery Pipelines) 6 | 4. [Github SSH Connection](https://docs.github.com/en/github/authenticating-to-github/connecting-to-github-with-ssh/about-ssh) 7 | -------------------------------------------------------------------------------- /pipeline-backups/ci-pipeline-backup/backup-azure-pipelines.yml: -------------------------------------------------------------------------------- 1 | trigger: 2 | - main 3 | 4 | # Stages 5 | # Stage-1: 6 | # Task-1: Copy terraform-manifests files to Build Artifact Directory 7 | # Task-2: Publish build articats to Azure Pipelines 8 | # Pipeline Hierarchial Flow: Stages -> Stage -> Jobs -> Job -> Steps -> Task1, Task2, Task3 9 | 10 | stages: 11 | # Build Stage 12 | - stage: Build 13 | displayName: Build Stage 14 | jobs: 15 | - job: Build 16 | displayName: Build Job 17 | pool: 18 | vmImage: 'ubuntu-latest' 19 | steps: 20 | ## Publish Artifacts pipeline code in addition to Build and Push 21 | - bash: echo Contents in System Default Working Directory; ls -R $(System.DefaultWorkingDirectory) 22 | - bash: echo Before copying Contents in Build Artifact Directory; ls -R $(Build.ArtifactStagingDirectory) 23 | # Task-2: Copy files (Copy files from a source folder to target folder) 24 | # Source Directory: $(System.DefaultWorkingDirectory)/terraform-manifests 25 | # Target Directory: $(Build.ArtifactStagingDirectory) 26 | - task: CopyFiles@2 27 | inputs: 28 | SourceFolder: '$(System.DefaultWorkingDirectory)/terraform-manifests' 29 | Contents: '**' 30 | TargetFolder: '$(Build.ArtifactStagingDirectory)' 31 | OverWrite: true 32 | # List files from Build Artifact Staging Directory - After Copy 33 | - bash: echo After copying to Build Artifact Directory; ls -R $(Build.ArtifactStagingDirectory) 34 | # Task-3: Publish build artifacts (Publish build to Azure Pipelines) 35 | - task: PublishBuildArtifacts@1 36 | inputs: 37 | PathtoPublish: '$(Build.ArtifactStagingDirectory)' 38 | ArtifactName: 'terraform-manifests' 39 | publishLocation: 'Container' 40 | -------------------------------------------------------------------------------- /pipeline-backups/release-pipeline-backup/Terraform-CD.json: -------------------------------------------------------------------------------- 1 | {"source":2,"revision":17,"description":null,"createdBy":{"displayName":"Stack Simplify","url":"https://spsprodsin1.vssps.visualstudio.com/A0e49ef12-3b12-4bce-8402-6d597dfcf044/_apis/Identities/3148445f-5326-6553-95f0-3b2b95341788","_links":{"avatar":{"href":"https://dev.azure.com/stacksimplify1/_apis/GraphProfile/MemberAvatars/msa.MzE0ODQ0NWYtNTMyNi03NTUzLTk1ZjAtM2IyYjk1MzQxNzg4"}},"id":"3148445f-5326-6553-95f0-3b2b95341788","uniqueName":"stacksimplify@gmail.com","imageUrl":"https://dev.azure.com/stacksimplify1/_apis/GraphProfile/MemberAvatars/msa.MzE0ODQ0NWYtNTMyNi03NTUzLTk1ZjAtM2IyYjk1MzQxNzg4","descriptor":"msa.MzE0ODQ0NWYtNTMyNi03NTUzLTk1ZjAtM2IyYjk1MzQxNzg4"},"createdOn":"2021-08-25T08:57:22.800Z","modifiedBy":{"displayName":"Stack Simplify","url":"https://spsprodsin1.vssps.visualstudio.com/A0e49ef12-3b12-4bce-8402-6d597dfcf044/_apis/Identities/3148445f-5326-6553-95f0-3b2b95341788","_links":{"avatar":{"href":"https://dev.azure.com/stacksimplify1/_apis/GraphProfile/MemberAvatars/msa.MzE0ODQ0NWYtNTMyNi03NTUzLTk1ZjAtM2IyYjk1MzQxNzg4"}},"id":"3148445f-5326-6553-95f0-3b2b95341788","uniqueName":"stacksimplify@gmail.com","imageUrl":"https://dev.azure.com/stacksimplify1/_apis/GraphProfile/MemberAvatars/msa.MzE0ODQ0NWYtNTMyNi03NTUzLTk1ZjAtM2IyYjk1MzQxNzg4","descriptor":"msa.MzE0ODQ0NWYtNTMyNi03NTUzLTk1ZjAtM2IyYjk1MzQxNzg4"},"modifiedOn":"2021-08-25T10:01:07.770Z","isDeleted":false,"lastRelease":{"id":7,"name":"Release-7","artifacts":[],"_links":{},"description":"Triggered by Terraform Continuous Integration CI Pipeline 20210825.9.","releaseDefinition":{"id":1,"projectReference":null,"_links":{}},"createdOn":"2021-08-25T10:29:34.117Z","createdBy":{"displayName":"Stack Simplify","url":"https://spsprodsin1.vssps.visualstudio.com/A0e49ef12-3b12-4bce-8402-6d597dfcf044/_apis/Identities/3148445f-5326-6553-95f0-3b2b95341788","_links":{"avatar":{"href":"https://dev.azure.com/stacksimplify1/_apis/GraphProfile/MemberAvatars/msa.MzE0ODQ0NWYtNTMyNi03NTUzLTk1ZjAtM2IyYjk1MzQxNzg4"}},"id":"3148445f-5326-6553-95f0-3b2b95341788","uniqueName":"stacksimplify@gmail.com","imageUrl":"https://dev.azure.com/stacksimplify1/_apis/GraphProfile/MemberAvatars/msa.MzE0ODQ0NWYtNTMyNi03NTUzLTk1ZjAtM2IyYjk1MzQxNzg4","descriptor":"msa.MzE0ODQ0NWYtNTMyNi03NTUzLTk1ZjAtM2IyYjk1MzQxNzg4"}},"variables":{},"variableGroups":[],"environments":[{"id":1,"name":"Dev","rank":1,"owner":{"displayName":"Stack Simplify","url":"https://spsprodsin1.vssps.visualstudio.com/A0e49ef12-3b12-4bce-8402-6d597dfcf044/_apis/Identities/3148445f-5326-6553-95f0-3b2b95341788","_links":{"avatar":{"href":"https://dev.azure.com/stacksimplify1/_apis/GraphProfile/MemberAvatars/msa.MzE0ODQ0NWYtNTMyNi03NTUzLTk1ZjAtM2IyYjk1MzQxNzg4"}},"id":"3148445f-5326-6553-95f0-3b2b95341788","uniqueName":"stacksimplify@gmail.com","imageUrl":"https://dev.azure.com/stacksimplify1/_apis/GraphProfile/MemberAvatars/msa.MzE0ODQ0NWYtNTMyNi03NTUzLTk1ZjAtM2IyYjk1MzQxNzg4","descriptor":"msa.MzE0ODQ0NWYtNTMyNi03NTUzLTk1ZjAtM2IyYjk1MzQxNzg4"},"variables":{},"variableGroups":[],"preDeployApprovals":{"approvals":[{"rank":1,"isAutomated":true,"isNotificationOn":false,"id":1}],"approvalOptions":{"requiredApproverCount":null,"releaseCreatorCanBeApprover":false,"autoTriggeredAndPreviousEnvironmentApprovedCanBeSkipped":false,"enforceIdentityRevalidation":false,"timeoutInMinutes":0,"executionOrder":1}},"deployStep":{"id":2},"postDeployApprovals":{"approvals":[{"rank":1,"isAutomated":true,"isNotificationOn":false,"id":3}],"approvalOptions":{"requiredApproverCount":null,"releaseCreatorCanBeApprover":false,"autoTriggeredAndPreviousEnvironmentApprovedCanBeSkipped":false,"enforceIdentityRevalidation":false,"timeoutInMinutes":0,"executionOrder":2}},"deployPhases":[{"deploymentInput":{"parallelExecution":{"parallelExecutionType":0},"agentSpecification":{"identifier":"ubuntu-20.04"},"skipArtifactsDownload":false,"artifactsDownloadInput":{"downloadInputs":[]},"queueId":54,"demands":[],"enableAccessToken":false,"timeoutInMinutes":0,"jobCancelTimeoutInMinutes":1,"condition":"succeeded()","overrideInputs":{}},"rank":1,"phaseType":1,"name":"Agent job","refName":null,"workflowTasks":[{"environment":{},"taskId":"a4789e5d-f6e8-431f-add9-379d640a883c","version":"0.*","name":"Install Terraform 1.0.5","refName":"","enabled":true,"alwaysRun":false,"continueOnError":false,"timeoutInMinutes":0,"definitionType":"task","overrideInputs":{},"condition":"succeeded()","inputs":{"terraformVersion":"1.0.5"}},{"environment":{},"taskId":"fe504acc-6115-40cb-89ff-191386b5e7bf","version":"2.*","name":"Terraform : Init","refName":"","enabled":true,"alwaysRun":false,"continueOnError":false,"timeoutInMinutes":0,"definitionType":"task","overrideInputs":{},"condition":"succeeded()","inputs":{"provider":"azurerm","command":"init","workingDirectory":"$(System.DefaultWorkingDirectory)/_Terraform Continuous Integration CI Pipeline/terraform-manifests","commandOptions":"","environmentServiceNameAzureRM":"","environmentServiceNameAWS":"","environmentServiceNameGCP":"","backendServiceArm":"6cf8a51b-70a0-4999-9be3-171f3dcca1b1","backendAzureRmResourceGroupName":"terraform-storage-rg","backendAzureRmStorageAccountName":"terraformstate201","backendAzureRmContainerName":"tfstatefiles","backendAzureRmKey":"dev-terraform.tfstate","backendServiceAWS":"","backendAWSBucketName":"","backendAWSKey":"","backendServiceGCP":"","backendGCPBucketName":"","backendGCPPrefix":""}},{"environment":{},"taskId":"fe504acc-6115-40cb-89ff-191386b5e7bf","version":"2.*","name":"Terraform : validate","refName":"","enabled":true,"alwaysRun":false,"continueOnError":false,"timeoutInMinutes":0,"definitionType":"task","overrideInputs":{},"condition":"succeeded()","inputs":{"provider":"azurerm","command":"validate","workingDirectory":"$(System.DefaultWorkingDirectory)/_Terraform Continuous Integration CI Pipeline/terraform-manifests","commandOptions":"","environmentServiceNameAzureRM":"","environmentServiceNameAWS":"","environmentServiceNameGCP":"","backendServiceArm":"","backendAzureRmResourceGroupName":"","backendAzureRmStorageAccountName":"","backendAzureRmContainerName":"","backendAzureRmKey":"","backendServiceAWS":"","backendAWSBucketName":"","backendAWSKey":"","backendServiceGCP":"","backendGCPBucketName":"","backendGCPPrefix":""}},{"environment":{},"taskId":"fe504acc-6115-40cb-89ff-191386b5e7bf","version":"2.*","name":"Terraform : plan","refName":"","enabled":true,"alwaysRun":false,"continueOnError":false,"timeoutInMinutes":0,"definitionType":"task","overrideInputs":{},"condition":"succeeded()","inputs":{"provider":"azurerm","command":"plan","workingDirectory":"$(System.DefaultWorkingDirectory)/_Terraform Continuous Integration CI Pipeline/terraform-manifests","commandOptions":"-var-file=dev.tfvars","environmentServiceNameAzureRM":"6cf8a51b-70a0-4999-9be3-171f3dcca1b1","environmentServiceNameAWS":"","environmentServiceNameGCP":"","backendServiceArm":"","backendAzureRmResourceGroupName":"","backendAzureRmStorageAccountName":"","backendAzureRmContainerName":"","backendAzureRmKey":"","backendServiceAWS":"","backendAWSBucketName":"","backendAWSKey":"","backendServiceGCP":"","backendGCPBucketName":"","backendGCPPrefix":""}},{"environment":{},"taskId":"fe504acc-6115-40cb-89ff-191386b5e7bf","version":"2.*","name":"Terraform : apply -auto-approve","refName":"","enabled":true,"alwaysRun":false,"continueOnError":false,"timeoutInMinutes":0,"definitionType":"task","overrideInputs":{},"condition":"succeeded()","inputs":{"provider":"azurerm","command":"apply","workingDirectory":"$(System.DefaultWorkingDirectory)/_Terraform Continuous Integration CI Pipeline/terraform-manifests","commandOptions":"-var-file=dev.tfvars -auto-approve","environmentServiceNameAzureRM":"6cf8a51b-70a0-4999-9be3-171f3dcca1b1","environmentServiceNameAWS":"","environmentServiceNameGCP":"","backendServiceArm":"","backendAzureRmResourceGroupName":"","backendAzureRmStorageAccountName":"","backendAzureRmContainerName":"","backendAzureRmKey":"","backendServiceAWS":"","backendAWSBucketName":"","backendAWSKey":"","backendServiceGCP":"","backendGCPBucketName":"","backendGCPPrefix":""}}]}],"environmentOptions":{"emailNotificationType":"OnlyOnFailure","emailRecipients":"release.environment.owner;release.creator","skipArtifactsDownload":false,"timeoutInMinutes":0,"enableAccessToken":false,"publishDeploymentStatus":true,"badgeEnabled":false,"autoLinkWorkItems":false,"pullRequestDeploymentEnabled":false},"demands":[],"conditions":[{"name":"ReleaseStarted","conditionType":1,"value":""}],"executionPolicy":{"concurrencyCount":1,"queueDepthCount":0},"schedules":[],"currentRelease":{"id":7,"url":"https://vsrm.dev.azure.com/stacksimplify1/9a3e7db9-9b55-405d-a8fa-49a65dd823f4/_apis/Release/releases/7","_links":{}},"retentionPolicy":{"daysToKeep":30,"releasesToKeep":3,"retainBuild":true},"processParameters":{},"properties":{"BoardsEnvironmentType":{"$type":"System.String","$value":"unmapped"},"LinkBoardsWorkItems":{"$type":"System.String","$value":"False"}},"preDeploymentGates":{"id":0,"gatesOptions":null,"gates":[]},"postDeploymentGates":{"id":0,"gatesOptions":null,"gates":[]},"environmentTriggers":[],"badgeUrl":"https://vsrm.dev.azure.com/stacksimplify1/_apis/public/Release/badge/9a3e7db9-9b55-405d-a8fa-49a65dd823f4/1/1"},{"id":2,"name":"QA","rank":2,"owner":{"displayName":"Stack Simplify","url":"https://spsprodsin1.vssps.visualstudio.com/A0e49ef12-3b12-4bce-8402-6d597dfcf044/_apis/Identities/3148445f-5326-6553-95f0-3b2b95341788","_links":{"avatar":{"href":"https://dev.azure.com/stacksimplify1/_apis/GraphProfile/MemberAvatars/msa.MzE0ODQ0NWYtNTMyNi03NTUzLTk1ZjAtM2IyYjk1MzQxNzg4"}},"id":"3148445f-5326-6553-95f0-3b2b95341788","uniqueName":"stacksimplify@gmail.com","imageUrl":"https://dev.azure.com/stacksimplify1/_apis/GraphProfile/MemberAvatars/msa.MzE0ODQ0NWYtNTMyNi03NTUzLTk1ZjAtM2IyYjk1MzQxNzg4","descriptor":"msa.MzE0ODQ0NWYtNTMyNi03NTUzLTk1ZjAtM2IyYjk1MzQxNzg4"},"variables":{},"variableGroups":[],"preDeployApprovals":{"approvals":[{"rank":1,"isAutomated":false,"isNotificationOn":false,"approver":{"displayName":"Stack Simplify","url":"https://spsprodsin1.vssps.visualstudio.com/A0e49ef12-3b12-4bce-8402-6d597dfcf044/_apis/Identities/3148445f-5326-6553-95f0-3b2b95341788","_links":{"avatar":{"href":"https://dev.azure.com/stacksimplify1/_apis/GraphProfile/MemberAvatars/msa.MzE0ODQ0NWYtNTMyNi03NTUzLTk1ZjAtM2IyYjk1MzQxNzg4"}},"id":"3148445f-5326-6553-95f0-3b2b95341788","uniqueName":"stacksimplify@gmail.com","imageUrl":"https://dev.azure.com/stacksimplify1/_apis/GraphProfile/MemberAvatars/msa.MzE0ODQ0NWYtNTMyNi03NTUzLTk1ZjAtM2IyYjk1MzQxNzg4","descriptor":"msa.MzE0ODQ0NWYtNTMyNi03NTUzLTk1ZjAtM2IyYjk1MzQxNzg4"},"id":13}],"approvalOptions":{"requiredApproverCount":null,"releaseCreatorCanBeApprover":true,"autoTriggeredAndPreviousEnvironmentApprovedCanBeSkipped":false,"enforceIdentityRevalidation":false,"timeoutInMinutes":0,"executionOrder":1}},"deployStep":{"id":5},"postDeployApprovals":{"approvals":[{"rank":1,"isAutomated":true,"isNotificationOn":false,"id":6}],"approvalOptions":{"requiredApproverCount":null,"releaseCreatorCanBeApprover":false,"autoTriggeredAndPreviousEnvironmentApprovedCanBeSkipped":false,"enforceIdentityRevalidation":false,"timeoutInMinutes":0,"executionOrder":2}},"deployPhases":[{"deploymentInput":{"parallelExecution":{"parallelExecutionType":0},"agentSpecification":{"identifier":"ubuntu-20.04"},"skipArtifactsDownload":false,"artifactsDownloadInput":{"downloadInputs":[]},"queueId":54,"demands":[],"enableAccessToken":false,"timeoutInMinutes":0,"jobCancelTimeoutInMinutes":1,"condition":"succeeded()","overrideInputs":{}},"rank":1,"phaseType":1,"name":"Agent job","refName":null,"workflowTasks":[{"environment":{},"taskId":"a4789e5d-f6e8-431f-add9-379d640a883c","version":"0.*","name":"Install Terraform 1.0.5","refName":"","enabled":true,"alwaysRun":false,"continueOnError":false,"timeoutInMinutes":0,"definitionType":"task","overrideInputs":{},"condition":"succeeded()","inputs":{"terraformVersion":"1.0.5"}},{"environment":{},"taskId":"fe504acc-6115-40cb-89ff-191386b5e7bf","version":"2.*","name":"Terraform : Init","refName":"","enabled":true,"alwaysRun":false,"continueOnError":false,"timeoutInMinutes":0,"definitionType":"task","overrideInputs":{},"condition":"succeeded()","inputs":{"provider":"azurerm","command":"init","workingDirectory":"$(System.DefaultWorkingDirectory)/_Terraform Continuous Integration CI Pipeline/terraform-manifests","commandOptions":"","environmentServiceNameAzureRM":"","environmentServiceNameAWS":"","environmentServiceNameGCP":"","backendServiceArm":"6cf8a51b-70a0-4999-9be3-171f3dcca1b1","backendAzureRmResourceGroupName":"terraform-storage-rg","backendAzureRmStorageAccountName":"terraformstate201","backendAzureRmContainerName":"tfstatefiles","backendAzureRmKey":"qa-terraform.tfstate","backendServiceAWS":"","backendAWSBucketName":"","backendAWSKey":"","backendServiceGCP":"","backendGCPBucketName":"","backendGCPPrefix":""}},{"environment":{},"taskId":"fe504acc-6115-40cb-89ff-191386b5e7bf","version":"2.*","name":"Terraform : validate","refName":"","enabled":true,"alwaysRun":false,"continueOnError":false,"timeoutInMinutes":0,"definitionType":"task","overrideInputs":{},"condition":"succeeded()","inputs":{"provider":"azurerm","command":"validate","workingDirectory":"$(System.DefaultWorkingDirectory)/_Terraform Continuous Integration CI Pipeline/terraform-manifests","commandOptions":"","environmentServiceNameAzureRM":"","environmentServiceNameAWS":"","environmentServiceNameGCP":"","backendServiceArm":"","backendAzureRmResourceGroupName":"","backendAzureRmStorageAccountName":"","backendAzureRmContainerName":"","backendAzureRmKey":"","backendServiceAWS":"","backendAWSBucketName":"","backendAWSKey":"","backendServiceGCP":"","backendGCPBucketName":"","backendGCPPrefix":""}},{"environment":{},"taskId":"fe504acc-6115-40cb-89ff-191386b5e7bf","version":"2.*","name":"Terraform : plan","refName":"","enabled":true,"alwaysRun":false,"continueOnError":false,"timeoutInMinutes":0,"definitionType":"task","overrideInputs":{},"condition":"succeeded()","inputs":{"provider":"azurerm","command":"plan","workingDirectory":"$(System.DefaultWorkingDirectory)/_Terraform Continuous Integration CI Pipeline/terraform-manifests","commandOptions":"-var-file=qa.tfvars","environmentServiceNameAzureRM":"6cf8a51b-70a0-4999-9be3-171f3dcca1b1","environmentServiceNameAWS":"","environmentServiceNameGCP":"","backendServiceArm":"","backendAzureRmResourceGroupName":"","backendAzureRmStorageAccountName":"","backendAzureRmContainerName":"","backendAzureRmKey":"","backendServiceAWS":"","backendAWSBucketName":"","backendAWSKey":"","backendServiceGCP":"","backendGCPBucketName":"","backendGCPPrefix":""}},{"environment":{},"taskId":"fe504acc-6115-40cb-89ff-191386b5e7bf","version":"2.*","name":"Terraform : apply -auto-approve","refName":"","enabled":true,"alwaysRun":false,"continueOnError":false,"timeoutInMinutes":0,"definitionType":"task","overrideInputs":{},"condition":"succeeded()","inputs":{"provider":"azurerm","command":"apply","workingDirectory":"$(System.DefaultWorkingDirectory)/_Terraform Continuous Integration CI Pipeline/terraform-manifests","commandOptions":"-var-file=qa.tfvars -auto-approve","environmentServiceNameAzureRM":"6cf8a51b-70a0-4999-9be3-171f3dcca1b1","environmentServiceNameAWS":"","environmentServiceNameGCP":"","backendServiceArm":"","backendAzureRmResourceGroupName":"","backendAzureRmStorageAccountName":"","backendAzureRmContainerName":"","backendAzureRmKey":"","backendServiceAWS":"","backendAWSBucketName":"","backendAWSKey":"","backendServiceGCP":"","backendGCPBucketName":"","backendGCPPrefix":""}}]}],"environmentOptions":{"emailNotificationType":"OnlyOnFailure","emailRecipients":"release.environment.owner;release.creator","skipArtifactsDownload":false,"timeoutInMinutes":0,"enableAccessToken":false,"publishDeploymentStatus":true,"badgeEnabled":false,"autoLinkWorkItems":false,"pullRequestDeploymentEnabled":false},"demands":[],"conditions":[{"name":"Dev","conditionType":2,"value":"4"}],"executionPolicy":{"concurrencyCount":1,"queueDepthCount":0},"schedules":[],"currentRelease":{"id":7,"url":"https://vsrm.dev.azure.com/stacksimplify1/9a3e7db9-9b55-405d-a8fa-49a65dd823f4/_apis/Release/releases/7","_links":{}},"retentionPolicy":{"daysToKeep":30,"releasesToKeep":3,"retainBuild":true},"processParameters":{},"properties":{"BoardsEnvironmentType":{"$type":"System.String","$value":"unmapped"},"LinkBoardsWorkItems":{"$type":"System.String","$value":"False"}},"preDeploymentGates":{"id":0,"gatesOptions":null,"gates":[]},"postDeploymentGates":{"id":0,"gatesOptions":null,"gates":[]},"environmentTriggers":[],"badgeUrl":"https://vsrm.dev.azure.com/stacksimplify1/_apis/public/Release/badge/9a3e7db9-9b55-405d-a8fa-49a65dd823f4/1/2"},{"id":3,"name":"Stage","rank":3,"owner":{"displayName":"Stack Simplify","url":"https://spsprodsin1.vssps.visualstudio.com/A0e49ef12-3b12-4bce-8402-6d597dfcf044/_apis/Identities/3148445f-5326-6553-95f0-3b2b95341788","_links":{"avatar":{"href":"https://dev.azure.com/stacksimplify1/_apis/GraphProfile/MemberAvatars/msa.MzE0ODQ0NWYtNTMyNi03NTUzLTk1ZjAtM2IyYjk1MzQxNzg4"}},"id":"3148445f-5326-6553-95f0-3b2b95341788","uniqueName":"stacksimplify@gmail.com","imageUrl":"https://dev.azure.com/stacksimplify1/_apis/GraphProfile/MemberAvatars/msa.MzE0ODQ0NWYtNTMyNi03NTUzLTk1ZjAtM2IyYjk1MzQxNzg4","descriptor":"msa.MzE0ODQ0NWYtNTMyNi03NTUzLTk1ZjAtM2IyYjk1MzQxNzg4"},"variables":{},"variableGroups":[],"preDeployApprovals":{"approvals":[{"rank":1,"isAutomated":false,"isNotificationOn":false,"approver":{"displayName":"Stack Simplify","url":"https://spsprodsin1.vssps.visualstudio.com/A0e49ef12-3b12-4bce-8402-6d597dfcf044/_apis/Identities/3148445f-5326-6553-95f0-3b2b95341788","_links":{"avatar":{"href":"https://dev.azure.com/stacksimplify1/_apis/GraphProfile/MemberAvatars/msa.MzE0ODQ0NWYtNTMyNi03NTUzLTk1ZjAtM2IyYjk1MzQxNzg4"}},"id":"3148445f-5326-6553-95f0-3b2b95341788","uniqueName":"stacksimplify@gmail.com","imageUrl":"https://dev.azure.com/stacksimplify1/_apis/GraphProfile/MemberAvatars/msa.MzE0ODQ0NWYtNTMyNi03NTUzLTk1ZjAtM2IyYjk1MzQxNzg4","descriptor":"msa.MzE0ODQ0NWYtNTMyNi03NTUzLTk1ZjAtM2IyYjk1MzQxNzg4"},"id":14}],"approvalOptions":{"requiredApproverCount":null,"releaseCreatorCanBeApprover":true,"autoTriggeredAndPreviousEnvironmentApprovedCanBeSkipped":false,"enforceIdentityRevalidation":false,"timeoutInMinutes":0,"executionOrder":1}},"deployStep":{"id":8},"postDeployApprovals":{"approvals":[{"rank":1,"isAutomated":false,"isNotificationOn":false,"approver":{"displayName":"Stack Simplify","url":"https://spsprodsin1.vssps.visualstudio.com/A0e49ef12-3b12-4bce-8402-6d597dfcf044/_apis/Identities/3148445f-5326-6553-95f0-3b2b95341788","_links":{"avatar":{"href":"https://dev.azure.com/stacksimplify1/_apis/GraphProfile/MemberAvatars/msa.MzE0ODQ0NWYtNTMyNi03NTUzLTk1ZjAtM2IyYjk1MzQxNzg4"}},"id":"3148445f-5326-6553-95f0-3b2b95341788","uniqueName":"stacksimplify@gmail.com","imageUrl":"https://dev.azure.com/stacksimplify1/_apis/GraphProfile/MemberAvatars/msa.MzE0ODQ0NWYtNTMyNi03NTUzLTk1ZjAtM2IyYjk1MzQxNzg4","descriptor":"msa.MzE0ODQ0NWYtNTMyNi03NTUzLTk1ZjAtM2IyYjk1MzQxNzg4"},"id":16}],"approvalOptions":{"requiredApproverCount":null,"releaseCreatorCanBeApprover":true,"autoTriggeredAndPreviousEnvironmentApprovedCanBeSkipped":false,"enforceIdentityRevalidation":false,"timeoutInMinutes":0,"executionOrder":2}},"deployPhases":[{"deploymentInput":{"parallelExecution":{"parallelExecutionType":0},"agentSpecification":{"identifier":"ubuntu-20.04"},"skipArtifactsDownload":false,"artifactsDownloadInput":{"downloadInputs":[]},"queueId":54,"demands":[],"enableAccessToken":false,"timeoutInMinutes":0,"jobCancelTimeoutInMinutes":1,"condition":"succeeded()","overrideInputs":{}},"rank":1,"phaseType":1,"name":"Agent job","refName":null,"workflowTasks":[{"environment":{},"taskId":"a4789e5d-f6e8-431f-add9-379d640a883c","version":"0.*","name":"Install Terraform 1.0.5","refName":"","enabled":true,"alwaysRun":false,"continueOnError":false,"timeoutInMinutes":0,"definitionType":"task","overrideInputs":{},"condition":"succeeded()","inputs":{"terraformVersion":"1.0.5"}},{"environment":{},"taskId":"fe504acc-6115-40cb-89ff-191386b5e7bf","version":"2.*","name":"Terraform : Init","refName":"","enabled":true,"alwaysRun":false,"continueOnError":false,"timeoutInMinutes":0,"definitionType":"task","overrideInputs":{},"condition":"succeeded()","inputs":{"provider":"azurerm","command":"init","workingDirectory":"$(System.DefaultWorkingDirectory)/_Terraform Continuous Integration CI Pipeline/terraform-manifests","commandOptions":"","environmentServiceNameAzureRM":"","environmentServiceNameAWS":"","environmentServiceNameGCP":"","backendServiceArm":"6cf8a51b-70a0-4999-9be3-171f3dcca1b1","backendAzureRmResourceGroupName":"terraform-storage-rg","backendAzureRmStorageAccountName":"terraformstate201","backendAzureRmContainerName":"tfstatefiles","backendAzureRmKey":"stage-terraform.tfstate","backendServiceAWS":"","backendAWSBucketName":"","backendAWSKey":"","backendServiceGCP":"","backendGCPBucketName":"","backendGCPPrefix":""}},{"environment":{},"taskId":"fe504acc-6115-40cb-89ff-191386b5e7bf","version":"2.*","name":"Terraform : validate","refName":"","enabled":true,"alwaysRun":false,"continueOnError":false,"timeoutInMinutes":0,"definitionType":"task","overrideInputs":{},"condition":"succeeded()","inputs":{"provider":"azurerm","command":"validate","workingDirectory":"$(System.DefaultWorkingDirectory)/_Terraform Continuous Integration CI Pipeline/terraform-manifests","commandOptions":"","environmentServiceNameAzureRM":"","environmentServiceNameAWS":"","environmentServiceNameGCP":"","backendServiceArm":"","backendAzureRmResourceGroupName":"","backendAzureRmStorageAccountName":"","backendAzureRmContainerName":"","backendAzureRmKey":"","backendServiceAWS":"","backendAWSBucketName":"","backendAWSKey":"","backendServiceGCP":"","backendGCPBucketName":"","backendGCPPrefix":""}},{"environment":{},"taskId":"fe504acc-6115-40cb-89ff-191386b5e7bf","version":"2.*","name":"Terraform : plan","refName":"","enabled":true,"alwaysRun":false,"continueOnError":false,"timeoutInMinutes":0,"definitionType":"task","overrideInputs":{},"condition":"succeeded()","inputs":{"provider":"azurerm","command":"plan","workingDirectory":"$(System.DefaultWorkingDirectory)/_Terraform Continuous Integration CI Pipeline/terraform-manifests","commandOptions":"-var-file=stage.tfvars","environmentServiceNameAzureRM":"6cf8a51b-70a0-4999-9be3-171f3dcca1b1","environmentServiceNameAWS":"","environmentServiceNameGCP":"","backendServiceArm":"","backendAzureRmResourceGroupName":"","backendAzureRmStorageAccountName":"","backendAzureRmContainerName":"","backendAzureRmKey":"","backendServiceAWS":"","backendAWSBucketName":"","backendAWSKey":"","backendServiceGCP":"","backendGCPBucketName":"","backendGCPPrefix":""}},{"environment":{},"taskId":"fe504acc-6115-40cb-89ff-191386b5e7bf","version":"2.*","name":"Terraform : apply -auto-approve","refName":"","enabled":true,"alwaysRun":false,"continueOnError":false,"timeoutInMinutes":0,"definitionType":"task","overrideInputs":{},"condition":"succeeded()","inputs":{"provider":"azurerm","command":"apply","workingDirectory":"$(System.DefaultWorkingDirectory)/_Terraform Continuous Integration CI Pipeline/terraform-manifests","commandOptions":"-var-file=stage.tfvars -auto-approve","environmentServiceNameAzureRM":"6cf8a51b-70a0-4999-9be3-171f3dcca1b1","environmentServiceNameAWS":"","environmentServiceNameGCP":"","backendServiceArm":"","backendAzureRmResourceGroupName":"","backendAzureRmStorageAccountName":"","backendAzureRmContainerName":"","backendAzureRmKey":"","backendServiceAWS":"","backendAWSBucketName":"","backendAWSKey":"","backendServiceGCP":"","backendGCPBucketName":"","backendGCPPrefix":""}}]}],"environmentOptions":{"emailNotificationType":"OnlyOnFailure","emailRecipients":"release.environment.owner;release.creator","skipArtifactsDownload":false,"timeoutInMinutes":0,"enableAccessToken":false,"publishDeploymentStatus":true,"badgeEnabled":false,"autoLinkWorkItems":false,"pullRequestDeploymentEnabled":false},"demands":[],"conditions":[{"name":"Dev","conditionType":2,"value":"4"}],"executionPolicy":{"concurrencyCount":1,"queueDepthCount":0},"schedules":[],"currentRelease":{"id":7,"url":"https://vsrm.dev.azure.com/stacksimplify1/9a3e7db9-9b55-405d-a8fa-49a65dd823f4/_apis/Release/releases/7","_links":{}},"retentionPolicy":{"daysToKeep":30,"releasesToKeep":3,"retainBuild":true},"processParameters":{},"properties":{"BoardsEnvironmentType":{"$type":"System.String","$value":"testing"},"LinkBoardsWorkItems":{"$type":"System.String","$value":"False"}},"preDeploymentGates":{"id":0,"gatesOptions":null,"gates":[]},"postDeploymentGates":{"id":0,"gatesOptions":null,"gates":[]},"environmentTriggers":[],"badgeUrl":"https://vsrm.dev.azure.com/stacksimplify1/_apis/public/Release/badge/9a3e7db9-9b55-405d-a8fa-49a65dd823f4/1/3"},{"id":4,"name":"Prod","rank":4,"owner":{"displayName":"Stack Simplify","url":"https://spsprodsin1.vssps.visualstudio.com/A0e49ef12-3b12-4bce-8402-6d597dfcf044/_apis/Identities/3148445f-5326-6553-95f0-3b2b95341788","_links":{"avatar":{"href":"https://dev.azure.com/stacksimplify1/_apis/GraphProfile/MemberAvatars/msa.MzE0ODQ0NWYtNTMyNi03NTUzLTk1ZjAtM2IyYjk1MzQxNzg4"}},"id":"3148445f-5326-6553-95f0-3b2b95341788","uniqueName":"stacksimplify@gmail.com","imageUrl":"https://dev.azure.com/stacksimplify1/_apis/GraphProfile/MemberAvatars/msa.MzE0ODQ0NWYtNTMyNi03NTUzLTk1ZjAtM2IyYjk1MzQxNzg4","descriptor":"msa.MzE0ODQ0NWYtNTMyNi03NTUzLTk1ZjAtM2IyYjk1MzQxNzg4"},"variables":{},"variableGroups":[],"preDeployApprovals":{"approvals":[{"rank":1,"isAutomated":false,"isNotificationOn":false,"approver":{"displayName":"Stack Simplify","url":"https://spsprodsin1.vssps.visualstudio.com/A0e49ef12-3b12-4bce-8402-6d597dfcf044/_apis/Identities/3148445f-5326-6553-95f0-3b2b95341788","_links":{"avatar":{"href":"https://dev.azure.com/stacksimplify1/_apis/GraphProfile/MemberAvatars/msa.MzE0ODQ0NWYtNTMyNi03NTUzLTk1ZjAtM2IyYjk1MzQxNzg4"}},"id":"3148445f-5326-6553-95f0-3b2b95341788","uniqueName":"stacksimplify@gmail.com","imageUrl":"https://dev.azure.com/stacksimplify1/_apis/GraphProfile/MemberAvatars/msa.MzE0ODQ0NWYtNTMyNi03NTUzLTk1ZjAtM2IyYjk1MzQxNzg4","descriptor":"msa.MzE0ODQ0NWYtNTMyNi03NTUzLTk1ZjAtM2IyYjk1MzQxNzg4"},"id":15}],"approvalOptions":{"requiredApproverCount":null,"releaseCreatorCanBeApprover":true,"autoTriggeredAndPreviousEnvironmentApprovedCanBeSkipped":false,"enforceIdentityRevalidation":false,"timeoutInMinutes":0,"executionOrder":1}},"deployStep":{"id":11},"postDeployApprovals":{"approvals":[{"rank":1,"isAutomated":true,"isNotificationOn":false,"id":12}],"approvalOptions":{"requiredApproverCount":null,"releaseCreatorCanBeApprover":false,"autoTriggeredAndPreviousEnvironmentApprovedCanBeSkipped":false,"enforceIdentityRevalidation":false,"timeoutInMinutes":0,"executionOrder":2}},"deployPhases":[{"deploymentInput":{"parallelExecution":{"parallelExecutionType":0},"agentSpecification":{"identifier":"ubuntu-20.04"},"skipArtifactsDownload":false,"artifactsDownloadInput":{"downloadInputs":[]},"queueId":54,"demands":[],"enableAccessToken":false,"timeoutInMinutes":0,"jobCancelTimeoutInMinutes":1,"condition":"succeeded()","overrideInputs":{}},"rank":1,"phaseType":1,"name":"Agent job","refName":null,"workflowTasks":[{"environment":{},"taskId":"a4789e5d-f6e8-431f-add9-379d640a883c","version":"0.*","name":"Install Terraform 1.0.5","refName":"","enabled":true,"alwaysRun":false,"continueOnError":false,"timeoutInMinutes":0,"definitionType":"task","overrideInputs":{},"condition":"succeeded()","inputs":{"terraformVersion":"1.0.5"}},{"environment":{},"taskId":"fe504acc-6115-40cb-89ff-191386b5e7bf","version":"2.*","name":"Terraform : Init","refName":"","enabled":true,"alwaysRun":false,"continueOnError":false,"timeoutInMinutes":0,"definitionType":"task","overrideInputs":{},"condition":"succeeded()","inputs":{"provider":"azurerm","command":"init","workingDirectory":"$(System.DefaultWorkingDirectory)/_Terraform Continuous Integration CI Pipeline/terraform-manifests","commandOptions":"","environmentServiceNameAzureRM":"","environmentServiceNameAWS":"","environmentServiceNameGCP":"","backendServiceArm":"6cf8a51b-70a0-4999-9be3-171f3dcca1b1","backendAzureRmResourceGroupName":"terraform-storage-rg","backendAzureRmStorageAccountName":"terraformstate201","backendAzureRmContainerName":"tfstatefiles","backendAzureRmKey":"prod-terraform.tfstate","backendServiceAWS":"","backendAWSBucketName":"","backendAWSKey":"","backendServiceGCP":"","backendGCPBucketName":"","backendGCPPrefix":""}},{"environment":{},"taskId":"fe504acc-6115-40cb-89ff-191386b5e7bf","version":"2.*","name":"Terraform : validate","refName":"","enabled":true,"alwaysRun":false,"continueOnError":false,"timeoutInMinutes":0,"definitionType":"task","overrideInputs":{},"condition":"succeeded()","inputs":{"provider":"azurerm","command":"validate","workingDirectory":"$(System.DefaultWorkingDirectory)/_Terraform Continuous Integration CI Pipeline/terraform-manifests","commandOptions":"","environmentServiceNameAzureRM":"","environmentServiceNameAWS":"","environmentServiceNameGCP":"","backendServiceArm":"","backendAzureRmResourceGroupName":"","backendAzureRmStorageAccountName":"","backendAzureRmContainerName":"","backendAzureRmKey":"","backendServiceAWS":"","backendAWSBucketName":"","backendAWSKey":"","backendServiceGCP":"","backendGCPBucketName":"","backendGCPPrefix":""}},{"environment":{},"taskId":"fe504acc-6115-40cb-89ff-191386b5e7bf","version":"2.*","name":"Terraform : plan","refName":"","enabled":true,"alwaysRun":false,"continueOnError":false,"timeoutInMinutes":0,"definitionType":"task","overrideInputs":{},"condition":"succeeded()","inputs":{"provider":"azurerm","command":"plan","workingDirectory":"$(System.DefaultWorkingDirectory)/_Terraform Continuous Integration CI Pipeline/terraform-manifests","commandOptions":"-var-file=prod.tfvars","environmentServiceNameAzureRM":"6cf8a51b-70a0-4999-9be3-171f3dcca1b1","environmentServiceNameAWS":"","environmentServiceNameGCP":"","backendServiceArm":"","backendAzureRmResourceGroupName":"","backendAzureRmStorageAccountName":"","backendAzureRmContainerName":"","backendAzureRmKey":"","backendServiceAWS":"","backendAWSBucketName":"","backendAWSKey":"","backendServiceGCP":"","backendGCPBucketName":"","backendGCPPrefix":""}},{"environment":{},"taskId":"fe504acc-6115-40cb-89ff-191386b5e7bf","version":"2.*","name":"Terraform : apply -auto-approve","refName":"","enabled":true,"alwaysRun":false,"continueOnError":false,"timeoutInMinutes":0,"definitionType":"task","overrideInputs":{},"condition":"succeeded()","inputs":{"provider":"azurerm","command":"apply","workingDirectory":"$(System.DefaultWorkingDirectory)/_Terraform Continuous Integration CI Pipeline/terraform-manifests","commandOptions":"-var-file=prod.tfvars -auto-approve","environmentServiceNameAzureRM":"6cf8a51b-70a0-4999-9be3-171f3dcca1b1","environmentServiceNameAWS":"","environmentServiceNameGCP":"","backendServiceArm":"","backendAzureRmResourceGroupName":"","backendAzureRmStorageAccountName":"","backendAzureRmContainerName":"","backendAzureRmKey":"","backendServiceAWS":"","backendAWSBucketName":"","backendAWSKey":"","backendServiceGCP":"","backendGCPBucketName":"","backendGCPPrefix":""}}]}],"environmentOptions":{"emailNotificationType":"OnlyOnFailure","emailRecipients":"release.environment.owner;release.creator","skipArtifactsDownload":false,"timeoutInMinutes":0,"enableAccessToken":false,"publishDeploymentStatus":true,"badgeEnabled":false,"autoLinkWorkItems":false,"pullRequestDeploymentEnabled":false},"demands":[],"conditions":[{"name":"Stage","conditionType":2,"value":"4"}],"executionPolicy":{"concurrencyCount":1,"queueDepthCount":0},"schedules":[],"currentRelease":{"id":7,"url":"https://vsrm.dev.azure.com/stacksimplify1/9a3e7db9-9b55-405d-a8fa-49a65dd823f4/_apis/Release/releases/7","_links":{}},"retentionPolicy":{"daysToKeep":30,"releasesToKeep":3,"retainBuild":true},"processParameters":{},"properties":{"BoardsEnvironmentType":{"$type":"System.String","$value":"unmapped"},"LinkBoardsWorkItems":{"$type":"System.String","$value":"False"}},"preDeploymentGates":{"id":0,"gatesOptions":null,"gates":[]},"postDeploymentGates":{"id":0,"gatesOptions":null,"gates":[]},"environmentTriggers":[],"badgeUrl":"https://vsrm.dev.azure.com/stacksimplify1/_apis/public/Release/badge/9a3e7db9-9b55-405d-a8fa-49a65dd823f4/1/4"}],"artifacts":[{"sourceId":"9a3e7db9-9b55-405d-a8fa-49a65dd823f4:7","type":"Build","alias":"_Terraform Continuous Integration CI Pipeline","definitionReference":{"artifactSourceDefinitionUrl":{"id":"https://dev.azure.com/stacksimplify1/_permalink/_build/index?collectionId=457d86fd-6242-404a-af3c-c96b162f2dc2&projectId=9a3e7db9-9b55-405d-a8fa-49a65dd823f4&definitionId=7","name":""},"defaultVersionBranch":{"id":"","name":""},"defaultVersionSpecific":{"id":"","name":""},"defaultVersionTags":{"id":"","name":""},"defaultVersionType":{"id":"latestType","name":"Latest"},"definition":{"id":"7","name":"Terraform Continuous Integration CI Pipeline"},"definitions":{"id":"","name":""},"IsMultiDefinitionType":{"id":"False","name":"False"},"project":{"id":"9a3e7db9-9b55-405d-a8fa-49a65dd823f4","name":"terraform-on-azure-with-azure-devops-internal"},"repository":{"id":"","name":""}},"isPrimary":true,"isRetained":false}],"triggers":[{"artifactAlias":"_Terraform Continuous Integration CI Pipeline","triggerConditions":[],"triggerType":1}],"releaseNameFormat":"Release-$(rev:r)","tags":[],"properties":{"DefinitionCreationSource":{"$type":"System.String","$value":"ReleaseNew"},"IntegrateBoardsWorkItems":{"$type":"System.String","$value":"False"},"IntegrateJiraWorkItems":{"$type":"System.String","$value":"false"}},"id":1,"name":"Terraform-CD","path":"\\","projectReference":null,"url":"https://vsrm.dev.azure.com/stacksimplify1/9a3e7db9-9b55-405d-a8fa-49a65dd823f4/_apis/Release/definitions/1","_links":{"self":{"href":"https://vsrm.dev.azure.com/stacksimplify1/9a3e7db9-9b55-405d-a8fa-49a65dd823f4/_apis/Release/definitions/1"},"web":{"href":"https://dev.azure.com/stacksimplify1/9a3e7db9-9b55-405d-a8fa-49a65dd823f4/_release?definitionId=1"}}} -------------------------------------------------------------------------------- /terraform-manifests/.terraform.lock.hcl: -------------------------------------------------------------------------------- 1 | # This file is maintained automatically by "terraform init". 2 | # Manual edits may be lost in future updates. 3 | 4 | provider "registry.terraform.io/hashicorp/azurerm" { 5 | version = "2.74.0" 6 | constraints = ">= 2.0.0" 7 | hashes = [ 8 | "h1:gmx4I8DTW9RsSFCigIKR2XSdDM+fyPoQNrUDvDnwp8w=", 9 | "h1:mVJLx0z3IFBM94jJPbzXajRyhh5xUHtuflp/Xtue104=", 10 | "h1:pcfiBvZI14svYXQ3/392OpagPWoQoNhzIqNg6gm7UuY=", 11 | "zh:39770dfaaa2281ed0c8e620b9013ef96d45bc88a12ffff9df470b2da7c6f41df", 12 | "zh:487d6920d1bc28cfda310dff43e0038e6621409b8746ca1d2937c177743d6194", 13 | "zh:6b7f8224c63689e62e0178c7cf9fb21374ae840d646fe065c0b61902c77448df", 14 | "zh:9e4810b85438905e417da01814dc2203a0e904d74b89f1d0330869ab71f88eaf", 15 | "zh:ab09186cc1b7d4d92d0d85cd9f77dfb9d7b98992badb433156e5bf179c508bcd", 16 | "zh:b9f11c240b05cfdd8b10da35848f269c16a8a0a2e6dfaaaf3982c6f4d9591266", 17 | "zh:be35031ede79f8ab10fca9448def6b12ac1a81a748b1607f28345e7c341a9ad6", 18 | "zh:caeaf6c93120df4f461d75d9f00c4ea493b3cd910e5d426dca34f74a27d36474", 19 | "zh:d5e5eeafb61e8bb710f9f364a0352e38d783ca4584968bd0311a647bad9e84c1", 20 | "zh:deda32842c89c5999148bfa045e0f9b0a17e7bd618c22ceb9dadb79f88d8c1f0", 21 | "zh:ec7a4960b9960cd917fd727c9805afd23a48c5c6f5263701f8ef72f1107ed657", 22 | ] 23 | } 24 | 25 | provider "registry.terraform.io/hashicorp/null" { 26 | version = "3.1.0" 27 | constraints = ">= 3.0.0" 28 | hashes = [ 29 | "h1:SFT7X3zY18CLWjoH2GfQyapxsRv6GDKsy9cF1aRwncc=", 30 | "h1:vpC6bgUQoJ0znqIKVFevOdq+YQw42bRq0u+H3nto8nA=", 31 | "h1:xhbHC6in3nQryvTQBWKxebi3inG5OCgHgc4fRxL0ymc=", 32 | "zh:02a1675fd8de126a00460942aaae242e65ca3380b5bb192e8773ef3da9073fd2", 33 | "zh:53e30545ff8926a8e30ad30648991ca8b93b6fa496272cd23b26763c8ee84515", 34 | "zh:5f9200bf708913621d0f6514179d89700e9aa3097c77dac730e8ba6e5901d521", 35 | "zh:9ebf4d9704faba06b3ec7242c773c0fbfe12d62db7d00356d4f55385fc69bfb2", 36 | "zh:a6576c81adc70326e4e1c999c04ad9ca37113a6e925aefab4765e5a5198efa7e", 37 | "zh:a8a42d13346347aff6c63a37cda9b2c6aa5cc384a55b2fe6d6adfa390e609c53", 38 | "zh:c797744d08a5307d50210e0454f91ca4d1c7621c68740441cf4579390452321d", 39 | "zh:cecb6a304046df34c11229f20a80b24b1603960b794d68361a67c5efe58e62b8", 40 | "zh:e1371aa1e502000d9974cfaff5be4cfa02f47b17400005a16f14d2ef30dc2a70", 41 | "zh:fc39cc1fe71234a0b0369d5c5c7f876c71b956d23d7d6f518289737a001ba69b", 42 | "zh:fea4227271ebf7d9e2b61b89ce2328c7262acd9fd190e1fd6d15a591abfa848e", 43 | ] 44 | } 45 | 46 | provider "registry.terraform.io/hashicorp/random" { 47 | version = "3.1.0" 48 | constraints = ">= 3.0.0" 49 | hashes = [ 50 | "h1:BZMEPucF+pbu9gsPk0G0BHx7YP04+tKdq2MrRDF1EDM=", 51 | "h1:EPIax4Ftp2SNdB9pUfoSjxoueDoLc/Ck3EUoeX0Dvsg=", 52 | "h1:rKYu5ZUbXwrLG1w81k7H3nce/Ys6yAxXhWcbtk36HjY=", 53 | "zh:2bbb3339f0643b5daa07480ef4397bd23a79963cc364cdfbb4e86354cb7725bc", 54 | "zh:3cd456047805bf639fbf2c761b1848880ea703a054f76db51852008b11008626", 55 | "zh:4f251b0eda5bb5e3dc26ea4400dba200018213654b69b4a5f96abee815b4f5ff", 56 | "zh:7011332745ea061e517fe1319bd6c75054a314155cb2c1199a5b01fe1889a7e2", 57 | "zh:738ed82858317ccc246691c8b85995bc125ac3b4143043219bd0437adc56c992", 58 | "zh:7dbe52fac7bb21227acd7529b487511c91f4107db9cc4414f50d04ffc3cab427", 59 | "zh:a3a9251fb15f93e4cfc1789800fc2d7414bbc18944ad4c5c98f466e6477c42bc", 60 | "zh:a543ec1a3a8c20635cf374110bd2f87c07374cf2c50617eee2c669b3ceeeaa9f", 61 | "zh:d9ab41d556a48bd7059f0810cf020500635bfc696c9fc3adab5ea8915c1d886b", 62 | "zh:d9e13427a7d011dbd654e591b0337e6074eef8c3b9bb11b2e39eaaf257044fd7", 63 | "zh:f7605bd1437752114baf601bdf6931debe6dc6bfe3006eb7e9bb9080931dca8a", 64 | ] 65 | } 66 | -------------------------------------------------------------------------------- /terraform-manifests/c1-versions.tf: -------------------------------------------------------------------------------- 1 | # Terraform Block 2 | terraform { 3 | required_version = ">= 1.0.0" 4 | required_providers { 5 | azurerm = { 6 | source = "hashicorp/azurerm" 7 | version = ">= 2.0" 8 | } 9 | random = { 10 | source = "hashicorp/random" 11 | version = ">= 3.0" 12 | } 13 | null = { 14 | source = "hashicorp/null" 15 | version = ">= 3.0" 16 | } 17 | } 18 | # Terraform State Storage to Azure Storage Container (Values will be taken from Azure DevOps) 19 | backend "azurerm" { 20 | 21 | } 22 | } 23 | 24 | # Provider Block 25 | provider "azurerm" { 26 | features {} 27 | } 28 | 29 | # Simple comment 30 | # QA, Stage and Prod env added 31 | 32 | 33 | -------------------------------------------------------------------------------- /terraform-manifests/c2-generic-input-variables.tf: -------------------------------------------------------------------------------- 1 | # Generic Input Variables 2 | # Business Division 3 | variable "business_divsion" { 4 | description = "Business Division in the large organization this Infrastructure belongs" 5 | type = string 6 | default = "sap" 7 | } 8 | # Environment Variable 9 | variable "environment" { 10 | description = "Environment Variable used as a prefix" 11 | type = string 12 | default = "dev" 13 | } 14 | 15 | # Azure Resource Group Name 16 | variable "resource_group_name" { 17 | description = "Resource Group Name" 18 | type = string 19 | default = "rg-default" 20 | } 21 | 22 | # Azure Resources Location 23 | variable "resource_group_location" { 24 | description = "Region in which Azure Resources to be created" 25 | type = string 26 | default = "eastus2" 27 | } 28 | 29 | -------------------------------------------------------------------------------- /terraform-manifests/c3-locals.tf: -------------------------------------------------------------------------------- 1 | # Define Local Values in Terraform 2 | locals { 3 | owners = var.business_divsion 4 | environment = var.environment 5 | resource_name_prefix = "${var.business_divsion}-${var.environment}" 6 | #name = "${local.owners}-${local.environment}" 7 | common_tags = { 8 | owners = local.owners 9 | environment = local.environment 10 | } 11 | } -------------------------------------------------------------------------------- /terraform-manifests/c4-random-resources.tf: -------------------------------------------------------------------------------- 1 | # Random String Resource 2 | resource "random_string" "myrandom" { 3 | length = 6 4 | upper = false 5 | special = false 6 | number = false 7 | } 8 | -------------------------------------------------------------------------------- /terraform-manifests/c5-resource-group.tf: -------------------------------------------------------------------------------- 1 | # Resource-1: Azure Resource Group 2 | resource "azurerm_resource_group" "rg" { 3 | # name = "${local.resource_name_prefix}-${var.resource_group_name}" 4 | name = "${local.resource_name_prefix}-${var.resource_group_name}-${random_string.myrandom.id}" 5 | location = var.resource_group_location 6 | tags = local.common_tags 7 | } 8 | -------------------------------------------------------------------------------- /terraform-manifests/c6-01-vnet-input-variables.tf: -------------------------------------------------------------------------------- 1 | # Virtual Network, Subnets and Subnet NSG's 2 | 3 | ## Virtual Network 4 | variable "vnet_name" { 5 | description = "Virtual Network name" 6 | type = string 7 | default = "vnet-default" 8 | } 9 | variable "vnet_address_space" { 10 | description = "Virtual Network address_space" 11 | type = list(string) 12 | default = ["10.0.0.0/16"] 13 | } 14 | 15 | 16 | # Web Subnet Name 17 | variable "web_subnet_name" { 18 | description = "Virtual Network Web Subnet Name" 19 | type = string 20 | default = "websubnet" 21 | } 22 | # Web Subnet Address Space 23 | variable "web_subnet_address" { 24 | description = "Virtual Network Web Subnet Address Spaces" 25 | type = list(string) 26 | default = ["10.0.1.0/24"] 27 | } 28 | 29 | 30 | # App Subnet Name 31 | variable "app_subnet_name" { 32 | description = "Virtual Network App Subnet Name" 33 | type = string 34 | default = "appsubnet" 35 | } 36 | # App Subnet Address Space 37 | variable "app_subnet_address" { 38 | description = "Virtual Network App Subnet Address Spaces" 39 | type = list(string) 40 | default = ["10.0.11.0/24"] 41 | } 42 | 43 | 44 | # Database Subnet Name 45 | variable "db_subnet_name" { 46 | description = "Virtual Network Database Subnet Name" 47 | type = string 48 | default = "dbsubnet" 49 | } 50 | # Database Subnet Address Space 51 | variable "db_subnet_address" { 52 | description = "Virtual Network Database Subnet Address Spaces" 53 | type = list(string) 54 | default = ["10.0.21.0/24"] 55 | } 56 | 57 | 58 | # Bastion / Management Subnet Name 59 | variable "bastion_subnet_name" { 60 | description = "Virtual Network Bastion Subnet Name" 61 | type = string 62 | default = "bastionsubnet" 63 | } 64 | # Bastion / Management Subnet Address Space 65 | variable "bastion_subnet_address" { 66 | description = "Virtual Network Bastion Subnet Address Spaces" 67 | type = list(string) 68 | default = ["10.0.100.0/24"] 69 | } 70 | 71 | 72 | 73 | -------------------------------------------------------------------------------- /terraform-manifests/c6-02-virtual-network.tf: -------------------------------------------------------------------------------- 1 | # Create Virtual Network 2 | resource "azurerm_virtual_network" "vnet" { 3 | name = "${local.resource_name_prefix}-${var.vnet_name}" 4 | address_space = var.vnet_address_space 5 | location = azurerm_resource_group.rg.location 6 | resource_group_name = azurerm_resource_group.rg.name 7 | tags = local.common_tags 8 | } 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | -------------------------------------------------------------------------------- /terraform-manifests/c6-03-web-subnet-and-nsg.tf: -------------------------------------------------------------------------------- 1 | # Resource-1: Create WebTier Subnet 2 | resource "azurerm_subnet" "websubnet" { 3 | name = "${azurerm_virtual_network.vnet.name}-${var.web_subnet_name}" 4 | resource_group_name = azurerm_resource_group.rg.name 5 | virtual_network_name = azurerm_virtual_network.vnet.name 6 | address_prefixes = var.web_subnet_address 7 | } 8 | 9 | # Resource-2: Create Network Security Group (NSG) 10 | resource "azurerm_network_security_group" "web_subnet_nsg" { 11 | name = "${azurerm_subnet.websubnet.name}-nsg" 12 | location = azurerm_resource_group.rg.location 13 | resource_group_name = azurerm_resource_group.rg.name 14 | } 15 | 16 | # Resource-3: Associate NSG and Subnet 17 | resource "azurerm_subnet_network_security_group_association" "web_subnet_nsg_associate" { 18 | depends_on = [ azurerm_network_security_rule.web_nsg_rule_inbound] # Every NSG Rule Association will disassociate NSG from Subnet and Associate it, so we associate it only after NSG is completely created - Azure Provider Bug https://github.com/terraform-providers/terraform-provider-azurerm/issues/354 19 | subnet_id = azurerm_subnet.websubnet.id 20 | network_security_group_id = azurerm_network_security_group.web_subnet_nsg.id 21 | } 22 | 23 | # Resource-4: Create NSG Rules 24 | ## Locals Block for Security Rules 25 | locals { 26 | web_inbound_ports_map = { 27 | "100" : "80", # If the key starts with a number, you must use the colon syntax ":" instead of "=" 28 | "110" : "443", 29 | "120" : "22" 30 | } 31 | } 32 | ## NSG Inbound Rule for WebTier Subnets 33 | resource "azurerm_network_security_rule" "web_nsg_rule_inbound" { 34 | for_each = local.web_inbound_ports_map 35 | name = "Rule-Port-${each.value}" 36 | priority = each.key 37 | direction = "Inbound" 38 | access = "Allow" 39 | protocol = "Tcp" 40 | source_port_range = "*" 41 | destination_port_range = each.value 42 | source_address_prefix = "*" 43 | destination_address_prefix = "*" 44 | resource_group_name = azurerm_resource_group.rg.name 45 | network_security_group_name = azurerm_network_security_group.web_subnet_nsg.name 46 | } 47 | 48 | 49 | -------------------------------------------------------------------------------- /terraform-manifests/c6-04-app-subnet-and-nsg.tf: -------------------------------------------------------------------------------- 1 | # Resource-1: Create AppTier Subnet 2 | resource "azurerm_subnet" "appsubnet" { 3 | name = "${azurerm_virtual_network.vnet.name}-${var.app_subnet_name}" 4 | resource_group_name = azurerm_resource_group.rg.name 5 | virtual_network_name = azurerm_virtual_network.vnet.name 6 | address_prefixes = var.app_subnet_address 7 | } 8 | 9 | # Resource-2: Create Network Security Group (NSG) 10 | resource "azurerm_network_security_group" "app_subnet_nsg" { 11 | name = "${azurerm_subnet.appsubnet.name}-nsg" 12 | location = azurerm_resource_group.rg.location 13 | resource_group_name = azurerm_resource_group.rg.name 14 | } 15 | 16 | # Resource-3: Associate NSG and Subnet 17 | resource "azurerm_subnet_network_security_group_association" "app_subnet_nsg_associate" { 18 | depends_on = [ azurerm_network_security_rule.app_nsg_rule_inbound] 19 | subnet_id = azurerm_subnet.appsubnet.id 20 | network_security_group_id = azurerm_network_security_group.app_subnet_nsg.id 21 | } 22 | 23 | # Resource-4: Create NSG Rules 24 | ## Locals Block for Security Rules 25 | locals { 26 | app_inbound_ports_map = { 27 | "100" : "80", # If the key starts with a number, you must use the colon syntax ":" instead of "=" 28 | "110" : "443", 29 | "120" : "8080", 30 | "130" : "22" 31 | } 32 | } 33 | ## NSG Inbound Rule for AppTier Subnets 34 | resource "azurerm_network_security_rule" "app_nsg_rule_inbound" { 35 | for_each = local.app_inbound_ports_map 36 | name = "Rule-Port-${each.value}" 37 | priority = each.key 38 | direction = "Inbound" 39 | access = "Allow" 40 | protocol = "Tcp" 41 | source_port_range = "*" 42 | destination_port_range = each.value 43 | source_address_prefix = "*" 44 | destination_address_prefix = "*" 45 | resource_group_name = azurerm_resource_group.rg.name 46 | network_security_group_name = azurerm_network_security_group.app_subnet_nsg.name 47 | } 48 | 49 | 50 | -------------------------------------------------------------------------------- /terraform-manifests/c6-05-db-subnet-and-nsg.tf: -------------------------------------------------------------------------------- 1 | # Resource-1: Create DBTier Subnet 2 | resource "azurerm_subnet" "dbsubnet" { 3 | name = "${azurerm_virtual_network.vnet.name}-${var.db_subnet_name}" 4 | resource_group_name = azurerm_resource_group.rg.name 5 | virtual_network_name = azurerm_virtual_network.vnet.name 6 | address_prefixes = var.db_subnet_address 7 | } 8 | 9 | # Resource-2: Create Network Security Group (NSG) 10 | resource "azurerm_network_security_group" "db_subnet_nsg" { 11 | name = "${azurerm_subnet.dbsubnet.name}-nsg" 12 | location = azurerm_resource_group.rg.location 13 | resource_group_name = azurerm_resource_group.rg.name 14 | } 15 | 16 | # Resource-3: Associate NSG and Subnet 17 | resource "azurerm_subnet_network_security_group_association" "db_subnet_nsg_associate" { 18 | depends_on = [ azurerm_network_security_rule.db_nsg_rule_inbound] 19 | subnet_id = azurerm_subnet.dbsubnet.id 20 | network_security_group_id = azurerm_network_security_group.db_subnet_nsg.id 21 | } 22 | 23 | # Resource-4: Create NSG Rules 24 | ## Locals Block for Security Rules 25 | locals { 26 | db_inbound_ports_map = { 27 | "100" : "3306", # If the key starts with a number, you must use the colon syntax ":" instead of "=" 28 | "110" : "1433", 29 | "120" : "5432" 30 | } 31 | } 32 | ## NSG Inbound Rule for DBTier Subnets 33 | resource "azurerm_network_security_rule" "db_nsg_rule_inbound" { 34 | for_each = local.db_inbound_ports_map 35 | name = "Rule-Port-${each.value}" 36 | priority = each.key 37 | direction = "Inbound" 38 | access = "Allow" 39 | protocol = "Tcp" 40 | source_port_range = "*" 41 | destination_port_range = each.value 42 | source_address_prefix = "*" 43 | destination_address_prefix = "*" 44 | resource_group_name = azurerm_resource_group.rg.name 45 | network_security_group_name = azurerm_network_security_group.db_subnet_nsg.name 46 | } 47 | 48 | 49 | -------------------------------------------------------------------------------- /terraform-manifests/c6-06-bastion-subnet-and-nsg.tf: -------------------------------------------------------------------------------- 1 | # Resource-1: Create Bastion / Management Subnet 2 | resource "azurerm_subnet" "bastionsubnet" { 3 | name = "${azurerm_virtual_network.vnet.name}-${var.bastion_subnet_name}" 4 | resource_group_name = azurerm_resource_group.rg.name 5 | virtual_network_name = azurerm_virtual_network.vnet.name 6 | address_prefixes = var.bastion_subnet_address 7 | } 8 | 9 | # Resource-2: Create Network Security Group (NSG) 10 | resource "azurerm_network_security_group" "bastion_subnet_nsg" { 11 | name = "${azurerm_subnet.bastionsubnet.name}-nsg" 12 | location = azurerm_resource_group.rg.location 13 | resource_group_name = azurerm_resource_group.rg.name 14 | } 15 | 16 | # Resource-3: Associate NSG and Subnet 17 | resource "azurerm_subnet_network_security_group_association" "bastion_subnet_nsg_associate" { 18 | depends_on = [ azurerm_network_security_rule.bastion_nsg_rule_inbound] 19 | subnet_id = azurerm_subnet.bastionsubnet.id 20 | network_security_group_id = azurerm_network_security_group.bastion_subnet_nsg.id 21 | } 22 | 23 | # Resource-4: Create NSG Rules 24 | ## Locals Block for Security Rules 25 | locals { 26 | bastion_inbound_ports_map = { 27 | "100" : "22", # If the key starts with a number, you must use the colon syntax ":" instead of "=" 28 | "110" : "3389" 29 | } 30 | } 31 | ## NSG Inbound Rule for Bastion / Management Subnets 32 | resource "azurerm_network_security_rule" "bastion_nsg_rule_inbound" { 33 | for_each = local.bastion_inbound_ports_map 34 | name = "Rule-Port-${each.value}" 35 | priority = each.key 36 | direction = "Inbound" 37 | access = "Allow" 38 | protocol = "Tcp" 39 | source_port_range = "*" 40 | destination_port_range = each.value 41 | source_address_prefix = "*" 42 | destination_address_prefix = "*" 43 | resource_group_name = azurerm_resource_group.rg.name 44 | network_security_group_name = azurerm_network_security_group.bastion_subnet_nsg.name 45 | } 46 | 47 | 48 | -------------------------------------------------------------------------------- /terraform-manifests/c6-07-vnet-outputs.tf: -------------------------------------------------------------------------------- 1 | # Virtual Network Outputs 2 | ## Virtual Network Name 3 | output "virtual_network_name" { 4 | description = "Virtual Network Name" 5 | value = azurerm_virtual_network.vnet.name 6 | } 7 | ## Virtual Network ID 8 | output "virtual_network_id" { 9 | description = "Virtual Network ID" 10 | value = azurerm_virtual_network.vnet.id 11 | } 12 | 13 | # Subnet Outputs (We will write for one web subnet and rest all we will ignore for now) 14 | ## Subnet Name 15 | output "web_subnet_name" { 16 | description = "WebTier Subnet Name" 17 | value = azurerm_subnet.websubnet.name 18 | } 19 | 20 | ## Subnet ID 21 | output "web_subnet_id" { 22 | description = "WebTier Subnet ID" 23 | value = azurerm_subnet.websubnet.id 24 | } 25 | 26 | # Network Security Outputs 27 | ## Web Subnet NSG Name 28 | output "web_subnet_nsg_name" { 29 | description = "WebTier Subnet NSG Name" 30 | value = azurerm_network_security_group.web_subnet_nsg.name 31 | } 32 | 33 | ## Web Subnet NSG ID 34 | output "web_subnet_nsg_id" { 35 | description = "WebTier Subnet NSG ID" 36 | value = azurerm_network_security_group.web_subnet_nsg.id 37 | } 38 | -------------------------------------------------------------------------------- /terraform-manifests/c7-01-web-linuxvm-input-variables.tf: -------------------------------------------------------------------------------- 1 | # Linux VM Input Variables Placeholder file. 2 | variable "web_linuxvm_size" { 3 | description = "Web Linux VM Size" 4 | type = string 5 | default = "Standard_DS1_v2" 6 | } 7 | 8 | variable "web_linuxvm_admin_user" { 9 | description = "Web Linux VM Admin Username" 10 | type = string 11 | default = "azureuser" 12 | } -------------------------------------------------------------------------------- /terraform-manifests/c7-02-web-linuxvm-publicip.tf: -------------------------------------------------------------------------------- 1 | # Resource-1: Create Public IP Address 2 | resource "azurerm_public_ip" "web_linuxvm_publicip" { 3 | name = "${local.resource_name_prefix}-web-linuxvm-publicip" 4 | resource_group_name = azurerm_resource_group.rg.name 5 | location = azurerm_resource_group.rg.location 6 | allocation_method = "Static" 7 | sku = "Standard" 8 | domain_name_label = "app1-vm-${random_string.myrandom.id}" 9 | } 10 | 11 | -------------------------------------------------------------------------------- /terraform-manifests/c7-03-web-linuxvm-network-interface.tf: -------------------------------------------------------------------------------- 1 | # Resource-2: Create Network Interface 2 | resource "azurerm_network_interface" "web_linuxvm_nic" { 3 | name = "${local.resource_name_prefix}-web-linuxvm-nic" 4 | location = azurerm_resource_group.rg.location 5 | resource_group_name = azurerm_resource_group.rg.name 6 | 7 | ip_configuration { 8 | name = "web-linuxvm-ip-1" 9 | subnet_id = azurerm_subnet.websubnet.id 10 | private_ip_address_allocation = "Dynamic" 11 | public_ip_address_id = azurerm_public_ip.web_linuxvm_publicip.id 12 | } 13 | } 14 | 15 | -------------------------------------------------------------------------------- /terraform-manifests/c7-04-web-linuxvm-network-security-group.tf: -------------------------------------------------------------------------------- 1 | /* 2 | # Resource-3 (Optional): Create Network Security Group and Associate to Linux VM Network Interface 3 | # Resource-1: Create Network Security Group (NSG) 4 | resource "azurerm_network_security_group" "web_vmnic_nsg" { 5 | name = "${azurerm_network_interface.web_linuxvm_nic.name}-nsg" 6 | location = azurerm_resource_group.rg.location 7 | resource_group_name = azurerm_resource_group.rg.name 8 | } 9 | 10 | # Resource-2: Associate NSG and Linux VM NIC 11 | resource "azurerm_network_interface_security_group_association" "web_vmnic_nsg_associate" { 12 | depends_on = [ azurerm_network_security_rule.web_vmnic_nsg_rule_inbound] 13 | network_interface_id = azurerm_network_interface.web_linuxvm_nic.id 14 | network_security_group_id = azurerm_network_security_group.web_vmnic_nsg.id 15 | } 16 | 17 | # Resource-3: Create NSG Rules 18 | ## Locals Block for Security Rules 19 | locals { 20 | web_vmnic_inbound_ports_map = { 21 | "100" : "80", # If the key starts with a number, you must use the colon syntax ":" instead of "=" 22 | "110" : "443", 23 | "120" : "22" 24 | } 25 | } 26 | ## NSG Inbound Rule for WebTier Subnets 27 | resource "azurerm_network_security_rule" "web_vmnic_nsg_rule_inbound" { 28 | for_each = local.web_vmnic_inbound_ports_map 29 | name = "Rule-Port-${each.value}" 30 | priority = each.key 31 | direction = "Inbound" 32 | access = "Allow" 33 | protocol = "Tcp" 34 | source_port_range = "*" 35 | destination_port_range = each.value 36 | source_address_prefix = "*" 37 | destination_address_prefix = "*" 38 | resource_group_name = azurerm_resource_group.rg.name 39 | network_security_group_name = azurerm_network_security_group.web_vmnic_nsg.name 40 | } 41 | */ 42 | 43 | 44 | 45 | -------------------------------------------------------------------------------- /terraform-manifests/c7-05-web-linuxvm-resource.tf: -------------------------------------------------------------------------------- 1 | # Locals Block for custom data 2 | locals { 3 | webvm_custom_data = < /var/www/html/index.html 13 | sudo mkdir /var/www/html/app1 14 | sudo echo "Welcome to stacksimplify - WebVM App1 - VM Hostname: $(hostname)" > /var/www/html/app1/hostname.html 15 | sudo echo "Welcome to stacksimplify - WebVM App1 - App Status Page" > /var/www/html/app1/status.html 16 | sudo echo '

Welcome to Stack Simplify - WebVM APP-1

Terraform Demo

Application Version: V1

' | sudo tee /var/www/html/app1/index.html 17 | sudo curl -H "Metadata:true" --noproxy "*" "http://169.254.169.254/metadata/instance?api-version=2020-09-01" -o /var/www/html/app1/metadata.html 18 | CUSTOM_DATA 19 | } 20 | 21 | 22 | # Resource: Azure Linux Virtual Machine 23 | resource "azurerm_linux_virtual_machine" "web_linuxvm" { 24 | name = "${local.resource_name_prefix}-web-linuxvm" 25 | #computer_name = "web-linux-vm" # Hostname of the VM (Optional) 26 | resource_group_name = azurerm_resource_group.rg.name 27 | location = azurerm_resource_group.rg.location 28 | size = var.web_linuxvm_size 29 | admin_username = var.web_linuxvm_admin_user 30 | network_interface_ids = [ azurerm_network_interface.web_linuxvm_nic.id ] 31 | admin_ssh_key { 32 | username = var.web_linuxvm_admin_user 33 | public_key = file("${path.module}/ssh-keys/terraform-azure.pub") 34 | } 35 | os_disk { 36 | caching = "ReadWrite" 37 | storage_account_type = "Standard_LRS" 38 | } 39 | source_image_reference { 40 | publisher = "RedHat" 41 | offer = "RHEL" 42 | sku = "83-gen2" 43 | version = "latest" 44 | } 45 | #custom_data = filebase64("${path.module}/app-scripts/redhat-webvm-script.sh") 46 | custom_data = base64encode(local.webvm_custom_data) 47 | } 48 | -------------------------------------------------------------------------------- /terraform-manifests/c7-06-web-linuxvm-outputs.tf: -------------------------------------------------------------------------------- 1 | ## Public IP Address 2 | output "web_linuxvm_public_ip" { 3 | description = "Web Linux VM Public Address" 4 | value = azurerm_public_ip.web_linuxvm_publicip.ip_address 5 | } 6 | 7 | # Network Interface Outputs 8 | ## Network Interface ID 9 | output "web_linuxvm_network_interface_id" { 10 | description = "Web Linux VM Network Interface ID" 11 | value = azurerm_network_interface.web_linuxvm_nic.id 12 | } 13 | ## Network Interface Private IP Addresses 14 | output "web_linuxvm_network_interface_private_ip_addresses" { 15 | description = "Web Linux VM Private IP Addresses" 16 | value = [azurerm_network_interface.web_linuxvm_nic.private_ip_addresses] 17 | } 18 | 19 | # Linux VM Outputs 20 | 21 | ## Virtual Machine Public IP 22 | output "web_linuxvm_public_ip_address" { 23 | description = "Web Linux Virtual Machine Public IP" 24 | value = azurerm_linux_virtual_machine.web_linuxvm.public_ip_address 25 | } 26 | 27 | 28 | ## Virtual Machine Private IP 29 | output "web_linuxvm_private_ip_address" { 30 | description = "Web Linux Virtual Machine Private IP" 31 | value = azurerm_linux_virtual_machine.web_linuxvm.private_ip_address 32 | } 33 | ## Virtual Machine 128-bit ID 34 | output "web_linuxvm_virtual_machine_id_128bit" { 35 | description = "Web Linux Virtual Machine ID - 128-bit identifier" 36 | value = azurerm_linux_virtual_machine.web_linuxvm.virtual_machine_id 37 | } 38 | ## Virtual Machine ID 39 | output "web_linuxvm_virtual_machine_id" { 40 | description = "Web Linux Virtual Machine ID " 41 | value = azurerm_linux_virtual_machine.web_linuxvm.id 42 | } 43 | 44 | 45 | 46 | 47 | -------------------------------------------------------------------------------- /terraform-manifests/dev.tfvars: -------------------------------------------------------------------------------- 1 | # Environment Name 2 | environment = "dev" 3 | 4 | # Virtual Network Variables 5 | vnet_name = "vnet" 6 | vnet_address_space = ["10.1.0.0/16"] 7 | 8 | web_subnet_name = "websubnet" 9 | web_subnet_address = ["10.1.1.0/24"] 10 | 11 | app_subnet_name = "appsubnet" 12 | app_subnet_address = ["10.1.11.0/24"] 13 | 14 | db_subnet_name = "dbsubnet" 15 | db_subnet_address = ["10.1.21.0/24"] 16 | 17 | bastion_subnet_name = "bastionsubnet" 18 | bastion_subnet_address = ["10.1.100.0/24"] 19 | 20 | # Web Linux VM Variables 21 | web_linuxvm_size = "Standard_DS1_v2" 22 | web_linuxvm_admin_user = "azureuser" -------------------------------------------------------------------------------- /terraform-manifests/prod.tfvars: -------------------------------------------------------------------------------- 1 | # Environment Name 2 | environment = "prod" 3 | 4 | # Virtual Network Variables 5 | vnet_name = "vnet" 6 | vnet_address_space = ["10.4.0.0/16"] 7 | 8 | web_subnet_name = "websubnet" 9 | web_subnet_address = ["10.4.1.0/24"] 10 | 11 | app_subnet_name = "appsubnet" 12 | app_subnet_address = ["10.4.11.0/24"] 13 | 14 | db_subnet_name = "dbsubnet" 15 | db_subnet_address = ["10.4.21.0/24"] 16 | 17 | bastion_subnet_name = "bastionsubnet" 18 | bastion_subnet_address = ["10.4.100.0/24"] 19 | 20 | # Web Linux VM Variables 21 | web_linuxvm_size = "Standard_DS1_v2" 22 | web_linuxvm_admin_user = "azureuser" 23 | #web_linuxvm_admin_user = "produser" # Enable during step-22 24 | -------------------------------------------------------------------------------- /terraform-manifests/qa.tfvars: -------------------------------------------------------------------------------- 1 | # Environment Name 2 | environment = "qa" 3 | 4 | # Virtual Network Variables 5 | vnet_name = "vnet" 6 | vnet_address_space = ["10.2.0.0/16"] 7 | 8 | web_subnet_name = "websubnet" 9 | web_subnet_address = ["10.2.1.0/24"] 10 | 11 | app_subnet_name = "appsubnet" 12 | app_subnet_address = ["10.2.11.0/24"] 13 | 14 | db_subnet_name = "dbsubnet" 15 | db_subnet_address = ["10.2.21.0/24"] 16 | 17 | bastion_subnet_name = "bastionsubnet" 18 | bastion_subnet_address = ["10.2.100.0/24"] 19 | 20 | # Web Linux VM Variables 21 | web_linuxvm_size = "Standard_DS1_v2" 22 | web_linuxvm_admin_user = "azureuser" -------------------------------------------------------------------------------- /terraform-manifests/ssh-keys/terraform-azure.pem: -------------------------------------------------------------------------------- 1 | -----BEGIN RSA PRIVATE KEY----- 2 | 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 51 | -----END RSA PRIVATE KEY----- 52 | -------------------------------------------------------------------------------- /terraform-manifests/ssh-keys/terraform-azure.pub: -------------------------------------------------------------------------------- 1 | ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAACAQCxA6mEMrD7t6WV9VkWDiNLLtfJo9Fjiq9BQ0QSST1lfz6khwr7ALrjddDSVELMqtDsey7otyz+GvsXYN5Pw2/aR50ym5ft7Plz7f2YmTEzhSBa5nAnin1HnGFQwiYsYF25qdUsNDvkLrkWs8Nn2n7wGT8hmrRK+NROWNb4Jl7fqdiHdmd2xbWQNMIZ3D6rjFF2rVpmTHaK7w6P1ZwWRdjH+6rcFOdS1O76zctpoVPcZ3731FxHnsBwUEucAbVdT9oKefwCsgsF8IUeKMAdHexkpB6OO/7DU4sy22yByrHBsv+e2KBAFSRNwom4Fa+kpy3iMlMklysJDtAF9Ob6EqDXuKEyFdis8rbND1byN4H/kKw9nDsLqIW3KjoUf/hBHafLbElKSsq8kRZKTHPhzVIHKfOJhX2lsOW2s2X/RnNrb1cDTqZQanqNIk/umnJZR8hG87CbxOyni04xFp89OqbRl7Pnm7+efqGVYA5wLk7EnwHnj9uI+Yxz2HyBW7Y645pNt8WuwiEabcyHe+ht40Sx8XVAayCoaA6RhZjMGP4xykBf3i7Is9VlrwgjcrYbrwJo5aF/4x7pP+6SgNKnAi39JGL1kzEHVu5FJiHxJqd8/fYNlKz+I9/e+b1IZgQchelsUPG8SYtU7/6wi70xw4fvaEkwFYRDaF1SowqDBggnFw== azureuser@myserver 2 | -------------------------------------------------------------------------------- /terraform-manifests/stage.tfvars: -------------------------------------------------------------------------------- 1 | # Environment Name 2 | environment = "stage" 3 | 4 | # Virtual Network Variables 5 | vnet_name = "vnet" 6 | vnet_address_space = ["10.3.0.0/16"] 7 | 8 | web_subnet_name = "websubnet" 9 | web_subnet_address = ["10.3.1.0/24"] 10 | 11 | app_subnet_name = "appsubnet" 12 | app_subnet_address = ["10.3.11.0/24"] 13 | 14 | db_subnet_name = "dbsubnet" 15 | db_subnet_address = ["10.3.21.0/24"] 16 | 17 | bastion_subnet_name = "bastionsubnet" 18 | bastion_subnet_address = ["10.3.100.0/24"] 19 | 20 | # Web Linux VM Variables 21 | web_linuxvm_size = "Standard_DS1_v2" 22 | web_linuxvm_admin_user = "azureuser" -------------------------------------------------------------------------------- /terraform-manifests/terraform.tfvars: -------------------------------------------------------------------------------- 1 | # Generic Variables 2 | business_divsion = "hr" 3 | resource_group_location = "eastus" 4 | resource_group_name = "rg" 5 | --------------------------------------------------------------------------------